#!/bin/bash
#
# NEMS Application Builder 
# A front-end script that guides the source code access and installation of
# available NEMS applications.
################################################################################
# add paths to find personal "dialog" installations on Theia, Yellowstone.
PATH=$PATH:/scratch4/NCEPDEV/nems/save/Gerhard.Theurich/bin:/glade/p/work/theurich/bin

# determine whether dialog or whiptail is available
read dialog <<< "$(which dialog 2> /dev/null)"
read whiptail <<< "$(which whiptail 2> /dev/null)"

# use whichever tool was found
if [ "$dialog"x != "x" ] ; then
  tool=$dialog
  toolflag="dialog"
  if [[ "$tool" =~ "scratch4/NCEPDEV/nems/save/Gerhard.Theurich/bin" ]]; then
    # Special Theia case here of avoiding branches below that spawn multiple 
    # processes. Those branches seem to cause (intermittent) trouble on Theia
    # for some reason!
    toolflag="NOTdialog"
  fi
elif [ "$whiptail"x != "x" ] ; then
  tool=$whiptail
  toolflag="whiptail"
else
  echo "ABORT: Neither dialog nor whiptail found." \
  "Must first install one of those tools!" >&2
  exit 1
fi

echo $tool
echo $toolflag

# delete temporary files
deletetempfiles(){
  rm -f $ROOTDIR/*.$$
}

bailout(){
  $tool --clear --backtitle "NEMS Application Builder" \
  --title "Bail out" --msgbox "Confirm bail out with <Enter>, back with <Esc>."\
  8 30
  if [ "$?" == "0" ] ; then
    exit
  fi
  bailFlag=true
}

# External component build functions ###########################################

build_checkloop(){
  # in: COMP, ${COMP}_DIR, ${COMP}_SRCDIR, ${COMP}_BINDIR, BUILD_FUNC
  eval COMP_DIR=\${${COMP}_DIR}
  eval COMP_SRCDIR=\${${COMP}_SRCDIR}
  eval COMP_BINDIR=\${${COMP}_BINDIR}
  if [[ -d $COMP_BINDIR ]] ; then
    # component installation directory exists
    reuse=true
  else
    # component installation directory does not exist
    reuse=false
    if [[ -f $COMP.install.md5sum.$MACHINE_ID ]] ; then
      # checksum of a previous build exists
      $tool --backtitle "NEMS Application Builder" \
        --title "Info: $COMP" --infobox "Check against previous checksum..." 6 25
      md5sum $COMP_DIR/* > $COMP.install.md5sum.$MACHINE_ID.tmp
      # read checksum file line by line and compare between two files.
      while read line
      do
        procline=`echo $line | grep -v "\.mk"`  # exclude .mk from comparing
        if [ "x$procline" != "x" ]; then
          # valid line
          checksum=`echo $procline | awk ' { print $1 } '`
          check=`grep $checksum $COMP.install.md5sum.$MACHINE_ID.tmp`
          if [ "x$check" == "x" ]; then
            # did not find the checksum -> failed check
            reuse=false_failchecksum
          fi
        fi
      done < $COMP.install.md5sum.$MACHINE_ID
    #  rm -f $COMP.install.md5sum.$MACHINE_ID.tmp
      if [[ "$reuse" == "false" ]] ; then
        $tool --backtitle "NEMS Application Builder" \
        --title "Info: $COMP" --infobox "Check against previous checksum...MATCH!" 6 35
        sleep 2
        # checksum comparison okay -> copy the existing component files over
        mkdir -p $COMP_BINDIR
        rm -rf $COMP_BINDIR/*
        cp $COMP_DIR/* $COMP_BINDIR
      else
        $tool --backtitle "NEMS Application Builder" \
        --title "Info: $COMP" --infobox "Check against previous checksum...NO MATCH!" 6 35
        sleep 2
      fi
    else
      # no existing checksum exists
      reuse=invalid
    fi
  fi
  
  # conditionally clean-up a pre-existing component installation
  if [[ "$reuse" == "true" ]] ; then  
    $tool --clear --backtitle "NEMS Application Builder" \
      --title "Alert" --yesno \
      "Looks like the $COMP component has been installed.\
      \n\nUse previous installation <Yes>, or re-install <No>." 10 40
    if [[ "$?" != "0" ]] ; then
      rm -rf $COMP_BINDIR
      $tool --clear --backtitle "NEMS Application Builder" \
        --title "Alert" --yesno \
        "Clean the $COMP component and build from scratch?" 8 40
      if [[ "$?" == "0" ]] ; then
      
        if [[ "$toolflag" == "dialog" ]] ; then
          # "dialog" implementation

          $tool --backtitle "NEMS Application Builder" \
               --title "${COMP} Clean Progress" \
                --tailboxbg $ROOTDIR/appBuilder.${COMP}.log.$$ 20 120 \
                --and-widget --ok-label "CANCEL" \
                --begin 2 1 --msgbox "Press CANCEL to interrupt." 5 30 \
                2> /dev/null &
          mypid=$!
          $BUILD_FUNC clean > $ROOTDIR/appBuilder.${COMP}.log.$$ 2>&1 &
          makepid=$!
  
          # now wait for either for $mypid to finish because of canceling, or
          # $makepid to finish due to done or bail out of make command.
  
          while ps -p $makepid > /dev/null
          do
            if ! ps -p $mypid > /dev/null
            then
              kill $makepid > /dev/null 2>&1
            fi
          done
          kill $mypid > /dev/null 2>&1
        else
          # "whiptail" implementation (less fancy)
          $BUILD_FUNC clean 2>&1 | tee $ROOTDIR/appBuilder.${COMP}.log.$$
        fi
        
      fi
    fi
  fi
  
  # enter re-build cycle
  while [[ ! -d $COMP_BINDIR ]] ; do
  
    if [[ "$toolflag" == "dialog" ]] ; then
      # "dialog" implementation

      $tool --backtitle "NEMS Application Builder" \
            --title "${COMP} Build Progress" \
            --tailboxbg $ROOTDIR/appBuilder.${COMP}.log.$$ 20 120 \
            --and-widget --ok-label "CANCEL" \
            --begin 2 1 --msgbox "Press CANCEL to interrupt." 5 30 \
            2> /dev/null &
      mypid=$!
      $BUILD_FUNC > $ROOTDIR/appBuilder.${COMP}.log.$$ 2>&1 &
      makepid=$!
  
      echo $BUILD_FUNC $mypid $makepid >> appBuilder.log.$$

      # now wait for either for $mypid to finish because of canceling, or
      # $makepid to finish due to done or bail out of make command.
  
      while ps -p $makepid > /dev/null
      do
        if ! ps -p $mypid > /dev/null
        then
          kill $makepid > /dev/null 2>&1
        fi
      done
      kill $mypid > /dev/null 2>&1
  
      if ([ ! -d $COMP_BINDIR ]); then
        # build did not succeed
        $tool --clear --backtitle "NEMS Application Builder" \
          --title "Trouble view log" \
          --textbox $ROOTDIR/appBuilder.${COMP}.log.$$ 20 120
        $tool --clear --backtitle "NEMS Application Builder" \
          --title "Diagnosis" --yesno \
          "Looks like the attempt to build the $COMP component failed.\
          \n\nTry again <Yes>, or skip <No>." 10 40
        if [[ "$?" != "0" ]] ; then
          cp $ROOTDIR/appBuilder.NEMS.log.$$ $ROOTDIR/appBuilder.NEMS.log
          cp $ROOTDIR/appBuilder.${COMP}.log.$$ $ROOTDIR/appBuilder.${COMP}.log
          break
        fi
      fi
    else
      # "whiptail" implementation (less fancy)
    
      $BUILD_FUNC 2>&1 | tee $ROOTDIR/appBuilder.${COMP}.log.$$
    
      if ([ ! -d $COMP_BINDIR ]); then
        # build did not succeed
        $tool --clear --backtitle "NEMS Application Builder" \
          --title "Trouble view log" \
          --textbox $ROOTDIR/appBuilder.${COMP}.log.$$ 20 120 --scrolltext
        $tool --clear --backtitle "NEMS Application Builder" \
          --title "Diagnosis" --yesno \
          "Looks like the attempt to build the $COMP component failed.\
          \n\nTry again <Yes>, or skip <No>." 10 40
        if [[ "$?" != "0" ]] ; then
          cp $ROOTDIR/appBuilder.NEMS.log.$$ $ROOTDIR/appBuilder.NEMS.log
          cp $ROOTDIR/appBuilder.${COMP}.log.$$ $ROOTDIR/appBuilder.${COMP}.log
          break
        fi
      fi
    fi
  done
    
  if ([ -d $COMP_BINDIR ]); then
    # create a new checksum file
    md5sum $COMP_BINDIR/* > $COMP.install.md5sum.$MACHINE_ID
  fi
}

build_std(){
  # in: COMP, COMP_SRCDIR, COMP_BINDIR
  if [[ $1"" == "clean" ]] ; then
    echo "Cleaning $COMP..."
    cd $COMP_SRCDIR
    make clean
    echo "...done cleaning $COMP."
  else
    echo "Building $COMP..."
    cd $COMP_SRCDIR
    make
    make DESTDIR=/ INSTDIR=$COMP_BINDIR install
    if ([ ! -d $COMP_BINDIR ]); then
      echo "...failed building $COMP."
    else
      echo "...done building $COMP."
    fi
  fi
}

build_cice(){
  #TODO: This component has a totally non-standard way of building!!!!
  #TODO: CICE and CICE_CAP should be merged into a single source tree, 
  #TODO: and building the CICE component in NUOPC mode should be done 
  #TODO: with standard target "nuopc". See HYCOM for an example.
  #
  # in: COMP, COMP_SRCDIR, COMP_BINDIR
  if [[ $1"" == "clean" ]] ; then
    echo "Cleaning $COMP..."
    echo "Only partially implemented!!!"
    cd CICE_CAP
    make -f makefile.nuopc clean
    echo "...done cleaning $COMP."
  else
    echo "Building $COMP..."
    cd $COMP_SRCDIR
    export SITE=NEMS.$MACHINE_ID
    export SYSTEM_USERDIR=`pwd`
    export SRCDIR=`pwd`
    export EXEDIR=`pwd`
    if [ "$NEMS_GRID"x != "x" ] ; then
      export NEMS_GRID=$NEMS_GRID
    else
      export NEMS_GRID=T126_mx5
#      export NEMS_GRID=T126_nx1
    fi
    ./comp_ice.backend
    cd ../CICE_CAP
    make -f makefile.nuopc LANLCICEDIR=$COMP_SRCDIR INSTALLDIR=$COMP_BINDIR install
    if ([ ! -d $COMP_BINDIR ]); then
      echo "...failed building $COMP."
    else
      echo "...done building $COMP."
    fi
  fi
}

build_mom5(){
  #TODO: This component has a totally non-standard way of building!!!!
  #TODO: MOM5 and MOM5_CAP should be merged into a single source tree, 
  #TODO: and building the CICE component in NUOPC mode should be done 
  #TODO: with standard target "nuopc". See HYCOM for an example.
  #
  # in: COMP, COMP_SRCDIR, COMP_BINDIR
  if [[ $1"" == "clean" ]] ; then
    echo "Cleaning $COMP..."
    echo "Only partially implemented!!!"
    echo "...done cleaning $COMP."
  else
    echo "Building $COMP..."
    cd $COMP_SRCDIR/exp
    ./MOM_compile.csh --platform $MACHINE_ID --type MOM_solo --experiment box1
    cd ../../MOM5_CAP
    make -f makefile.nuopc NEMSMOMDIR=$COMP_SRCDIR/exec/$MACHINE_ID INSTALLDIR=$COMP_BINDIR install
    if ([ ! -d $COMP_BINDIR ]); then
      echo "...failed building $COMP."
    else
      echo "...done building $COMP."
    fi
  fi
}

build_hycom(){
  # in: COMP, COMP_SRCDIR, COMP_BINDIR
  if [ $MACHINE_ID = linux_gnu ]; then
    HYCOM_ARCH='Alinux-gnu-relo'
  else
    HYCOM_ARCH='Aintelrelo'    
  fi

  if [[ $1"" == "clean" ]] ; then
    echo "Cleaning $COMP..."
    cd $COMP_SRCDIR/sorc
    make ARCH=$HYCOM_ARCH TYPE=nuopc clean
    echo "...done cleaning $COMP."
  else
    echo "Building $COMP..."
    cd $COMP_SRCDIR/sorc
    make ARCH=$HYCOM_ARCH TYPE=nuopc nuopc
    make ARCH=$HYCOM_ARCH TYPE=nuopc DESTDIR=/ INSTDIR=$COMP_BINDIR nuopcinstall
    if ([ ! -d $COMP_BINDIR ]); then
      echo "...failed building $COMP."
    else
      echo "...done building $COMP."
    fi
  fi
}

build_ipe(){
  # in: COMP, COMP_SRCDIR, COMP_BINDIR
  if [[ $1"" == "clean" ]] ; then
    echo "Cleaning $COMP..."
    cd $COMP_SRCDIR"LIB"
    make clean
    cd $COMP_SRCDIR
    make clean
    echo "...done cleaning $COMP."
  else
    echo "Building $COMP..."
    cd $COMP_SRCDIR"LIB"
    mkdir -p include lib bin
    cd src
    make theia_intel_parallel
    cd $COMP_SRCDIR
    make IPE=$COMP_SRCDIR"LIB" nuopc
    make IPE=$COMP_SRCDIR"LIB" DESTDIR=/ INSTDIR=$COMP_BINDIR nuopcinstall
    if ([ ! -d $COMP_BINDIR ]); then
      echo "...failed building $COMP."
    else
      echo "...done building $COMP."
    fi
  fi
}

build_wrfhydro(){
  # in: COMP, COMP_SRCDIR, COMP_BINDIR
  export HYDRO_D=1
  export WRF_HYDRO=1
  cp $COMP_SRCDIR/arc/macros.nems.$MACHINE_ID $COMP_SRCDIR/macros
  if [[ "$?" != "0" ]] ; then
    echo "[Error] WRFHYDRO macros file cannot be copied!" 1>&2
    exit 1
  fi

  if [[ $1"" == "clean" ]] ; then
    echo "Cleaning $COMP..."
    cd $COMP_SRCDIR
    make nuopcclean
    echo "...done cleaning $COMP."
  else
    echo "Building $COMP..."
    cd $COMP_SRCDIR
    make nuopc
    make DESTDIR=/ INSTDIR=$COMP_BINDIR nuopcinstall
    if ([ ! -d $COMP_BINDIR ]); then
      echo "...failed building $COMP."
    else
      echo "...done building $COMP."
    fi
  fi
}

build_ww3(){
  # in: COMP, COMP_SRCDIR, COMP_BINDIR
  if [[ $1"" == "clean" ]] ; then
    echo "Cleaning $COMP..."
    cd $COMP_SRCDIR/esmf
    make distclean
    echo "...done cleaning $COMP."
  else
    echo "Building $COMP..."
    cd $COMP_SRCDIR/esmf
    make WW3_COMP=Intel
    mkdir -p $COMP_BINDIR
    cp $COMP_SRCDIR/nuopc.mk $COMP_BINDIR
    if ([ ! -d $COMP_BINDIR ]); then
      echo "...failed building $COMP."
    else
      echo "...done building $COMP."
    fi
  fi
}

build_lis(){
  # in: COMP, COMP_SRCDIR, COMP_BINDIR                                                                                                                           
  # this required due to LIS interactive configure script
  # ideally, configure could be run here and pick up the
  # relevant environment variables
  cp $COMP_SRCDIR/arch/configure.lis.$MACHINE_ID.debug $COMP_SRCDIR/make/configure.lis
  if [[ "$?" != "0" ]] ; then
    echo "[Error] LIS configure.lis file cannot be copied!" 1>&2
    exit 1
  fi
  cp $COMP_SRCDIR/arch/LIS_misc.h.$MACHINE_ID $COMP_SRCDIR/make/LIS_misc.h
  if [[ "$?" != "0" ]] ; then
    echo "[Error] LIS LIS_misc.h file cannot be copied!" 1>&2
    exit 1
  fi
  cp $COMP_SRCDIR/arch/LIS_NetCDF_inc.h.$MACHINE_ID $COMP_SRCDIR/make/LIS_NetCDF_inc.h
  if [[ "$?" != "0" ]] ; then
    echo "[Error] LIS LIS_NetCDF_inc.h file cannot be copied!" 1>&2
    exit 1
  fi

  if [[ $1"" == "clean" ]] ; then
    echo "Cleaning $COMP..."
    cd $COMP_SRCDIR/make
    make clean
    echo "...done cleaning $COMP."
  else
    echo "Building $COMP..."
    cd $COMP_SRCDIR
    ./compile
    cd $COMP_SRCDIR/runmodes/nuopc_cpl_mode 
    make
    make install DESTDIR=/ INSTDIR=$COMP_BINDIR
    if ([ ! -d $COMP_BINDIR ]); then
      echo "...failed building $COMP."
    else
      echo "...done building $COMP."
    fi
  fi
}


# MAIN #########################################################################

trap 'deletetempfiles'  EXIT     # delete temp files on exit

ROOTDIR=`pwd`
LOGFILE=`pwd`/appBuilder.log.$$
NEMSDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )

# Start of the Front-End #######################################################

# Determine the available application(s)
appCounter=0
shopt -s nullglob # all expansion to null string
for i in $ROOTDIR/*.appBuilder; do
  if [ "x$i" != "x" ]; then
    let appCounter++
    title=`head -1 $i`
    title=${title#"#"}
    title=${title#" "}
    appbuilderlist=( "${appbuilderlist[@]}" $i )
    i=${i#"$ROOTDIR/"}
    i=${i%".appBuilder"}
    if [ $appCounter == 1 ]; then
      radiolist=( "${radiolist[@]}" $i "$title" on )
    else
      radiolist=( "${radiolist[@]}" $i "$title" off )
    fi
  fi
done

APPLEVELUSE=true

# Situation dependent welcome
if [ $appCounter != 1 ]; then
  bailFlag=true
  while [ $bailFlag == "true" ] ; do
  bailFlag=false
  $tool --clear --backtitle "NEMS Application Builder" \
    --title "Welcome" --msgbox "Welcome to the NOAA Environmental Modeling System (NEMS) \
Application Builder. \
  \n\nThe NEMS Application Builder will guide you through the installation of \
the NEMS executable. \
  \n\nProceed with <Enter>, exit with <Esc>. \
  \n\nOther keys used: \
  \n  <Arrows> - to move between items, \
  \n  <Tab>    - to change focus between input areas, \
  \n  <Space>  - to select & unselect items." \
  19 60
  if [ "$?" != "0" ] ; then
    bailout
  fi
  done
fi

# deal with the situation of no appBuilder files found
if [ $appCounter == 0 ]; then
  APPLEVELUSE=false
  radiolist=( NEMS "Explicit selection of NEMS components" on )
  appCounter=1
  # check the AppBuilder subdirectory for more appBuilder files
  for i in $ROOTDIR/AppBuilder/*.appBuilder; do
    if [ "x$i" != "x" ]; then
      let appCounter++
      title=`head -1 $i`
      title=${title#"#"}
      title=${title#" "}
      appbuilderlist=( "${appbuilderlist[@]}" $i )
      i=${i#"$ROOTDIR/AppBuilder/"}
      i=${i%".appBuilder"}
      radiolist=( "${radiolist[@]}" $i "$title" off )
    fi
  done
fi

# Selection of NEMS application
if [[ $appCounter > 1 ]]; then
  bailFlag=true
  while [ $bailFlag == "true" ] ; do
  bailFlag=false
  $tool --clear --backtitle "NEMS Application Builder" \
    --title "Application Selection" \
    --radiolist "Select the target application to be supported by the \
  NEMS executable:"  15 75 $appCounter \
    "${radiolist[@]}" \
    2> $LOGFILE
  if [ "$?" != "0" ] ; then
    bailout
  fi
  done
else
  # explicitly write selection into the LOGFILE
  echo "${radiolist[0]}" > $LOGFILE
fi

# new line into file
echo >> $LOGFILE

# determine APP selection
APP=`head -1 $LOGFILE`

# select on the APP selection
case $APP in

NEMS) 
# Selection of NEMS components
bailFlag=true
while [ $bailFlag == "true" ] ; do
bailFlag=false
$tool --clear --backtitle "NEMS Application Builder" \
  --title "NEMS Component Selection" \
  --checklist "Select the components to be built into the NEMS executable \
explicitly:"  25 75 18 \
  SATM      "ATM: Stub Model"                                       off \
  XATM      "ATM: Dead Model"                                       off \
  GSM       "ATM: Global Spectral Model"                            on  \
  NMMB      "ATM: Nonhydrostatic Multiscale Model on B Grid"        off \
  FIM       "ATM: Flow-Following Finite Volume Icosahedral Model"   off \
  SICE      "ICE: Stub Model"                                       off \
  XICE      "ICE: Dead Model"                                       off \
  CICE      "ICE: Los Alamos Sea Ice Model"                         off \
  KISS      "ICE: NOAA Keeping Ice'S Simplicity ice model"          off \
  SOCN      "OCN: Stub Model"                                       off \
  XOCN      "OCN: Dead Model"                                       off \
  MOM5      "OCN: NOAA Modular Ocean Model 5"                       off \
  HYCOM     "OCN: HYbrid Coordinate Ocean Model"                    off \
  POM       "OCN: Princeton Ocean Model"                            off \
  SWAV      "WAV: Stub Model"                                       off \
  XWAV      "WAV: Dead Model"                                       off \
  WW3       "WAV: WaveWatchIII"                                     off \
  SLND      "LND: Stub Model"                                       off \
  XLND      "LND: Dead Model"                                       off \
  LIS       "LND: NASA LIS"                                         off \
  NOAH      "LND: Community Land Surface Model"                     off \
  NOAHMP    "LND: Community Land Surface Model with Multi-Physics"  off \
  SIPM      "IPM: Stub Model"                                       off \
  XIPM      "IPM: Dead Model"                                       off \
  IPE       "IPM: NOAA Ionosphere Plasmasphere Electrodynamics"     off \
  SHYD      "HYD: Stub Model"                                       off \
  XHYD      "HYD: Dead Model"                                       off \
  WRFHYDRO  "HYD: Hydraulics portion of WRF-Hydro Model"            off \
  2>> $LOGFILE
if [ "$?" != "0" ] ; then
  bailout
fi
  COMPONENTS=( `tail -1 $LOGFILE` )
done
;;

*)
# Need to find the associated appBuilder file
for i in "${appbuilderlist[@]}" ; do
  if ( [[ "$i" =~ "$APP" ]] ); then
    source "$i"
    echo "${COMPONENTS[@]}" >> $LOGFILE
  fi
done
;;

esac

# Situation dependent welcome
if [ $appCounter == 1 ]; then
  # exactly one application present -> Application level
  bailFlag=true
  while [ $bailFlag == "true" ] ; do
  bailFlag=false
  comps="${COMPONENTS[@]}"
  $tool --clear --backtitle "NEMS Application Builder" \
    --title "Welcome" --msgbox "Welcome to the NOAA Environmental Modeling System (NEMS) \
Application Builder. \
  \n\nPreparing to build the NEMS executable for the \"$APP\" application. \
  \n\nWith components: $comps. \
  \n\nProceed with <Enter>, exit with <Esc>. \
  \n\nOther keys used: \
  \n  <Arrows> - to move between items, \
  \n  <Tab>    - to change focus between input areas, \
  \n  <Space>  - to select & unselect items." \
  22 60
  if [ "$?" != "0" ] ; then
    bailout
  fi
  done
fi

# Start of the Back-End ########################################################

# use NEMS script to determine the platform
$tool --backtitle "NEMS Application Builder" \
  --title "Info" --infobox "Determine platform..." 6 25
bailFlag=true
while [ $bailFlag == "true" ] ; do
bailFlag=false
source $NEMSDIR/tests/detect_machine.sh machineonly > /dev/null 2>&1
if [ "$MACHINE_ID"x == "x" ] ; then
  $tool --clear --backtitle "NEMS Application Builder" \
  --title "Unknown machine" --yesno \
  "Need to add NEMS configuration for this machine before trying again!\
  \n\nTry again <Yes>, or bail out <No>."\
  10 40
  if [ "$?" != "0" ] ; then
    exit
  fi
  bailFlag=true
fi
done
$tool --backtitle "NEMS Application Builder" \
  --title "Info" --infobox "Determine platform...$MACHINE_ID" 6 35

# configure NEMS for the specific platform
if [ $MACHINE_ID = linux_gnu ]; then
  COMPILER=""
else
  COMPILER="intel_"
fi
cd $NEMSDIR/src
./configure coupled_$COMPILER$MACHINE_ID  > $ROOTDIR/appBuilder.NEMS.log.$$ 2>&1
echo >> $ROOTDIR/appBuilder.NEMS.log.$$ 2>&1
cd $ROOTDIR

# set the platform specific build environment (if provided)
envir="environment_${MACHINE_ID}"
if [ `type -t $envir`"" == 'function' ]; then
  $envir
else
  if [[ -f $NEMSDIR/src/conf/modules.nems ]] ; then
    # prompt to use default environment provided by NEMS
    $tool --clear --backtitle "NEMS Application Builder" \
      --title "Build environment" \--yesno \
"Source the NEMS provided module file to set up the build environment?\n\n\
Select <Yes> to overwrite the build environment of the current \
shell (purge modules) and to replace it with the NEMS provided setting.\n\n\
Select <No> to retain and use the build environment of the current shell." \
16 40
    if [[ "$?" == "0" ]] ; then
      source $NEMSDIR/src/conf/modules.nems
    fi
  fi
fi

# make available dirs of pre-installed externals
source $NEMSDIR/src/conf/externals.nems

# loop over the components to build them
if [[ "$APPLEVELUSE" == "true" ]] ; then
  for i in "${COMPONENTS[@]}" ; do
    # first remove potential quotation marks
    i=${i#\"}
    COMP=${i%\"}
    if [[ $COMP != "GSM" && $COMP != "NMMB" && $COMP != "FIM" ]] ; then
      envir="environment_${MACHINE_ID}_${COMP}"
      if [ `type -t $envir`"" == 'function' ]; then
        $envir
      fi
      if [[ $COMP == "HYCOM" ]] ; then
        BUILD_FUNC=build_hycom
      elif [[ $COMP == "MOM5" ]] ; then
        BUILD_FUNC=build_mom5
      elif [[ $COMP == "CICE" ]] ; then
        BUILD_FUNC=build_cice
      elif [[ $COMP == "IPE" ]] ; then
        BUILD_FUNC=build_ipe
      elif [[ $COMP == "WRFHYDRO" ]] ; then
        BUILD_FUNC=build_wrfhydro
      elif [[ $COMP == "WW3" ]] ; then
        BUILD_FUNC=build_ww3
      elif [[ $COMP == "LIS" ]] ; then
	BUILD_FUNC=build_lis
      else
        BUILD_FUNC=build_std
      fi
      # attempt to build the component
      build_checkloop
    fi
  done
fi

cd $NEMSDIR/src
# for the explicit NEMS case must obtain component locations
if [[ "$APPLEVELUSE" == "false" ]] ; then
  for i in "${COMPONENTS[@]}" ; do
    # first remove potential quotation marks
    i=${i#\"}
    COMP=${i%\"}
    if [[ $COMP != "GSM" && $COMP != "NMMB" && $COMP != "FIM" ]] ; then
      eval ${COMP}_BINDIR=\${${COMP}_DIR}
    fi
  done
fi

# loop over the components to construct COMP and COMPDIRS make variables
COMP=""
COMPDIRS=""
gsmFlag="false"
nmmFlag="false"
for i in "${COMPONENTS[@]}" ; do
  # first remove potential quotation marks
  i=${i#\"}
  COMPO=${i%\"}
 # - NEMS internal target components
  if [[ $COMPO == "GSM" ]] ; then
    gsmFlag="true"
  elif [[ $COMPO == "NMMB" ]] ; then
    nmmFlag="true"
 # - stub components
  elif [[ $COMPO == "SATM" ]] ; then
    COMP=$COMP",satm"
    COMPDIRS="$COMPDIRS SATM_DIR=$SATM_BINDIR"
  elif [[ $COMPO == "SHYD" ]] ; then
    COMP=$COMP",shyd"
    COMPDIRS="$COMPDIRS SHYD_DIR=$SHYD_BINDIR"
  elif [[ $COMPO == "SICE" ]] ; then
    COMP=$COMP",sice"
    COMPDIRS="$COMPDIRS SICE_DIR=$SICE_BINDIR"
  elif [[ $COMPO == "SIPM" ]] ; then
    COMP=$COMP",sipm"
    COMPDIRS="$COMPDIRS SIPM_DIR=$SIPM_BINDIR"
  elif [[ $COMPO == "SLND" ]] ; then
    COMP=$COMP",slnd"
    COMPDIRS="$COMPDIRS SLND_DIR=$SLND_BINDIR"
  elif [[ $COMPO == "SOCN" ]] ; then
    COMP=$COMP",socn"
    COMPDIRS="$COMPDIRS SOCN_DIR=$SOCN_BINDIR"
  elif [[ $COMPO == "SWAV" ]] ; then
    COMP=$COMP",swav"
    COMPDIRS="$COMPDIRS SWAV_DIR=$SWAV_BINDIR"
 # - dead components
  elif [[ $COMPO == "XATM" ]] ; then
    COMP=$COMP",xatm"
    COMPDIRS="$COMPDIRS XATM_DIR=$XATM_BINDIR"
  elif [[ $COMPO == "XHYD" ]] ; then
    COMP=$COMP",xhyd"
    COMPDIRS="$COMPDIRS XHYD_DIR=$XHYD_BINDIR"
  elif [[ $COMPO == "XICE" ]] ; then
    COMP=$COMP",xice"
    COMPDIRS="$COMPDIRS XICE_DIR=$XICE_BINDIR"
  elif [[ $COMPO == "XIPM" ]] ; then
    COMP=$COMP",xipm"
    COMPDIRS="$COMPDIRS XIPM_DIR=$XIPM_BINDIR"
  elif [[ $COMPO == "XLND" ]] ; then
    COMP=$COMP",xlnd"
    COMPDIRS="$COMPDIRS XLND_DIR=$XLND_BINDIR"
  elif [[ $COMPO == "XOCN" ]] ; then
    COMP=$COMP",xocn"
    COMPDIRS="$COMPDIRS XOCN_DIR=$XOCN_BINDIR"
  elif [[ $COMPO == "XWAV" ]] ; then
    COMP=$COMP",xwav"
    COMPDIRS="$COMPDIRS XWAV_DIR=$XWAV_BINDIR"
 # - data components
  elif [[ $COMPO == "DATAWAM" ]] ; then
    COMP=$COMP",datawam"
    COMPDIRS="$COMPDIRS DATAWAM_DIR=$DATAWAM_BINDIR" 
  elif [[ $COMPO == "DATAIPE" ]] ; then
    COMP=$COMP",dataipe"
    COMPDIRS="$COMPDIRS DATAIPE_DIR=$DATAIPE_BINDIR" 
 # - actual ocean model components
  elif [[ $COMPO == "HYCOM" ]] ; then
    COMP=$COMP",hycom"
    COMPDIRS="$COMPDIRS HYCOM_DIR=$HYCOM_BINDIR"
  elif [[ $COMPO == "MOM5" ]] ; then
    COMP=$COMP",mom5"
    COMPDIRS="$COMPDIRS MOM5_DIR=$MOM5_BINDIR"
 # - actual wave model components
  elif [[ $COMPO == "WW3" ]] ; then
    COMP=$COMP",ww3"
    COMPDIRS="$COMPDIRS WW3_DIR=$WW3_BINDIR"
 # - actual ice model components
  elif [[ $COMPO == "CICE" ]] ; then
    COMP=$COMP",cice"
    COMPDIRS="$COMPDIRS CICE_DIR=$CICE_BINDIR"
 # - actual ionosphere-plasmasphere model components
  elif [[ $COMPO == "IPE" ]] ; then
    COMP=$COMP",ipe"
    COMPDIRS="$COMPDIRS IPE_DIR=$IPE_BINDIR"
 # - actual hydraulic model components
  elif [[ $COMPO == "WRFHYDRO" ]] ; then
    COMP=$COMP",wrfhydro"
    COMPDIRS="$COMPDIRS WRFHYDRO_DIR=$WRFHYDRO_BINDIR"
  elif [[ $COMPO == "LIS" ]] ; then
    COMP=$COMP",lis"
    COMPDIRS="$COMPDIRS LIS_DIR=$LIS_BINDIR"
  fi
done

# construct the NEMS target
if ( [[ $gsmFlag == "true" ]] ); then
  if ( [[ $nmmFlag == "true" ]] ); then
    TARGET=nmm_gsm
  else
    TARGET=gsm
  fi
elif ( [[ $nmmFlag == "true" ]] ); then
  TARGET=nmm
fi

# TODO: remove the default "gsm" target when NEMS can handle it
if [[ "x$TARGET" == "x" ]] ; then
  TARGET=gsm
fi

# turn COMP into a single string with commas
if [[ "x$COMP" != "x" ]] ; then
  COMPOPT="COMP=,${COMP#","},"
else
  COMPOPT=""
fi

# ready to build the NEMS executable
$tool --clear --backtitle "NEMS Application Builder" \
  --title "Ready to build NEMS executable:" \
  --msgbox "make $TARGET $COMPOPT$COMPDIRS \
  \n\nProceed with <Enter>, exit with <Esc>." 20 100

if [ "$?" != "0" ] ; then
  bailout
fi

# finally attempt to build the NEMS executable
export NEMSAppBuilder # guard variable used by NEMS makefile
# set nems specific build environment if provided
envir="environment_${MACHINE_ID}_nems"
if [ `type -t $envir`"" == 'function' ]; then
  $envir
fi
# potentially clean-up first
if [[ -f ../exe/NEMS.x ]] ; then
  $tool --clear --backtitle "NEMS Application Builder" \
    --title "Alert" --yesno \
    "Re-use parts from the previous NEMS build <Yes>, or build from scratch <No>?" \
    8 40
  if [[ "$?" != "0" ]] ; then
  
    if [[ "$toolflag" == "dialog" ]] ; then
      # "dialog" implementation
  
      $tool --backtitle "NEMS Application Builder" \
            --title "NEMS Clean Progress" \
            --tailboxbg $ROOTDIR/appBuilder.NEMS.log.$$ 20 120 \
            --and-widget --ok-label "CANCEL" \
            --begin 2 1 --msgbox "Press CANCEL to interrupt." 5 30 \
            2> /dev/null &
      mypid=$!
      make clean > $ROOTDIR/appBuilder.NEMS.log.$$ 2>&1 &
      makepid=$!
  
      # now wait for either for $mypid to finish because of canceling, or
      # $makepid to finish due to done or bail out of make command.
  
      while ps -p $makepid > /dev/null
      do
        if ! ps -p $mypid > /dev/null
        then
          killall gmake
          killall make
        fi
      done
      kill $mypid > /dev/null 2>&1
    else
      # "whiptail" implementation (less fancy)
      make clean 2>&1 | tee $ROOTDIR/appBuilder.NEMS.log.$$    
    fi
    
  else
    rm -f ../exe/NEMS.x
  fi
fi
# build loop
while [[ ! -f ../exe/NEMS.x ]] ; do
  echo "make $TARGET $COMPOPT $COMPDIRS" >> $ROOTDIR/appBuilder.NEMS.log.$$ 2>&1
  echo >> $ROOTDIR/appBuilder.NEMS.log.$$ 2>&1
  
  if [[ "$toolflag" == "dialog" ]] ; then
    # "dialog" implementation

    $tool --backtitle "NEMS Application Builder" \
          --title "NEMS Build Progress" \
          --tailboxbg $ROOTDIR/appBuilder.NEMS.log.$$ 20 120 \
          --and-widget --ok-label "CANCEL" \
          --begin 2 1 --msgbox "Press CANCEL to interrupt." 5 30 \
          2> /dev/null &
    mypid=$!
    make $TARGET $COMPOPT $COMPDIRS >> $ROOTDIR/appBuilder.NEMS.log.$$ 2>&1 &
    makepid=$!
  
    # now wait for either for $mypid to finish because of canceling, or
    # $makepid to finish due to done or bail out of make command.
  
    while ps -p $makepid > /dev/null
    do
      if ! ps -p $mypid > /dev/null
      then
        killall gmake
        killall make
      fi
    done
    kill $mypid > /dev/null 2>&1
  
    if [[ ! -f ../exe/NEMS.x ]] ; then
      # build did not succeed
      $tool --clear --backtitle "NEMS Application Builder" \
        --title "Trouble view log" --textbox $ROOTDIR/appBuilder.NEMS.log.$$ \
        20 120
      $tool --clear --backtitle "NEMS Application Builder" \
        --title "Diagnosis" --yesno \
        "Looks like the attempt to build the NEMS executable failed.\
        \n\nTry again <Yes>, or quit <No>." 10 40
      if [[ "$?" != "0" ]] ; then
        cp $ROOTDIR/appBuilder.NEMS.log.$$ $ROOTDIR/appBuilder.NEMS.log
        break
      fi
    fi

  else
    # "whiptail" implementation (less fancy)
  
    make $TARGET $COMPOPT $COMPDIRS 2>&1 | tee $ROOTDIR/appBuilder.NEMS.log.$$

    if [[ ! -f ../exe/NEMS.x ]] ; then
      # build did not succeed
      $tool --clear --backtitle "NEMS Application Builder" \
        --title "Trouble view log" --textbox $ROOTDIR/appBuilder.NEMS.log.$$ \
        20 120 --scrolltext
      $tool --clear --backtitle "NEMS Application Builder" \
        --title "Diagnosis" --yesno \
        "Looks like the attempt to build the NEMS executable failed.\
        \n\nTry again <Yes>, or quit <No>." 10 40
      if [[ "$?" != "0" ]] ; then
        cp $ROOTDIR/appBuilder.NEMS.log.$$ $ROOTDIR/appBuilder.NEMS.log
        break
      fi
    fi
  fi
done
if [[ -f ../exe/NEMS.x ]] ; then
  if [[ "$toolflag" == "dialog" ]] ; then
    # "dialog" implementation
    $tool --clear --backtitle "NEMS Application Builder" \
      --title "Success" --yesno "The NEMS executable was successfully built. \
      \n\nView log <Yes>, or exit <No>." 7 60
    if [[ "$?" == "0" ]] ; then
      $tool --clear --backtitle "NEMS Application Builder" \
        --title "Success view log" --textbox $ROOTDIR/appBuilder.NEMS.log.$$ \
        20 120
    fi
  else
    # "whiptail" implementation
    $tool --clear --backtitle "NEMS Application Builder" \
      --title "Success" --yesno "The NEMS executable was successfully built. \
      \n\nView log <Yes>, or exit <No>." 10 60
    if [[ "$?" == "0" ]] ; then
      $tool --clear --backtitle "NEMS Application Builder" \
        --title "Success view log" --textbox $ROOTDIR/appBuilder.NEMS.log.$$ \
        20 120 --scrolltext
    fi
  fi
fi

################################################################################
# Finish up

cd $ROOTDIR
clear
exit
