#!/bin/bash
#
# Created by: Arni Magnusson [2009-05-27] revision 243
#
# Copyright (c) 2008-2013 ADMB Foundation
#
shopt -s expand_aliases
alias help='echo -e "
Builds AD Model Builder executable or library.

Usage: admb [-c] [-d] [-g] [-r] [-f] model [src(s)]

Options:
 -c     Build only object file(s) (.obj).
 -d     Build a shared library (.so).
 -g     Build with debug symbols.
 -r     Build with Random effects library (ADMB-RE).
 -f     Build with Fast optimized mode library (no bounds checking).
        By default, admb script builds with bounds checking.
 model  TPL file (ie 'simple.tpl' or the filename 'simple' with no .tpl
        extension)
 src(s) C/C++ Source file(s) containing classes, methods and variables that
        are used in model.
"'

if [[ "$1" == "" ]]; then help; exit; fi
if [[ "$1" == "-h" ]]; then help; exit; fi
if [[ "$1" == "-help" ]]; then help; exit; fi
if [[ "$1" == "--help" ]]; then help; exit; fi

ADMB_HOME=
if [ -z "$ADMB_HOME" ]; then
  FILE=$0
  DIRECTORY=$(cd `dirname "$FILE"` && pwd)
  while [ -h "${FILE}" ]; do
    pushd "$DIRECTORY" &> /dev/null
    FILE=$(readlink "$DIRECTORY"/admb)
    DIRECTORY=$(cd `dirname "$FILE"` && pwd)
    popd &> /dev/null
  done
  pushd "$DIRECTORY/.." &> /dev/null
  declare -rx ADMB_HOME=$PWD
  popd &> /dev/null
fi
if [ "$OS" == "Windows_NT" ]; then
  PATH=$ADMB_HOME/utilities/mingw/bin:$PATH
fi
PATH=$ADMB_HOME/bin:$PATH

# Pop args until model=$1
unset dll
unset debug
unset parser
unset library
unset compileonly
dll=
debug=
parser=
library=safe
compileonly=
output=
while getopts "dgrsfco:" A; do
  case $A in
    d)
       dll=-dll
       SHARED=-shared
       ;;
    g)
       debug=-debug
       ;;
    r)
       parser=tpl2rem
       ;;
    s)
       ;;
    f)
       library=opt
       ;;
    c)
       compileonly=yes
       ;;
    o)
       output="$OPTARG"
       ;;
    *)
       help
       exit 1
       ;;
  esac
done
shift $((OPTIND-1))

tpls=
srcs=
objs=
nontpls=

for file in $*
do
  extension="${file#*.}"
  if [ "$extension" = "$file" ]; then
    tpls="$tpls $file"
  elif [ "$extension" = "tpl" ]; then
    tpls="$tpls ${file%.*}"
  elif [ "$extension" = "cpp" -o "$extension" = "c" -o "$extension" = "cc" -o "$extension" = "cxx" ]; then
    srcs="$srcs $file"
    nontpls="$nontpls $file"
  elif [ "$extension" = "o" -o "$extension" = "obj" ]; then
    objs="$objs $file"
    nontpls="$nontpls $file"
  fi
done
if [ -z "$tpls" ]; then
  if [ -z "$srcs" ]; then
    if [ -z "$objs" ]; then
      if [ -z "$nontpls" ]; then
        echo -e "Error: Nothing to build."
        exit 1
      fi
    fi
  fi
fi
if [ -f "$ADMB_HOME/bin/admb-cfg.sh" ]; then
  source "$ADMB_HOME/bin/admb-cfg.sh"
  CXX=$ADMB_CFG_CXX
  CXXFLAGS="$CXXFLAGS $ADMB_CFG_CXXFLAGS"
  LDFLAGS="$LDFLAGS $ADMB_CFG_LDFLAGS"
else
  CXX=c++
  CXXFLAGS="$CXXFLAGS"
  LDFLAGS="$LDFLAGS"
fi
if [ ! -z "$dll" ]; then
  if [ "$OS" != "Windows_NT" ]; then
    CXXFLAGS="-fPIC $CXXFLAGS"
  fi
  LDFLAGS="-shared $LDFLAGS"
fi
if [ ! -z "$debug" ]; then
  CXXFLAGS="-g $CXXFLAGS"
  LDFLAGS="-g $LDFLAGS"
else
  if [ "$CXX" == "openCC" ]; then
    CXXFLAGS="-O2 $CXXFLAGS"
    LDFLAGS="-O2 $LDFLAGS"
  else
    CXXFLAGS="-O3 $CXXFLAGS"
    LDFLAGS="-O3 $LDFLAGS"
  fi
fi
if [ "$library" == "opt" ]; then
  CXXFLAGS="$CXXFLAGS -DOPT_LIB"
fi
if [ ! -f "$ADMB_HOME/lib/libadmb-contrib$SHARED.a" ]; then
  CXXFLAGS="$CXXFLAGS -I. -I\"$ADMB_HOME/include\" -I\"$ADMB_HOME/include/contrib\""
else
  CXXFLAGS="$CXXFLAGS -I. -I\"$ADMB_HOME/include\" -I\"$ADMB_HOME/contrib/include\""
fi
if [ "$CXX" == "adcomp-x86_64-w64-mingw32" ]; then
  LDFLAGS="--static $LDFLAGS"
fi
tplsrcs=
for model in $tpls
do
  if [ ! -f $model.tpl ]; then
    echo -e "\\nError: $model.tpl not found\\n"
    exit 1
  fi

  rm -f classdef.tmp xxdata.tmp xxhtop.tmp xxhtopm.tmp xxglobal.tmp xxtopm.tmp &> /dev/null
  rm -f xxalloc.tmp xxalloc1.tmp xxalloc2.tmp xxalloc3.tmp xxalloc4.tmp xxalloc5.tmp xxalloc6.tmp header.tmp &> /dev/null
  rm -f tfile1 tfile2 tfile3 tfile4 tfile5 &> /dev/null
  rm -f $model.cpp $model.htp $model.obj $model.o $model &> /dev/null
  rm -f admb.log &> /dev/null

  if [ "$parser" == "tpl2rem" ]; then
    CMD="$parser $debug $dll $model"
    echo -e \\n\*\*\* Parse: $model.tpl\\n$CMD
    eval $CMD
  else
    echo -e \\n\*\*\* Parse: $model.tpl
    CMD="tpl2cpp $debug $dll $model || tpl2rem $debug $dll $model"
    echo -e $CMD
    eval $CMD &> admb.log
  fi

  if [ ! -f $model.cpp -o ! -f $model.htp ]; then
    echo -e "\\nError: could not parse \"$model.tpl\".\\n"
    cat admb.log
    exit 1
  else
    rm -f admb.log &> /dev/null
  fi
  tplsrcs="$tplsrcs ${model%.*}.cpp"
done

tplobjs=
for file in $tplsrcs
do
  if [ ! -f $file ]; then
    echo -e "\\nError: $file not found\\n"
    exit 1
  fi

  fileobj=${file%.*}.obj
  rm -f $fileobj
  CMD="$CXX -c $CXXFLAGS -o$fileobj $file"
  echo -e \\n\*\*\* Compile: $file\\n$CMD
  eval $CMD

  if [[ ! -f $fileobj ]]; then
    echo -e "\\nError: Could not compile $file\\n"
    exit 1
  fi
  tplobjs="$tplobjs $fileobj"
done

for file in $srcs
do
  if [ ! -f $file ]; then
    echo -e "\\nError: $file not found\\n"
    exit 1
  fi
  fileobj=${file%.*}.obj
  rm -f $fileobj
  CMD="$CXX -c $CXXFLAGS -o$fileobj $file"
  echo -e \\n\*\*\* Compile: $file\\n$CMD
  eval $CMD
  if [[ ! -f $fileobj ]]; then
    echo -e "\\nError: Could not compile $file\\n"
    exit 1
  fi
  if [ ! -z "$objs" ]; then
    objs="$fileobj $objs"
  else
    objs="$fileobj"
  fi
done

if [ ! -z "$compileonly" ]; then
  objects=$tplobjs
  if [ ! -z "$objs" ]; then
    objects=$objs
  fi
  echo -e "\\nCompiled $objects.\\n"
  exit 0
fi

for file in $tplobjs
do
  if [ ! -z  "$output" ]; then
    model="$output"
  else
    model=${file%.*}
  fi
  if [ ! -z  "$dll" ]; then
    CMD="$CXX $LDFLAGS -o$model.so"
  else
    CMD="$CXX $LDFLAGS -o$model"
  fi
  CMD="$CMD $file $objs"
  if [ ! -f "$ADMB_HOME/lib/libadmb-contrib$SHARED.a" ]; then
    if [[ "$library" == "opt" ]]; then
      CMD="$CMD \"$ADMB_HOME/lib/libadmbo$SHARED.a\""
    else
      CMD="$CMD \"$ADMB_HOME/lib/libadmb$SHARED.a\""
    fi
  else
    if [[ "$library" == "opt" ]]; then
      CMD="$CMD \"$ADMB_HOME/lib/libadmb-contribo$SHARED.a\""
    else
      CMD="$CMD \"$ADMB_HOME/lib/libadmb-contrib$SHARED.a\""
    fi
  fi
  echo -e \\n\*\*\* Linking: $file $objs\\n$CMD
  eval $CMD
  if [[ -z $dll ]]; then
    if [[ ! -f $model ]]; then
        echo -e "\\nError: Could not build $model\\n"
        exit 1
    fi
  else
    if [[ ! -f $model.so ]]; then
        echo -e "\\nError: Could not build $model.so\\n"
        exit 1
    fi
  fi
done

if [[ "$tplobjs" == "" ]]; then
  outputfilebasename=
  if [ ! -z  "$output" ]; then
    outputfilebasename="$output"
  fi
  listobjs=
  for file in $nontpls
  do
    extension="${file#*.}"
    if [ "$extension" = "o" -o "$extension" = "obj" ]; then
      listobjs="$listobjs $file"
    else
      listobjs="$listobjs ${file%.*}.obj"
    fi
    if [ -z  "$outputfilebasename" ]; then
      outputfilebasename="`basename $file`"
      outputfilebasename=${file%.*}
    fi
  done
  if [ ! -z  "$dll" ]; then
    CMD="$CXX $LDFLAGS -o$outputfilebasename.so"
  else
    CMD="$CXX $LDFLAGS -o$outputfilebasename"
  fi
  CMD="$CMD $listobjs"
  if [ ! -f "$ADMB_HOME/lib/libadmb-contrib$SHARED.a" ]; then
    if [[ "$library" == "opt" ]]; then
      CMD="$CMD \"$ADMB_HOME/lib/libadmbo$SHARED.a\""
    else
      CMD="$CMD \"$ADMB_HOME/lib/libadmb$SHARED.a\""
    fi
  else
    if [[ "$library" == "opt" ]]; then
      CMD="$CMD \"$ADMB_HOME/lib/libadmb-contribo$SHARED.a\""
    else
      CMD="$CMD \"$ADMB_HOME/lib/libadmb-contrib$SHARED.a\""
    fi
  fi
  echo -e \\n\*\*\* Linking: $listobjs\\n$CMD
  eval $CMD

  if [ ! -z  "$output" ]; then
    if [[ -z $dll ]]; then
      if [[ ! -f $output ]]; then
        echo -e "\\nError: Could not build $output\\n"
        exit 1
      fi
    else
      if [[ ! -f $output.so ]]; then
        echo -e "\\nError: Could not build $output.so\\n"
        exit 1
      fi
    fi
  else
    declare -a amodel=( $listobjs )
    m=${amodel[0]}
    m2=${m%.*}
    if [[ -z $dll ]]; then
      if [[ ! -f $m2 ]]; then
        echo -e "\\nError: Could not build $m2\\n"
        exit 1
      fi
    else
      if [[ ! -f $m2.so ]]; then
        echo -e "\\nError: Could not build $m2.so\\n"
        exit 1
      fi
    fi
  fi
fi

echo -e "\\nSuccessfully built executable.\\n"
exit 0
