#!/bin/bash -e
# --------------------------------------------------------------------------- #
# w3_make : Compile and link WAVEWATCH III programs using standard make and   #
#           makefile methods.                                                 #
#                                                                             #
# use     : w3_make [program [...]]                                           #
#              program: program name of WAVEWATCH III (sub)program.           #
#                                                                             #
# error codes : Program ends if error occurs in make_makefile.sh.             #
#                                                                             #
# programs used :                                                             #
#       make_makefile.sh :  Makes the makefile.                               #
#                                                                             #
# programs called from the makefile :                                         #
#       ad3   : script to execute preprocessor and to compile.                #
#       link  : linker script.                                                #
#                                                                             #
#                                                      Hendrik L. Tolman      #
#                                                      May 2009               #
#                                                      March 2014             #
#                                                                             #
#    Copyright 2009-2013 National Weather Service (NWS),                      #
#       National Oceanic and Atmospheric Administration.  All rights          #
#       reserved.  WAVEWATCH III is a trademark of the NWS.                   #
#       No unauthorized use without permission.                               #
#                                                                             #
# --------------------------------------------------------------------------- #


# --------------------------------------------------------------------------- #
# 1. Preparations                                                             #
# --------------------------------------------------------------------------- #

# 1.a ID header  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  echo ' '
  echo '                *****************************'
  echo '              ***   WAVEWATCH III make      ***'
  echo '                *****************************'
  echo ' '


# 1.b Input arguments - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  if [ $# -eq 0 ]
  then
    default_mode=1
    all_programs=""
  else
    default_mode=0
    all_programs="$*"
  fi


# 1.c Get data from setup file - - - - - - - - - - - - - - - - - - - - - - - - 

  source $(dirname $0)/w3_setenv
  main_dir=$WWATCH3_DIR
  temp_dir=$WWATCH3_TMP
  source=$WWATCH3_SOURCE
  list=$WWATCH3_LIST

  echo "Main directory    : $main_dir"
  echo "Scratch directory : $temp_dir"
  echo "Save source codes : $source"
  echo "Save listings     : $list"

# 1.d Check / make directories   - - - - - - - - - - - - - - - - - - - - - - -

  # bin dir
  if [ ! -d $main_dir/bin ]
  then
    echo ' '
    echo "[ERROR] Directory $main_dir/bin not found"
    echo '        Please check the content of your directory model'
    exit 1
  fi

  # exe dir
  if [ ! -d $main_dir/exe ]
  then
    mkdir -p $main_dir/exe
  fi

  # switch file
  if [ -z "$(env | grep switch_file)" ]
  then
    switch_file=$main_dir/bin/switch
  fi
  if [ ! -e $switch_file ] || [ ! -r $switch_file ]
  then
    echo ' '
    echo "[ERROR] switch file $switch_file not found"
    echo "        Please run $main_dir/bin/w3_setup <main_dir> -c <comp> -s <switch>"
    exit 1
  fi
  cp  $switch_file $main_dir/exe/

  # comp file
  comp_file=$main_dir/bin/comp
  if [ ! -e $comp_file ] || [ ! -r $comp_file ]
  then
    echo ' '
    echo "[ERROR] comp file $comp_file not found"
    echo "        Please run $main_dir/bin/w3_setup <main_dir> -c <comp> -s <switch>"
    exit 1
  fi

  # link file
  link_file=$main_dir/bin/link
  if [ ! -e $link_file ] || [ ! -r $link_file ]
  then
    echo ' '
    echo "[ERROR] link file $comp_file not found"
    echo "        Please run $main_dir/bin/w3_setup <main_dir> -c <comp> -s <switch>"
    exit 1
  fi

  # ftn dir
  makefile=$main_dir/ftn/makefile
  if [ ! -d $main_dir/ftn ]
  then
    echo ' '
    echo "[ERROR] Directory $main_dir/ftn not found"
    echo '        Please check the content of your directory model'
    exit 1
  fi
  rm -f $makefile




# 1.e Set regular and netCDF progs - - - - - - - - - - - - - - - - - - - - - -

# GRID STRT BOUND OUTF OUTP TRCK GRIB GINT GX* UPRSTR LIBWW3
#  reg_programs = non-NetCDF programs
  reg_programs="ww3_grid" 
  reg_programs="$reg_programs ww3_strt"
  reg_programs="$reg_programs ww3_bound"
  reg_programs="$reg_programs ww3_outf"
  reg_programs="$reg_programs ww3_outp"
  reg_programs="$reg_programs ww3_trck"
  reg_programs="$reg_programs ww3_grib"
  reg_programs="$reg_programs ww3_gint"
  reg_programs="$reg_programs gx_outf"
  reg_programs="$reg_programs gx_outp"
  reg_programs="$reg_programs ww3_uprstr" 

# PRNC OUNF OUNP BOUNC TRNC
# cdf_programs = NetCDF programs
  cdf_programs="ww3_prnc"
  cdf_programs="$cdf_programs ww3_ounf"
  cdf_programs="$cdf_programs ww3_ounp"
  cdf_programs="$cdf_programs ww3_bounc"
  cdf_programs="$cdf_programs ww3_trnc"

  # PRTIDE
  if [ -n "`grep TIDE $switch_file`" ]
  then
    cdf_programs="$cdf_programs ww3_prtide"
  fi

  # NCEP GRIB
  export ncep_grib_compile="no"
  if [ -n "`grep NCEP $switch_file`" ]
  then
    export ncep_grib_compile="yes"
  fi

  # MULTI MULTI_ESMF SBS1
  if [ -n "`grep SCRIPNC $switch_file`" ] || [ -n "`grep OASIS $switch_file`" ]  || [ -n "`grep PDLIB $switch_file`" ]
  then
    cdf_programs="$cdf_programs ww3_multi"
    cdf_programs="$cdf_programs ww3_sbs1"
    cdf_programs="$cdf_programs libww3"
    if [ $ESMFMKFILE ]
    then
      cdf_programs="$cdf_programs ww3_multi_esmf"
    fi
  else
    reg_programs="$reg_programs ww3_multi"
    reg_programs="$reg_programs ww3_sbs1"
    reg_programs="$reg_programs libww3"
    if [ $ESMFMKFILE ]
    then
      reg_programs="$reg_programs ww3_multi_esmf"
    fi
  fi

  # SYSTRK
  if [ -n "`grep TRKNC $switch_file`" ]
  then
    cdf_programs="$cdf_programs ww3_systrk"
    systrck_nc4notrknc=0
  else
    if [ -n "`grep NC4 $switch_file`" ]
    then
      systrck_nc4notrknc=1
    else
      systrck_nc4notrknc=0
      reg_programs="$reg_programs ww3_systrk"
    fi
  fi

  # SHEL PREP GSPL
  if [ -n "`grep OASIS $switch_file`" ] || [ -n "`grep PDLIB $switch_file`" ]
  then
    cdf_programs="$cdf_programs ww3_gspl"
    cdf_programs="$cdf_programs ww3_prep"
  else
    reg_programs="$reg_programs ww3_gspl"
    reg_programs="$reg_programs ww3_prep"
  fi

  if [ -n "`grep OASIS $switch_file`" ]  || [ -n "`grep PDLIB $switch_file`" ]
  then
    cdf_programs="$cdf_programs ww3_shel"
  else
    reg_programs="$reg_programs ww3_shel"
  fi

  if [ -n "`grep -nri fPIC $comp_file`" ]
  then
    reg_programs="$reg_programs libww3.so"
  else
    echo 'Shared Object     : No'
  fi

  # if no progs in argument
  if [ -z "$all_programs" ]
  then
    if [ -z "$WWATCH3_NETCDF" ]
    then
      all_programs="$reg_programs"
    else
      all_programs="$reg_programs $cdf_programs"
    fi
  fi
  echo ' '
  echo "[INFO] list of the programs selected : $all_programs"


# 1.f sort sequential and parallel programs - - - - - - - - - - - - - - - - - -

  # no filtering is done to distinguish sequential to parallel programs 
  # see w3_automake for this feature
  progs=$all_programs


# 1.e Set sequential or parallel folders - - - - - - - - - - - - - - - - - - -

  flag_SHRD=`grep SHRD $switch_file | wc -l | awk '{ print $1}'`
  flag_OMPX=`grep OMPX $switch_file | wc -l | awk '{ print $1}'`
  flag_OMPH=`grep OMPH $switch_file | wc -l | awk '{ print $1}'`

  switch_file_old=$main_dir/bin/switch.old
  exec_type_file=$main_dir/exe/exec_type

  here=`pwd`


  if [ "$flag_SHRD" -gt '0' ]
  then
    if [ "$flag_OMPX" -gt '0' ]
    then
      pres_type='OMP'
    else
      pres_type='SEQ'
    fi
  else
    if [ "$flag_OMPH" -gt '0' ]
    then
      pres_type='HYB'
    else
      pres_type='MPI'
    fi
  fi

  rm -rf $main_dir/obj
  rm -rf $main_dir/mod
  if [ -f ${switch_file_old}_$pres_type ] ; then
     cp ${switch_file_old}_$pres_type $switch_file_old
  fi
  if [ -f ${makefile}_$pres_type ] ; then
    cp ${makefile}_$pres_type $makefile
  fi
  cd $main_dir
  mkdir -p obj_$pres_type mod_$pres_type
  ln -sf obj_$pres_type obj
  ln -sf mod_$pres_type mod
  cd $here



# 1.c Setup for NetCDF compile - - - - - - - - - - - - - - - - - - - - - - - - 

# 1.c.1 NetCDF compile message function

  netcdf_compile_message () {

  cat 2>&1 << 'EOF'

*****************************************************************
***         WAVEWATCH III NetCDF Compile Instructions         ***
*****************************************************************

Compile of WAVEWATCH III NetCDF enabled programs requires the
environment variable WWATCH3_NETCDF be set to either NC3 (compile
with NetCDF version 3.x) or NC4 (compile with NetCDF version 4.x).

If WWATCH3_NETCDF = NC3, then the following environment variables
are required.

    NETCDF_LIBDIR = <path to NetCDF-3 libraries>
    NETCDF_INCDIR = <path to NetCDF-3 include>

If WWATCH3_NETCDF = NC4, then the following environment variables
are required.

    NETCDF_CONFIG = <path to NetCDF-4 nc-config utility>

The nc-config utility (part of the NetCDF-4 install) is used to
determine the appropriate compile and link flags for the
WWATCH3_NETCDF=NC4 compile.

The NetCDF-4 compile requires NetCDF version 4.1.1 or higher.
Use "nc-config --version" to check the version of the installed
NetCDF.

Compiling with the NC4 switch requires WWATCH3_NETCDF=NC4 and the
NetCDF-4 installation compiled with the NetCDF-4 API enabled.
Use "nc-config --has-nc4" to check if the installed NetCDF has
the NetCDF-4 API enabled.

*****************************************************************

EOF

  }

# 1.c.2 NetCDF check compile environment function

  netcdf_check_compile () {

  mode=$1 #must be ERROR or WARNING

  if [ -z "$WWATCH3_NETCDF" ]
  then
    netcdf_compile_message
    echo "$mode: WWATCH3_NETCDF not defined"; echo ' '
    return 1
  else
    case $WWATCH3_NETCDF in
      NC3)
        if [ -z "$NETCDF_LIBDIR" ]
        then
          netcdf_compile_message
          echo "$mode: NETCDF_LIBDIR not defined"; echo ' '
          return 1
        fi
        if [ -z "$NETCDF_INCDIR" ]
        then
          netcdf_compile_message
          echo "$mode: NETCDF_INCDIR not defined"; echo ' '
          return 1
        fi
      ;;
      NC4)
        if [ ! -n "`grep NC4 $switch_file`" ]
        then
          echo "WARNING: NC4 is set in WWATCH3_NETCDF but not in the switch file"; echo ' '
#          return 1
        fi
        if [ -z "$NETCDF_CONFIG" ]
        then
          netcdf_compile_message
          echo "$mode: NETCDF_CONFIG not defined"; echo ' '
          return 1
        fi
        if [ ! -x "$NETCDF_CONFIG" ]
        then
          netcdf_compile_message
          echo "$mode: $NETCDF_CONFIG does not exist or is not executable"; echo ' '
          return 1
        fi
        netcdf_version=`$NETCDF_CONFIG --version | awk '{print $2}'`
        if [ -z "`echo $netcdf_version | cut -d. -f3`" ]
        then
          netcdf_version="$netcdf_version.0"
        fi
        if [ `echo $netcdf_version | tr -d . | tr -d - | tr -d 'A-Z a-z'` -lt 411 ]
        then
          netcdf_compile_message
          echo "$mode: NetCDF version $netcdf_version < 4.1.1"; echo ' '
          return 1
        fi
      ;;
      *)
        netcdf_compile_message
        echo "$mode: WWATCH3_NETCDF=$WWATCH3_NETCDF not supported"; echo ' '
        return 1
      ;;
    esac
  fi

  return 0
  }

# 1.c.3 NetCDF check api function

  netcdf_check_api () {

  mode=$1 #must be ERROR or WARNING

  if [ -n "`grep NC4 $switch_file`" ]
  then
    case $WWATCH3_NETCDF in
      NC3)
        netcdf_compile_message
        echo "$mode: WWATCH3_NETCDF=NC3 incompatible with NC4 switch"; echo ' '
        return 1
      ;;
      NC4)
        if [ "`$NETCDF_CONFIG --has-nc4`" = 'no' ]
        then
          netcdf_compile_message
          echo "$mode: NetCDF-4 API not enabled (required by NC4 switch)"; echo ' '
          return 1
        fi
      ;;
    esac
  fi

  return 0
  }

# 1.c.4 Check for NetCDF compile

  if [ $default_mode -eq 1 ]
  then
    if ! netcdf_check_compile WARNING
    then
      echo "NetCDF enabled programs ($cdf_programs)"
      echo "will not be compiled unless NetCDF compile environment is properly set."; echo ' '
      if [ $systrck_nc4notrknc -eq 1 ] 
      then 
         echo "WARNING: ww3_systrk will not be compiled due to invalid switch option."; echo ' '
         echo "TRKNC switch is also required with NC4."; echo ' '
      fi 
      echo "Continuing with compile of non-NetCDF programs ..."; echo ' '
      progs="$reg_programs"
    fi
  else
    nc_compile=0
    for prog in $cdf_programs
    do
      if [ -n "`echo $progs | grep $prog`" ]
      then
        nc_compile=1
      fi
    done
    if [ $nc_compile -eq 1 ]
    then
      if ! netcdf_check_compile ERROR
      then
        echo "NetCDF enabled programs ($cdf_programs)"
        echo "will not be compiled unless NetCDF compile environment is properly set."; echo ' '
        echo "Now exiting ..."; echo ' '
        exit 1
      fi
    fi
    systrkprog="ww3_systrk"
    for prog in $systrkprog
    do
      if [ -n "`echo $progs | grep $prog`" ]
      then   
        if [ $systrck_nc4notrknc -eq 1 ]
        then
          echo "ERROR: ww3_systrk will not be compiled due to invalid switch option."; echo ' '
          echo "TRKNC switch is also required with NC4."; echo ' '
          echo "Now exiting ..."; echo ' '
          exit 1
        fi
      fi
    done
  fi

# 1.d Prepare scratch directory  - - - - - - - - - - - - - - - - - - - - - - - 

  if test ! -d $temp_dir
  then
    if ! `mkdir -p $temp_dir`
    then
      echo ' ' ; echo "   *** Cannot create $temp_dir ***" ; echo ' '
      exit 1
    fi
  fi

  cd $temp_dir
  if [ "$source" != 'yes' ]
  then
    rm -f *.f *.F *.f90 *.F90
  fi
  if [ "$list" != 'yes' ]
  then
    rm -f *.l
  fi
  cd $main_dir/ftn

# 1.e Prepare makefile - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  make_make='y'
  if test -f $switch_file_old
  then
    if test -f $main_dir/ftn/makefile && \
       test -z "`diff $switch_file $switch_file_old`"
    then
      make_make='n'
    fi
  fi

  if test "$make_make" = 'y'
  then
    echo 'Making makefile ...'
    if $main_dir/bin/make_makefile.sh
    then
      if [ "$flag_SHRD" -gt '0' ]
      then
        if [ "$flag_OMPX" -gt '0' ]
        then
          cp $switch_file ${switch_file_old}_OMP
          cp $makefile ${makefile}_OMP
        else
          cp $switch_file ${switch_file_old}_SEQ
          cp $makefile ${makefile}_SEQ
        fi
      else
        if [ "$flag_OMPH" -gt '0' ]
        then
          cp $switch_file ${switch_file_old}_HYB
          cp $makefile ${makefile}_HYB
        else
          cp $switch_file ${switch_file_old}_MPI
          cp $makefile ${makefile}_MPI
        fi
      fi
    else
      exit 1
    fi
  fi
  echo ' '

# 1.f Export paths - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

  aPb="$main_dir/bin"     # path containing shell scripts
  aPo="$main_dir/obj"     # path containing .o files
  aPm="$main_dir/mod"     # path containing .mod files
  aPe="$main_dir/exe"     # path containing executables

  export aPb aPo aPm aPe

# --------------------------------------------------------------------------- #
# 2. Run make for all requests                                                #
# --------------------------------------------------------------------------- #
# 2.a Loop over all requests

  for prog in $progs
  do
    echo "Processing $prog"
    echo "---------------------"

# 2.b Check input  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

    OK='n'
    for check in $all_programs
    do
      if test "$prog" = "$check"
      then
        OK='y'
      fi
    done
    if test "$OK" = 'n'
    then
      echo "   *** Program name not recognized ***"
      echo ' '
      exit 1

# 2.c Run make - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

    else

      netcdf_compile=no
      if [ -n "`echo $cdf_programs | grep $prog`" ]
      then
        netcdf_compile=yes
      fi
      export netcdf_compile

      mpi_mod=no
      if [ -n "`grep MPI $switch_file`" ]
      then
        mpi_mod=yes
      fi
      export mpi_mod

      omp_mod=no
      if [ -n "`grep OMP $switch_file`" ]
      then
        omp_mod=yes
      fi
      export omp_mod

      oasis_mod=no
      if [ -n "`grep OASIS $switch_file`" ] 
      then
        export oasis_mod='yes'
      fi
      export oasis_mod

      pdlib_mod=no
      esmfpdlib='' 
      if [ -n "`grep PDLIB $switch_file`" ]
      then
        export pdlib_mod='yes'
        esmfpdlib="$METIS_PATH/lib/libparmetis.a $METIS_PATH/lib/libmetis.a"
      fi
      export pdlib_mod



      # if esmf is included in program name, then the compile
      # requires DIST switch and the ESMFMKFILE is
      # processed to get required ESMF compile options
      if [ -n "`echo $prog | grep esmf 2>/dev/null`" ]
      then
        if [ -z "`grep DIST $switch_file`" ] 
        then
          echo ' '
          echo "*** DIST switch must be set when compiling with ESMF ***"
          echo ' '
          exit 1
        fi
        ESMF_F90COMPILEPATHS=
        if [ $ESMFMKFILE ]
        then
          if [ ! -r $ESMFMKFILE ]
          then
            echo ' '
            echo "*** ESMFMKFILE does not exist or is not readable: $ESMFMKFILE ***"
            echo ' '
            exit 1
          fi
          ESMF_F90COMPILEPATHS=`cat $ESMFMKFILE | grep '^ *ESMF_F90COMPILEPATHS' | sed 's/^ *ESMF_F90COMPILEPATHS *=//g'`
        else
          echo ' '
          echo "*** ESMFMKFILE must be defined when compiling with ESMF ***"
          echo ' '
          exit 1
        fi
      fi
      export ESMF_F90COMPILEPATHS

      # if esmf is included in program name, then
      # the target is compile and create archive
      if [ -n "`echo $prog | grep esmf 2>/dev/null`" ]
      then
        target="$prog"
      # if program name is libww3, then
      # the target is compile and create archive
      elif [ "$prog" = "libww3" ]
      then
        target="$prog"
      elif [ "$prog" = "libww3.so" ]
      then
        target="$prog"
      else
        target="$aPe/$prog"
      fi

      if [ ! -f $exec_type_file ] ; then
          touch $exec_type_file ; fi

      if [ `grep $prog $exec_type_file | wc -l | awk '{ print $1}'` != '0' ]
      then
        exec_type=`grep $prog $exec_type_file | tail -1 | awk '{ print $2}'`
      fi
      if [ "$exec_type" != "$pres_type" ] ; then
          rm -f $main_dir/exe/$prog  ; fi

      cp $exec_type_file tempfile
      sed -n "/$prog/!p" tempfile > $exec_type_file
      rm -f tempfile

      path_m=$main_dir/mod
      export path_m
      # WW3_PARCOMPN is an environment variable to set the parallel make tasks
      # it defaults to 4
      if make -j ${WW3_PARCOMPN:-4} -f makefile $target
      then
        echo ' '
      else
        exit 1
      fi

      echo "$prog $pres_type" >> $exec_type_file

      # if esmf is included in program name, then create $main_dir/nuopc.mk
      if [ -n "`echo $prog | grep esmf 2>/dev/null`" ]
      then
        mkfile=$main_dir/nuopc.mk
        if [ -n "`grep OMP $switch_file`" ]
        then
          mod_dir=$main_dir/mod_HYB
          obj_dir=$main_dir/obj_HYB
        else 
          mod_dir=$main_dir/mod_MPI
          obj_dir=$main_dir/obj_MPI
        fi 
        rm -f $mkfile
        touch $mkfile
        echo "#-----------------------------------------------"      >> $mkfile
        echo "# NUOPC/ESMF self-describing build dependency"         >> $mkfile
        echo "# makefile fragment for Wavewatch III"                 >> $mkfile
        echo "#-----------------------------------------------"      >> $mkfile
        echo "# component module name"                               >> $mkfile
        echo "ESMF_DEP_FRONT := WMESMFMD"                            >> $mkfile
        echo "# component module path"                               >> $mkfile
        echo "ESMF_DEP_INCPATH := $mod_dir"                          >> $mkfile
        echo "# component module objects"                            >> $mkfile
        echo "ESMF_DEP_CMPL_OBJS := $obj_dir/lib$prog.a(wmesmfmd.o)" >> $mkfile
        echo "# component object/archive list"                       >> $mkfile
        echo "ESMF_DEP_LINK_OBJS := $obj_dir/lib$prog.a $esmfpdlib"  >> $mkfile
      fi

    fi

  done

# 2.d copy comp and link 

  cp  $main_dir/bin/comp $main_dir/exe/
  cp  $main_dir/bin/link $main_dir/exe/
 
# --------------------------------------------------------------------------- #
# 3. End of program ID.                                                       #
# --------------------------------------------------------------------------- #

  echo ' '
  echo '                       **********************'
  echo '                     *** end of compilation ***'
  echo '                       **********************'
  echo ' '

# End of w3_make ------------------------------------------------------------ #