#!/usr/bin/env bash

function write_config_var() {
  local _dst=${1}; shift

  local _VAR_CT_VAR="$@"
  local _VAR=$(echo "${_VAR_CT_VAR}" | sed "s,^\([^\,]*\)\,.*,\1,")
  local _CT_VAR=$(echo "${_VAR_CT_VAR}" | sed "s,^[^\,]*\,\(.*\),\1,")
  local _VAL=${!_VAR}

  # echo "_VAR=${_VAR}, _CT_VAR=${_CT_VAR}, _VAL=${_VAL}"
  if [[ ${_CT_VAR} == *_NEEDED ]]; then
    if [[ -n "${_VAL}" ]]; then
      echo "${_CT_VAR}=y"                                           >> "${_dst}"
      # Drop into the VERSION logic below.
      _CT_VAR=${_CT_VAR//_NEEDED}_VERSION
      # echo _CT_VAR is ${_CT_VAR}
    fi
  fi
  # Special case for things that need _STUB_FAMILYU_V_X_Y_Z=y
  local _VERSION2=0
  # Even more special case for things that *also* need _STUB_FAMILYU_VERSION=y
  local _VERSION3=0

  if [[ ${_CT_VAR} == *_VERSION2 ]]; then
    _CT_VAR=${_CT_VAR//2/}
    # echo $_CT_VAR .. was 2?
    _VERSION2=1
  elif [[ ${_CT_VAR} == *_VERSION3 ]]; then
    _CT_VAR=${_CT_VAR//3/}
    # echo $_CT_VAR .. was 2?
    _VERSION2=1
    _VERSION3=1
  fi
  if [[ ${_CT_VAR} == *_VERSION ]]; then
    _STUB=${_CT_VAR//_VERSION/}
    if [[ -n "${_VAL}" ]]; then
      local _FAMILY=$(echo "${_VAL}" | sed "s,^\([^\,]*\)\,.*,\1,")
      local _FVAL=$(echo "${_VAL}" | sed "s,^[^\,]*\,\(.*\),\1,")
      echo _FAMILY $_FAMILY
      echo _FVAL $_FVAL
      if [[ ${_FAMILY} != ${_FVAL} ]]; then
        _FAMILYU=$(echo ${_FAMILY} | tr 'a-z' 'A-Z')
        echo "${_STUB}=\"${_FAMILY}\""                                >> "${_dst}"
        echo "${_STUB}_${_FAMILY}=y"                                  >> "${_dst}"
        if [[ ${_VERSION3} == 1 ]]; then
          echo "${_STUB}_${_FAMILYU}_VERSION=\"${_FVAL}\""            >> "${_dst}"
        else
          echo "${_STUB}_VERSION=\"${_FVAL}\""                        >> "${_dst}"
        fi
        if [[ ${_VERSION2} == 1 ]]; then
          echo "${_STUB}_${_FAMILYU}_V_$(echo $_FVAL | tr '.' '_')=y" >> "${_dst}"
        else
          echo "${_STUB}_V_$(echo $_FVAL | tr '.' '_')=y"             >> "${_dst}"
        fi
      else
        echo "_FAMILY=${_FAMILY}, _FVAL=${_FVAL}"
        echo "${_STUB}=y"                                             >> "${_dst}"
        echo "${_STUB}_V_$(echo $_VAL | tr '.' '_')=y"                >> "${_dst}"
      fi
    else
      echo "${_STUB}=n"                                               >> "${_dst}"
    fi
  elif [[ -n "${_VAL}" ]]; then
    echo "${_CT_VAR}=\"${_VAL}\""                                     >> "${_dst}"
    echo "${_CT_VAR}_${_VAL}=y"                                       >> "${_dst}"
  fi
}

function write_ctng_package_versions() {
  local _dst="${1}"

  declare -a _extras
  if [[ -n "${ctng_gdb}" ]]; then
    _extras+=("gdb_version,CT_GDB_VERSION")
  fi
  if [[ -n "${ctng_duma}" ]]; then
    _extras+=("duma_version,CT_DUMA_VERSION")
  fi
  # Compounds for bits that have different families
  local ctng_linux_version=linux,${ctng_kernel}
  local _libc=${ctng_libc#ctng_}
  if [[ ${_libc} == gnu ]]; then
    _libc=glibc
  fi
  local ctng_libc_version=${_libc},${!ctng_libc}
  local ctng_compiler_version=gcc,${ctng_gcc}
  local ctng_binutils_version=binutils,${ctng_binutils}
  local ctng_gdb_version=gdb,${ctng_gdb}
  # TODO :: Fix this in crosstool-ng, 200-duma.sh requires
  #         version numbers to be supplied with _'s insead
  #         of .'s for no good reason.
  local duma_version=duma,${ctng_duma//./_}
  local _VAR_CT_VAR
  for _VAR_CT_VAR in                           \
    ctng_vendor,CT_TARGET_VENDOR               \
    ctng_linux_version,CT_KERNEL_VERSION       \
    ctng_libc_version,CT_LIBC_VERSION2         \
    ctng_compiler_version,CT_CC_VERSION3       \
    ctng_binutils_version,CT_BINUTILS_VERSION  \
    ctng_libiconv,CT_LIBICONV_NEEDED           \
    ctng_gettext,CT_GETTEXT_NEEDED             \
    ctng_gmp,CT_GMP_NEEDED                     \
    ctng_mpfr,CT_MPFR_NEEDED                   \
    ctng_isl,CT_ISL_NEEDED                     \
    ctng_mpc,CT_MPC_NEEDED                     \
    ctng_ncurses,CT_NCURSES_NEEDED             \
    "${_extras[@]}"; do
      write_config_var "${_dst}" "${_VAR_CT_VAR}"
  done
  # Add this back here because build.sh filters out LIBC_GLIBC to prevent conflicts.
  if [[ ${_libc} == glibc ]]; then
    echo "CT_LIBC_GLIBC_FORCE_UNWIND=y"      >> "${_dst}"
    echo "CT_LIBC_SUPPORT_THREADS_ANY=y"     >> "${_dst}"
    echo "CT_LIBC_SUPPORT_THREADS_NATIVE=y"  >> "${_dst}"
    # More hacks. Time to find a better way than this?
    local _libc_minor=$(echo ${ctng_libc_version} | awk -F \. {'print $2'})
    if [[ ${_libc_minor} -ge 17 ]]; then
      echo "CT_LIBC_GLIBC_2_17_or_later=y" >> "${_dst}"
      if [[ ${_libc_minor} -ge 20 ]]; then
        echo "CT_LIBC_GLIBC_2_20_or_later=y" >> "${_dst}"
        if [[ ${_libc_minor} -ge 23 ]]; then
          echo "CT_LIBC_GLIBC_2_23_or_later=y" >> "${_dst}"
        fi
      fi
    fi
  fi
}

function write_ctng_config_before() {
  local _dst="${1}"

  echo "CT_OBSOLETE=y"                                                  >> "${_dst}"
  echo "CT_EXPERIMENTAL=y"                                              >> "${_dst}"
  # echo "CT_DEBUGGABLE_TOOLCHAIN=y"                                      >> "${_dst}"
  # echo "CT_STRIP_HOST_TOOLCHAIN_EXECUTABLES=n"                          >> "${_dst}"
  # echo "CT_STRIP_TARGET_TOOLCHAIN_EXECUTABLES=n"                        >> "${_dst}"
  echo "CT_LOCAL_TARBALLS_DIR=\"${SYS_PREFIX}/conda-bld/src_cache\""    >> "${_dst}"
  echo "CT_SAVE_TARBALLS=y"                                             >> "${_dst}"
  echo "CT_PREFIX_DIR=\"\${CT_TOP_DIR}/gcc_built\""                     >> "${_dst}"
  echo "CT_FORCE_SYSROOT=y"                                             >> "${_dst}"
  echo "CT_ARCH_CPU=\"${cpu_model}\""                                   >> "${_dst}"
  echo "CT_ALLOW_BUILD_AS_ROOT=y"                                       >> "${_dst}"
  echo "CT_ALLOW_BUILD_AS_ROOT_SURE=y"                                  >> "${_dst}"
  if [[ ${ctng_nature} == static ]]; then
    echo "CT_STATIC_TOOLCHAIN=y"                                        >> "${_dst}"
  else
    echo "CT_STATIC_TOOLCHAIN=n"                                        >> "${_dst}"
  fi
  echo "CT_CC_LANG_CXX=y"                                               >> "${_dst}"
  echo "CT_CC_LANG_FORTRAN=y"                                           >> "${_dst}"
  echo "CT_CC_LANG_OBJC=y"                                              >> "${_dst}"
  echo "CT_CC_LANG_OBJCXX=y"                                            >> "${_dst}"
  if [[ -n ${ctng_duma} ]]; then
    echo "CT_DEBUG_duma=y"                                              >> "${_dst}"
    echo "CT_DUMA_SO=y"                                                 >> "${_dst}"
    echo "CT_DUMA_CUSTOM_WRAPPER=y"                                     >> "${_dst}"
  fi
  if [[ -n ${ctng_gdb} ]]; then
    echo "CT_DEBUG_gdb=y"                                               >> "${_dst}"
    if [[ ${ctng_nature} == static ]]; then
      echo "CT_GDB_NATIVE_STATIC=y"                                     >> "${_dst}"
    else
      echo "CT_GDB_NATIVE=y"                                            >> "${_dst}"
      echo "# CT_GDB_NATIVE_STATIC is not set"                          >> "${_dst}"
    fi
    # GDBSERVER has issues with fully static:
    # x86_64-sarc-linux-gnu-gcc -static -shared -fPIC -Wl,--soname=libinproctrace.so -Wl,--no-undefined -g -O2    -I. -I/home/ray/gcc-native/work/.build/src/gdb-7.12.1/gdb/gdbserver -I/home/ray/gcc-native/work/.build/src/gdb-7.12.1/gdb/gdbserver/../common -I/home/ray/gcc-native/work/.build/src/gdb-7.12.1/gdb/gdbserver/../regformats -I/home/ray/gcc-native/work/.build/src/gdb-7.12.1/gdb/gdbserver/.. -I/home/ray/gcc-native/work/.build/src/gdb-7.12.1/gdb/gdbserver/../../include -I/home/ray/gcc-native/work/.build/src/gdb-7.12.1/gdb/gdbserver/../gnulib/import -Ibuild-gnulib-gdbserver/import  -Wall -Wpointer-arith -Wno-unused -Wunused-value -Wunused-function -Wno-switch -Wno-char-subscripts -Wempty-body -Wunused-but-set-parameter -Wunused-but-set-variable -Wpointer-sign -Wmissing-prototypes -Wdeclaration-after-statement -Wmissing-parameter-type -Wold-style-declaration -Wold-style-definition -Wformat-nonliteral -Wno-missing-prototypes  -DGDBSERVER -static-libstdc++ -static-libgcc  -Wl,--dynamic-list=/home/ray/gcc-native/work/.build/src/gdb-7.12.1/gdb/gdbserver/proc-service.list -o libinproctrace.so ax-ipa.o tracepoint-ipa.o format-ipa.o utils-ipa.o regcache-ipa.o remote-utils-ipa.o common-utils-ipa.o tdesc-ipa.o print-utils-ipa.o rsp-low-ipa.o errors-ipa.o amd64-linux-ipa.o amd64-avx-linux-ipa.o amd64-avx-mpx-linux-ipa.o amd64-avx512-linux-ipa.o amd64-mpx-linux-ipa.o linux-amd64-ipa.o -ldl -pthread
    # /home/ray/gcc-native/work/gcc_built/lib/gcc/x86_64-sarc-linux-gnu/6.3.0/../../../../x86_64-sarc-linux-gnu/bin/ld: /home/ray/gcc-native/work/gcc_built/lib/gcc/x86_64-sarc-linux-gnu/6.3.0/crtbeginT.o: relocation R_X86_64_32 against hidden symbol `__TMC_END__' can not be used when making a shared object
    # /home/ray/gcc-native/work/gcc_built/lib/gcc/x86_64-sarc-linux-gnu/6.3.0/../../../../x86_64-sarc-linux-gnu/bin/ld: final link failed: Nonrepresentable section on output
    if [[ ${ctng_nature} == static ]]; then
      echo "CT_GDB_GDBSERVER=n"                                         >> "${_dst}"
    else
      echo "CT_GDB_GDBSERVER=y"                                         >> "${_dst}"
      echo "CT_GDB_GDBSERVER_HAS_IPA_LIB=y"                             >> "${_dst}"
      echo "CT_GDB_GDBSERVER_STATIC=n"                                  >> "${_dst}"
    fi
  fi
  echo "CT_DISABLE_MULTILIB_LIB_OSDIRNAMES=y"                           >> "${_dst}"
  echo "CT_CC_GCC_LIBGOMP=y"                                            >> "${_dst}"
  echo "CT_CC_GCC_LIBQUADMATH=y"                                        >> "${_dst}"
  echo "CT_CC_GCC_USE_LTO=y"                                            >> "${_dst}"
  echo "CT_CC_GCC_LIBSANITIZER=y"                                       >> "${_dst}"
  echo "CT_CC_GCC_ENABLE_PLUGINS=n"                                     >> "${_dst}"
  # What about:
  # 1. --with-linker-hash-style=gnu (faster dynamic loading)? Should be possible
  #    on CentOS5.11, may be the default.
  # 2. --enable-gnu-unique-object (less memory for template class statics)? From:
  #    https://gcc.gnu.org/install/configure.html
  #    Enabled by default for a toolchain with an assembler that accepts it and
  #    GLIBC 2.11 or above, otherwise disabled.
  echo "CT_CC_GCC_EXTRA_CONFIG_ARRAY=\"--enable-default-pie\""          >> "${_dst}"
  echo "CT_BINUTILS_PLUGINS=y"                                          >> "${_dst}"

  # TODO :: This is freescale imx351 and an exact hardware device. It would be better
  #         to handle this via a custom .config file.
  if [[ ${ctng_libc} == uClibc ]] && [[ ${ctng_cpu_model} == arm1136jf-s ]]; then
    echo "CT_ARCH=\"arm\""                                              >> "${_dst}"
    echo "CT_ARCH_arm=y"                                                >> "${_dst}"
    echo "CT_ARCH_FPU=\"vfp\""                                          >> "${_dst}"
    echo "CT_ARCH_SUPPORTS_BOTH_MMU=y"                                  >> "${_dst}"
    echo "CT_ARCH_USE_MMU=y"                                            >> "${_dst}"
    echo "CT_ARCH_ARM_MODE=\"arm\""                                     >> "${_dst}"
    echo "CT_ARCH_ARM_MODE_ARM=y"                                       >> "${_dst}"
    echo "CT_ARCH_ARM_EABI=y"                                           >> "${_dst}"
    echo "CT_ARCH_FLOAT_SW=y"                                           >> "${_dst}"
    echo "CT_ARCH_FLOAT=\"soft\""                                       >> "${_dst}"
    echo "CT_ARCH_ARM_EABI_FORCE=y"                                     >> "${_dst}"
    echo "CT_LIBC_UCLIBC_IPV6=y"                                        >> "${_dst}"
    echo "CT_LIBC_UCLIBC_WCHAR=y"                                       >> "${_dst}"
    echo "CT_LIBC_UCLIBC_VERBOSITY_2=y"                                 >> "${_dst}"
    echo "CT_LIBC_UCLIBC_VERBOSITY=\"V=2\""                             >> "${_dst}"
    echo "CT_LIBC_UCLIBC_CONFIG_FILE=\"${SRC_DIR}/uclibc.config\""      >> "${_dst}"
  fi

  if [[ ${ctng_libc} == uClibc ]] || [[ -z "${ctng_gdb}" ]]; then
    # [ALL  ]    ada-exp.o: In function `ada_parse':
    # [ALL  ]    /home/ray/imx351uc/work/.build/arm-caterpillar-linux-uclibcgnueabi/build/build-gdb-native/gdb/ada-exp.y:745: undefined reference to `_obstack_free'
    # [ALL  ]    gdbarch.o: In function `gdbarch_free':
    # [ALL  ]    /home/ray/imx351uc/work/.build/src/gdb-7.12.1/gdb/gdbarch.c:484: undefined reference to `_obstack_free'
    # [ALL  ]    gdbtypes.o: In function `recursive_dump_type':
    # [ALL  ]    /home/ray/imx351uc/work/.build/src/gdb-7.12.1/gdb/gdbtypes.c:4381: undefined reference to `_obstack_free'
    # [ALL  ]    dwarf2read.o: In function `abbrev_table_free':
    # [ALL  ]    /home/ray/imx351uc/work/.build/src/gdb-7.12.1/gdb/dwarf2read.c:15480: undefined reference to `_obstack_free'
    # [ALL  ]    /home/ray/imx351uc/work/.build/src/gdb-7.12.1/gdb/dwarf2read.c:15480: undefined reference to `_obstack_free'
    # [ALL  ]    dwarf2read.o:/home/ray/imx351uc/work/.build/src/gdb-7.12.1/gdb/dwarf2read.c:22183: more undefined references to `_obstack_free' follow
    _native_gdb=n
  else
    _native_gdb=y
  fi

  if [[ -n "${ctng_gdb}" ]]; then
    echo "CT_DEBUG_gdb=y"                                               >> "${_dst}"
    echo "CT_GDB_CROSS=y"                                               >> "${_dst}"
    if [[ ${ctng_nature} == static ]]; then
      echo "CT_GDB_CROSS_STATIC=y"                                      >> "${_dst}"
      echo "CT_GDB_NATIVE_STATIC=y"                                     >> "${_dst}"
      # GDBSERVER has issues with fully static:
      # x86_64-sarc-linux-gnu-gcc -static -shared -fPIC -Wl,--soname=libinproctrace.so -Wl,--no-undefined -g -O2    -I. -I/home/ray/gcc-native/work/.build/src/gdb-7.12.1/gdb/gdbserver -I/home/ray/gcc-native/work/.build/src/gdb-7.12.1/gdb/gdbserver/../common -I/home/ray/gcc-native/work/.build/src/gdb-7.12.1/gdb/gdbserver/../regformats -I/home/ray/gcc-native/work/.build/src/gdb-7.12.1/gdb/gdbserver/.. -I/home/ray/gcc-native/work/.build/src/gdb-7.12.1/gdb/gdbserver/../../include -I/home/ray/gcc-native/work/.build/src/gdb-7.12.1/gdb/gdbserver/../gnulib/import -Ibuild-gnulib-gdbserver/import  -Wall -Wpointer-arith -Wno-unused -Wunused-value -Wunused-function -Wno-switch -Wno-char-subscripts -Wempty-body -Wunused-but-set-parameter -Wunused-but-set-variable -Wpointer-sign -Wmissing-prototypes -Wdeclaration-after-statement -Wmissing-parameter-type -Wold-style-declaration -Wold-style-definition -Wformat-nonliteral -Wno-missing-prototypes  -DGDBSERVER -static-libstdc++ -static-libgcc  -Wl,--dynamic-list=/home/ray/gcc-native/work/.build/src/gdb-7.12.1/gdb/gdbserver/proc-service.list -o libinproctrace.so ax-ipa.o tracepoint-ipa.o format-ipa.o utils-ipa.o regcache-ipa.o remote-utils-ipa.o common-utils-ipa.o tdesc-ipa.o print-utils-ipa.o rsp-low-ipa.o errors-ipa.o amd64-linux-ipa.o amd64-avx-linux-ipa.o amd64-avx-mpx-linux-ipa.o amd64-avx512-linux-ipa.o amd64-mpx-linux-ipa.o linux-amd64-ipa.o -ldl -pthread
      # /home/ray/gcc-native/work/gcc_built/lib/gcc/x86_64-sarc-linux-gnu/6.3.0/../../../../x86_64-sarc-linux-gnu/bin/ld: /home/ray/gcc-native/work/gcc_built/lib/gcc/x86_64-sarc-linux-gnu/6.3.0/crtbeginT.o: relocation R_X86_64_32 against hidden symbol `__TMC_END__' can not be used when making a shared object
      # /home/ray/gcc-native/work/gcc_built/lib/gcc/x86_64-sarc-linux-gnu/6.3.0/../../../../x86_64-sarc-linux-gnu/bin/ld: final link failed: Nonrepresentable section on output
      echo "CT_GDB_GDBSERVER=n"                                         >> "${_dst}"
      echo "CT_BINUTILS_HAS_GOLD=n"                                     >> "${_dst}"
      echo "CT_BINUTILS_LINKERS_LIST=\"ld\""                            >> "${_dst}"
    else
      echo "CT_GDB_CROSS_STATIC=n"                                      >> "${_dst}"
      echo "CT_GDB_NATIVE_STATIC=n"                                     >> "${_dst}"
      echo "CT_GDB_GDBSERVER=y"                                         >> "${_dst}"
      echo "CT_GDB_GDBSERVER_HAS_IPA_LIB=y"                             >> "${_dst}"
      echo "CT_GDB_GDBSERVER_STATIC=n"                                  >> "${_dst}"
      echo "CT_BINUTILS_HAS_GOLD=y"                                     >> "${_dst}"
      echo "CT_BINUTILS_GOLD_SUPPORT=y"                                 >> "${_dst}"
      # Support for building glibc with gold is not yet complete, never mind really old
      # versions of glibc. In general it sounds like gold is not ready for prime-time.
      # https://github.com/bminor/glibc/commit/f300dc7358e785dd92259514f57acd10f695d142
      # https://github.com/bminor/glibc/commit/19f1a11e7ea2a5082bae9d9a079338c5658ba954
      echo "CT_BINUTILS_LINKER_LD_GOLD=y"                               >> "${_dst}"
      echo "CT_BINUTILS_LINKERS_LIST=\"ld,gold\""                       >> "${_dst}"
    fi
    echo "CT_GDB_NATIVE=${_native_gdb}"                                 >> "${_dst}"
    echo "CT_GDB_CROSS_PYTHON=n"                                        >> "${_dst}"
    echo "CT_GDB_HAS_PYTHON=n"                                          >> "${_dst}"
  fi

  if [[ -n "${ctng_duma}" ]]; then
    echo "CT_DEBUG_duma=y"                                              >> "${_dst}"
    echo "CT_DUMA_SO=y"                                                 >> "${_dst}"
    echo "CT_DUMA_CUSTOM_WRAPPER=y"                                     >> "${_dst}"
  fi
  write_ctng_package_versions "${_dst}"
}

# This function is called after calling ct-ng oldconfig
# to undo the fixes it performs. Mostly, it will replace
# versions it doesn't know about with ones it does, but
# we really want the versions we want.
function write_ctng_config_after() {
  local _dst="${1}"
  write_ctng_package_versions "${_dst}"
  # These 3 are necessary on linux-32 for some reason.
  echo "CT_CONFIGURE_has_static_link=n"                                 >> "${_dst}"
  echo "CT_WANTS_STATIC_LINK=n"                                         >> "${_dst}"
  echo "CT_WANTS_STATIC_LINK_CXX=n"                                     >> "${_dst}"
}
