#!/bin/bash
# --------------------------------------------------------------------------- #
# ad3   : Run fortran preprocessor w3adc of WAVEWATCH III on for a single     #
#         source code file. Switches are set in the file 'switch', which      #
#         has to be in the "bin" directory. After the preprocessing the code  #
#         is compiled using the script comp in  the "bin" directory.          #
#                                                                             #
# use   : ad3 basename [itest [icomp]]                                        #
#            basename: name of source code file without the '.ftn' extension. #
#                      file with .f or .f90 extension is not preprocessed.    #
#                      file with .c extension uses standard cc compiler.      #
#            itest   : test output switch.                                    #
#                       not defind or 0 : no test output                      #
#                       all other       : verbose mode                        #
#            icomp   : compiling switch.                                      #
#                       not defind or 0 : compile.                            #
#                       all other       : do not compile.                     #
#                                                                             #
# error codes :  1 : input error                                              #
#                2 : no environment file $ww3_env found.                      #
#                3 : error in creating scratch directory.                     #
#                4 : w3adc error.                                             #
#                5 : compiler error.                                          #
#                                                                             #
# programs used :                                                             #
#       w3adc : executable of proprocessing program.                          #
#       comp  : compiler script.                                              #
#                                                                             #
# remarks :                                                                   #
#                                                                             #
#  - Do not use itest in w3adc to avoid spurious error messages.              #
#  - The main WAVEWATCH directory ($main_dir) is obtained from the setup      #
#    file $ww3_env, as is the scratch directory ($temp_dir). The following    #
#    directories are used :                                                   #
#       $main_dir/ftn : Raw FORTRAN file ($basename.ftn). If extension is     #
#                       not .ftn, w3adc will be skipped. if the extension is  # 
#                       .c, then the simple cc compiler is used. The latter   #
#                       is now used for profiling code only.                  #
#       $main_dir/bin : File with preprocessor switches 'switch', and         #
#                       compiler script 'comp'.                               #
#       $main_dir/obj : Final object modules ($basename.o).                   #
#       $main_dir/mod : Final modules (*.mod).                                #
#                                                                             #
#    The following temporary files (in $temp_dir) are used and are removed    #
#    only if the corresponding step of ad3 is ompleted successfully :         #
#       w3adc.inp     : input file for w3adc.                                 #
#       w3adc.out     : output file for w3adc.                                #
#       w3adc.err     : eror file for w3adc.                                  #
#       comp.out      : input file for comp.                                  #
#       comp.err      : eror file for comp.                                   #
#       comp.stat     : status file of compiler, containing number of errors  #
#                       and number of warnings (generated by comp).           #
#                                                                             #
#  - Check the compress variable in section 1.b to print or suppress the_     #
#    documentation in the clean FORTRAN files.                                #
#                                                                             #
#                                                      Hendrik L. Tolman      #
#                                                      May 2009               #
#                                                      January 2014           #
#                                                                             #
#    Copyright 2009-2014 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 Check and process input

  if [ "$#" -gt '3' ] || [ "$#" -lt 1 ]
  then
    echo "usage: ad3 basename [itest [icomp]]" 1>&2 ; exit 1
  fi

  name=$1
  if [ "$#" -ge '2' ]
  then
    itst=$2
  else
    itst='0'
  fi
  if [ "$#" = '3' ]
  then
    icmp=$3
  else
    icmp='0'
  fi

# 1.b Internal variables - - - - - - - - - - - - - - - - - - - - - - - - - - -

  switch="switch"          # file containing switches
  compress=0               # source code compression par in w3adc
                           # if not 0, documentaion removed from .f90 file

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

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


# 1.d Set up paths etc.  - - - - - - - - - - - - - - - - - - - - - - - - - - -

  path_b="$main_dir/bin"
  path_w="$( cd $temp_dir && pwd )"
  path_i="$main_dir/ftn"
  path_o="$main_dir/obj"
  path_m="$main_dir/mod"
  path_e="$main_dir/exe"
  if [ -n "`echo $name | grep scrip_ 2>/dev/null`" ]
  then
    path_i="$path_i/SCRIP"
  fi
  if [ ${name:0:3} = 'yow' ]
  then
    path_i="$path_i/PDLIB"
  fi

  if [ -z "$(env | grep switch_file)" ]
  then
    switch_file=$main_dir/bin/$switch
  fi

  sw_str=$(cat $switch_file)

  if [ ! -d $path_w ]
  then
    if ! `mkdir $path_w`
    then
      echo '      *** w3adc error ***'
      echo "          Cannot create $path_w"
      exit 3
    fi
  fi

# 1.e Test necessity of running w3adc - - - - - - - - - - - - - - - - - - - -

  if [ -f $path_i/$name.ftn ]
  then
    w3adc='yes'
    idstr=
  else
    w3adc='no'
    idstr='[no w3adc]'
  fi

# 1.f Set appropriate Fortran file suffix  - - - - - - - - - - - - - - - - - -

  suffixes="ftn f F f90 F90 c"
  fexti=none
  for s in $suffixes
  do
    if [ -f $path_i/$name.$s ]
    then
      fexti=$s
      break
    fi
  done
  if [ "$fexti" = 'none' ]
  then
    echo '      *** ad3 error ***'
    echo "          Source file $path_i/$name.* not found"
    echo "          Source file suffixes checked: $suffixes"
    exit 2
  fi
  if [ "$fexti" = 'ftn' ]
  then
    fexto=F90
  else
    fexto=$fexti
  fi
  fext=$fexto

# 1.g Output - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  echo "ad3 : processing $name $idstr"

  if [ "$itst" != '0' ]
  then
    echo ' ' ; echo 'Test output ad3 ' ; echo '----------------'
    echo "  bin directory    : $path_b "
    echo "  work directory   : $path_w "
    echo "  input directory  : $path_i "
    echo "  object directory : $path_o "
    echo "  module directory : $path_m "
    echo "  executable dir.  : $path_e "
    echo "  switches file    : $switch " ; echo ' '
    echo "  switches         : $sw_str"
    echo ' '
  fi

# 1.h Final preparations - - - - - - - - - - - - - - - - - - - - - - - - - - -

  cd $path_w
  rm -f $name.$fext
  rm -f $name.l
  ln -s $main_dir/bin/w3list . 2> /dev/null

# --------------------------------------------------------------------------- #
# 2. Run w3adc                                                                #
# --------------------------------------------------------------------------- #
# 2.a Make input file

  if [ "$w3adc" = 'yes' ]
  then

    echo "0 $compress"                             > w3adc.inp.$name
    echo "'$path_i/$name.ftn' '$name.$fext'"      >> w3adc.inp.$name
    echo "'$sw_str'"                              >> w3adc.inp.$name

# 2.b Add NCEP/NCO docmentation  - - - - - - - - - - - - - - - - - - - - - - -

# Obsolete feature, removed

# 2.b Run w3adc  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

    if [ "$itst" != '0' ]
    then
      echo '-- input file w3adc.inp -------------------------------------------'
      cat w3adc.inp.$name
      echo '-- end of file ----------------------------------------------------'
    fi

    $path_b/w3adc < w3adc.inp.$name > w3adc.out.$name 2> w3adc.err.$name

# 2.c Test the output of w3adc - - - - - - - - - - - - - - - - - - - - - - - -

    ad3_tst="`grep ERROR w3adc.out.$name`"
    if [ -n "$ad3_tst" ]
    then
      echo '      *** w3adc error ***'
      echo "     $ad3_tst" ; exit 4
    fi

    if [ ! -f $name.$fext ]
    then
      echo '      *** w3adc error ***'
      echo "          file $name.$fext not found (1)."
      cat w3adc.out.$name ; cat w3adc.err.$name  ; exit 4
    fi

    if [ "`wc -l $name.$fext | awk '{ print $1}'`" -lt '2'  ]
    then
      echo '      *** w3adc error ***'
      echo "          file $name.$fext not found (2)."
      cat w3adc.out.$name ; cat w3adc.err.$name  ; exit 4
    fi

    if [ "$itst" != '0' ]
    then
      cat w3adc.out.$name
    fi

# 2.d Clean up - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    rm -f w3adc.*.$name

# 2.e Add switches in w3initmd - - - - - - - - - - - - - - - - - - - - - -

    if [ "$name" = "w3initmd" ]
    then
      sw_1=''
      cp $path_w/w3initmd.$fext  $path_w/w3initmd.ft1
      for line in 1 2 3
        do
          sw_1=`echo $sw_str  | fold -w100 | sed -n "${line}p"`
          sw_old="PUT_SW$line"
          # echo $line  $sw_1 $sw_old
          sed -e "s/$sw_old/$sw_1/"  $path_w/w3initmd.ft1 > $path_w/w3initmd.ft2
          mv  $path_w/w3initmd.ft2 $path_w/w3initmd.ft1
        done
      mv $path_w/w3initmd.ft1 $path_w/w3initmd.$fext
      echo "'$path_w/$name.fts' '$name.$fext'"        >> w3adc.inp
    fi

  else

# 2.f No w3adc, just copy file - - - - - - - - - - - - - - - - - - - - - - - -

    cp $path_i/$name.$fext .

  fi

  if [ ! -f $name.$fext ]
  then
    echo '      *** adc error ***'
    echo "          file $name.$fext not found."
    exit 5
  fi

# 2.g Stop if requested  - - - - - - - - - - - - - - - - - - - - - - - - - - -

  if [ "$icmp" != '0' ]
  then
    rm -f w3list
    exit 0
  fi

  rm -f $path_o/$name.o
  ## Chris B: Dont delete *.mod - could clobber files in parallel make
  ## Need to delete specific mod file that could be upper/lower/mixed case!
#  rm -f *.mod ## too indiscriminate

  ## Using find -iname most succinct, but maybe not all version of find have
  ## the -iname option? 
#  find . -iname "${name}.mod" -delete  # not all versions of find have -iname?

  # Fall back on grep -i 
  mods=`ls *.mod 2> /dev/null | grep -i "${name}.mod"`
  if [ -n ${mods} ]; then
    rm -f ${mods}
  fi 

# --------------------------------------------------------------------------- #
# 3. Compile source code f / f90                                              #
# --------------------------------------------------------------------------- #

export fext    # for use by comp
export path_m  # for use by comp
export path_i  # for use by comp

if [ ! -f $name.c ]
then

# 3.a Run compile program

  error='0'

  $path_b/comp $name > comp.out.$name 2> comp.err.$name
  OK="$?"


# 3.b Error escape location  - - - - - - - - - - - - - - - - - - - - - - - - -
  if [ "$OK" != '0' ]
  then
    echo '      *** compile error ***'
    echo '          error in comp'
    echo '--- comp output -------------------------------------------------'
    cat comp.out.$name
    echo '--- comp error output -------------------------------------------'
    cat comp.err.$name
    echo '-----------------------------------------------------------------'
    error='6'
    rm -f comp.stat.$name
  fi
  rm -f comp.out.$name
  rm -f comp.err.$name


# 3.c Check comp.stat  - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    if [ -f comp.stat.$name ]
    then
      nr_err="$(grep -i error comp.stat.$name | awk '{ print $2 }')"
      nr_war="$(grep -i warning comp.stat.$name | awk '{ print $2 }')"
      rm -f comp.stat.$name
      if [ "$nr_err" != '0' ]
      then
        echo "      $nr_err errors found, see $path_w/$name.err"
        list='yes'
      else
        if [ "$nr_war" != '0' ]
        then
          echo "      $nr_war warnings found, see $path_w/$name.out"
          list='yes'
        fi
      fi
    else
      echo '      *** compile error ***'
      echo "          file comp.stat.$name not found"
      error='5'
      nr_err='1'
      rm -f $name.o
    fi

# 3.d process object file  - - - - - - - - - - - - - - - - - - - - - - - - - -

    if [ "$nr_err" != '0' ] && [ ! -f $name.o ] && [ "$error" = '0' ]
    then
      echo '      *** compile error ***'
      echo "          file $name.o not found"
      error='5'
    fi

    if [ "$nr_err" != '0' ]
    then
      rm -f $name.o
    else
      mv $name.o $path_o/.
      ## ChrisB: Don't move all module files...could break parallel make.
      ## Just target specific module file (could be mixed case filename
      ## depending on compiler - use case insensitive find):
#      mods=`ls *.mod 2> /dev/null` 

      ## Using find -iname most succinct, but maybe not all version of find have
      ## the -iname option? 
#      mods=`find . -iname "${name}.mod"` # not all versions of find have -iname?

      # Fall back on grep -i 
      mods=`ls *.mod 2> /dev/null | grep -i "${name}.mod"`
      if [ -n "$mods" ]
      then
        for mod in $mods
        do
          mv $mod $path_m/.
          echo "         $mod"
        done
      fi
    fi

# Note: the need for moving the .mod file and therefore the printing of the
#       $mod depend on the compiler behavior.


# 3.e process output files - - - - - - - - - - - - - - - - - - - - - - - - - -

  rm -f $name.o
  rm -f w3list

  if [ "$source" != 'yes' ]
  then
    rm -f $name.f $name.$fext
  fi
  if [ "$list" != 'yes' ] && [ "$error" = '0' ]
  then
    rm -f $name.l
  fi

  exit $error

# --------------------------------------------------------------------------- #
# 4. Compile source code c                                                    #
# --------------------------------------------------------------------------- #
# For now only diagnostics / profiling codes compiled with simple cc compiler

else

# 4.a Compile

  cc -c $name.c

# 4.b Save object file

  if [ -f $name.o ]
  then
    mv $name.o $path_o/.
  else
    echo '      *** compile error ***'
    echo "          file $name.o not found"
    error='6'
  fi

fi

# End of ad3 ---------------------------------------------------------------- #
