#!/usr/bin/env bash
set -e

ARCH=ppc64
MODSUBDIR=ppc64
USER_PWD="$PWD"

if [ -z "$NRNHOME" ] ; then
  prefix=/usr
  exec_prefix=/usr/lib/nrn/
  bindir=${exec_prefix}/bin
  libdir=${exec_prefix}/lib
else
  prefix="$NRNHOME"
  exec_prefix="${prefix}/${ARCH}"
  bindir="${prefix}/bin"
  libdir="${prefix}/lib"
fi

if [ -z ${CORENRNHOME+x} ] ; then
  # CORENRNHOME wasn't set, use the install prefix
  cnrn_prefix=
else
  cnrn_prefix="${CORENRNHOME}"
fi

if [ "${NRNHOME_EXEC}" ] ; then
  exec_prefix="${NRNHOME_EXEC}"
  bindir="${exec_prefix}/bin"
  libdir="${exec_prefix}/lib"
fi

export prefix
export bindir
export libdir

if command -v xcrun; then
    #export SDKROOT=$(xcrun --sdk macosx --show-sdk-path)
    #export MACOSX_DEPLOYMENT_TARGET=""
    if [ -z "${MACOSX_DEPLOYMENT_TARGET}" ]; then
        unset MACOSX_DEPLOYMENT_TARGET
    fi
fi

LinkCoreNEURON=false
UserINCFLAGS=""
UserLDFLAGS=""
UserCOREFLAGS=()

# - options come first but can be in any order.
while [ "$1" ] ; do
    case "$1" in
    -coreneuron)
        # also run nrnivmodl-core
        LinkCoreNEURON=true
        shift;;
    -incflags)
        # extra include flags and paths (NEURON only)
        UserINCFLAGS="$2"
        # extra include flags and paths for CoreNEURON
        UserCOREFLAGS+=(-i "${2}")
        shift
        shift;;
    -loadflags)
        # extra link flags, paths, libraries (NEURON only)
        UserLDFLAGS="$2"
        # extra lin flags, paths. libraries (CoreNEURON)
        UserCOREFLAGS+=(-l "${2}")
        shift
        shift;;
    -*)
        echo "$1 unrecognized"
        exit 1;;
    *)
        break;;
    esac
done

echo "$PWD"

# Mod file paths may contain spaces which make variable lists of those
# hard to manage as space is the item separator. Furthermore, when a
# path is used, sometimes the spaces must be escaped (eg. a Makefile
# dependency pattern, and sometimes it is more useful for readability to
# enclose the path in "". To work around this issue, when creating a list
# of paths, translate the spaces for each item to +++ and after retrieval
# of an item, retranslate back to either a space or an escaped space.
# Only do this for cmake

shopt -s nullglob
# files is the complete list of mod files to process
files=()
if [ $# -gt 0 ] ; then
  for i in "$@" ; do
    if [ -d "$i" ] ; then
      files+=( "$i"/*.mod )
    elif [ -e "$i" ] || [ -e "$i.mod" ] ; then
      files+=( "$i" )
    else
      echo "Arg Error: \"$i\" is not a folder or mod file name or prefix"

      echo ""
      echo -n "  Mod file, folder args:"
      for j in "$@" ; do
        echo -n " \"$j\""
      done
      echo ""

      exit 1
    fi
  done
else
  files=( *.mod )
fi

base_names=()
for i in "${files[@]}" ; do
  base_names+=( "$(basename "$i" .mod)" )
done

echo -n "Mod files:"
for i in "${files[@]}" ; do
  dir_name=$(dirname "$i")
  echo -n " \"$dir_name/${i%.mod}.mod\""
done
echo ""
echo ""


if [ ! -d "$MODSUBDIR" ] ; then
  echo "Creating '$MODSUBDIR' directory for .o files."
  echo
  mkdir "$MODSUBDIR"
fi

files=( "${files[@]%.mod}" )

cd $MODSUBDIR
mdir="$PWD"

# construct file to be included by makefile to specify mod to c rule when
# executed in $MODSUBDIR (child folder of launch location folder)
MODMAKE=makemod2c_inc
> "$MODMAKE"
for i in "${files[@]}" ; do
  case "$i" in
    /*) f="$i";; # absolute, fine as is
    *)  f="../$i";; # relative
  esac
  base_name="$(basename "$f")"
  dir_name="$(dirname "$f")"
  # Note: indentation for shell lines in make rules must be a tab
  echo "\
./${base_name// /\\ }.c: ${f// /\\ }.mod
	@printf \" -> \$(C_GREEN)NMODL\$(C_RESET) \$<\\\n\"
	(cd \"$dir_name\";  MODLUNIT=\$(NRNUNITS) \$(NOCMODL) \"$base_name.mod\" -o \"$mdir\")

./${base_name// /\\ }.o: ./${base_name// /\\ }.c
	@printf \" -> \$(C_GREEN)Compiling\$(C_RESET) \$<\\\n\"
	\$(COMPILE) -I\"$dir_name\" \$(INCLUDES) -fPIC -c \$< -o \$@
" >> "$MODMAKE"
done

MODOBJS=

{
  echo '#include <stdio.h>
#include "hocdec.h"
extern int nrnmpi_myid;
extern int nrn_nobanner_;
#if defined(__cplusplus)
extern "C" {
#endif
'

  for i in "${base_names[@]}" ; do
    echo "extern void _${i// }_reg(void);"
  done

  echo ""
  echo "void modl_reg() {"
  echo "  if (!nrn_nobanner_) if (nrnmpi_myid < 1) {"
  printf '    fprintf(stderr, "Additional mechanisms from files\\n");\n'

  for i in "${files[@]}"
  do
    echo '    fprintf(stderr, " \"'"$i"'.mod\"");'
  done

  printf '    fprintf(stderr, "\\n");\n'

  echo "  }"

  for i in "${base_names[@]}" ; do
    echo "  _${i// }_reg();"
    MODOBJS="$MODOBJS ./${i// /\\ }.o"
  done

  echo "}"

  echo '
#if defined(__cplusplus)
}
#endif'
} > mod_func.cpp

# call nrnivmodl-core if CoreNEURON is enabled and requested via CLI
UsingCoreNEURON=false
#UsingCoreNEURON=true
if [ "$LinkCoreNEURON" = true ] ; then
  if [ "$UsingCoreNEURON" = true ] ; then
    if [ "$#" -gt 1 ] ; then
        printf "ERROR : when called with -coreneuron only 1 mod dir is accepted.\n"
        exit 1
    fi
    cd "$USER_PWD"
    "${cnrn_prefix}/bin/nrnivmodl-core" "${UserCOREFLAGS[@]}" "$@"
    cd "$MODSUBDIR"
  else
    printf "ERROR : CoreNEURON support is not enabled!\n"
    exit 1
  fi
fi

make -j 4 -f "${bindir}/nrnmech_makefile" "ROOT=${prefix}" "MODOBJFILES=$MODOBJS" "UserLDFLAGS=$UserLDFLAGS" "UserINCFLAGS=$UserINCFLAGS" "LinkCoreNEURON=$LinkCoreNEURON" special &&
echo "Successfully created $MODSUBDIR/special"
