#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#
# Coupler set up prior to execution
#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#=#

# A unique tag for temporary file names etc
cpl_stamp=`date "+%j%H%M%S"$$`

# cpl_this_host will simply be the output from uname
cpl_this_host=`uname -n|awk -F\. '{print \$1}' -`

# cpl_bail is a simple error exit routine
cpl_error_out="${JHOME:-$HOME}/.queue/error_cpl_prelude_${runid}_${this_host}_$stamp"
[ -z "$cpl_error_out" ] || rm -f $cpl_error_out
cpl_bail_prefix="coupler prelude"
cpl_bail(){
  echo `date`" $this_host $runid --- ${cpl_bail_prefix}: $*"
  echo `date`" $this_host $runid --- ${cpl_bail_prefix}: $*" >>$cpl_error_out
  [ -n "$model" ] && echo `date`" $this_host $runid --- ${cpl_bail_prefix}: $*" >>haltit
  exit 2
}

ToF(){
  #   usage: ToF var_name
  # purpose: Possibly reset the value of var_name to "0" (false) or "1" (true)
  #          If var_name is null or has a value of "off" or "no" then reset to "0"
  #          If var_name has a value of "on" or "yes" then reset to "1"
  #          Otherwise return with var_name unchanged
  set +x
  [ -z "$1" ] && cpl_bail "ToF requires a variable name as an argument"
  eval ToF_var\=\$$1
  XXX=`echo $ToF_var|sed 's/ //g'`
  eval ToF_var\=$XXX
  if [ -n "$ToF_var" ]; then
    if   [ "$ToF_var" = 'on'  ]; then eval ToF_var\=1
    elif [ "$ToF_var" = 'off' ]; then eval ToF_var\=0
    elif [ "$ToF_var" = 'yes' ]; then eval ToF_var\=1
    elif [ "$ToF_var" = 'no'  ]; then eval ToF_var\=0
    else
      eval ToF_var\=\$$1
    fi
  else
    eval ToF_var\=0
  fi
  eval $1=$ToF_var
  set -x
}

# cpl_mod_nl is used to change namelist values for the current job
cpl_mod_nl(){
  # Modify a text file containing namelists
  # Each variable definition in this input namelist file must be on a line by itself
  # and be the of the form var =.* which will be replaced with var = value
  #
  # Usage: cpl_mod_nl namelist_file_in var1 [var2 ...]
  #   namelist_file_in  ...is an existing text file containing the namelists
  #   var1 var2 ...     ...names of variables to be changed
  #
  set +x
  [ -z "$1" ] && cpl_bail "cpl_mod_nl requires a namelist file as the first arg"
  [ -z "$2" ] && cpl_bail "cpl_mod_nl requires at least 1 variable name on the command line"
  nlfile=$1
  [ ! -s $nlfile ] && cpl_bail "cpl_mod_nl input namelist file --> $nlfile <-- is missing or empty"
  shift

  # Create a backup copy of the input namelist file, overwriting any existing backup
  cp -f $nlfile ${nlfile}.bak

  # Write a sed program to make the requested substitutions
  sprog=cpl_mod_nl_cmd
  rm -f $sprog
  touch $sprog
  for var in $*; do
    ischar=0
    # Any variable name beginning with _char_ is assumed to contain a string value
    # The leading _char_ prefix is removed from this name before further processing
    if [ x`echo $var|sed -n '/^ *_char_/p'` != x ]; then
      ischar=1
      var=`echo $var|sed 's/^_char_//'`
    fi
    eval val=\$$var
    if [ -z "$val" ]; then
      # If this variable is not defined then issue a warning and continue
      echo "cpl_mod_nl: $var is not defined"
      continue
    fi
    if [ $ischar -eq 1 ]; then
      # This is a character variable that needs to be quoted
      vsub='s/^ *'$var' *=.*/'"  ${var} = \"$val\""'/'
    else
      vsub='s/^ *'$var' *=.*/'"  ${var} = $val"'/'
    fi
    # Add this command to the file
    # Note, the quotes are required to preserve white space
    echo "$vsub" >> $sprog

    tstrng=`grep '^ *'$var' *=' $nlfile | sed 's/ *//g'`
    if [ "x$tstrng" = "x" ]; then
      # This variable does not appear in the namelist file
      # Insert a line with a definition for var that will get modified below
      sed '1 a\
  '$var' = 0' $nlfile > cpl_add_nl_var_$$
      mv cpl_add_nl_var_$$ $nlfile
      echo "${nlfile}: ADDED $var = $val"
    else
      # Echo the changes to stdout (useful for debugging runs)
      echo "${nlfile}: RESET $var = $val"
    fi
  done

  # Make the substitutions in situ, overwriting the input file
  sed -f $sprog $nlfile > cpl_mod_nl_tmp_$$
  mv cpl_mod_nl_tmp_$$ $nlfile
  rm $sprog
  set -x
}

cpl_acc_chksum() {
  # Attempt to access a file and add a checksum for that file to a local log file
  [ -z "$1" ] && cpl_bail "--> cpl_acc_chksum <-- requires a local file name as the first arg"
  local_file=$1
  [ -z "$2" ] && cpl_bail "--> cpl_acc_chksum $1 <-- requires a remote file name as the second arg"
  remote_file=$2
  shift 2
  access $local_file $remote_file $* ||
    cpl_bail "--> cpl_acc_chksum $local_file $remote_file $* <-- Unable to locate $remote_file"

  [ -f "$local_file" ] &&  sha1sum $local_file >> cpl_access_log || :
  [ -d "$local_file" ] &&  sha1sum ${local_file}/* >> cpl_access_log || :
}

echo " "
echo "#################### Start coupler pre-processing #################"

# Identify the location of the coupler git repository and the commit within
# that repository that is associated with the current run
cancpl_repo=${cancpl_repo:=$CCRNSRC/coupler_dir/coupler.git}
cancpl_ver=${cancpl_ver:=''}
if [ -n "$cancpl_ver" ]; then
  curr_cancpl_ver=$cancpl_ver
  # Dereference this commit and ensure we have a full sha1 hash
  cancpl_ver=`(cd $cancpl_repo; git rev-parse $cancpl_ver)` ||
      cpl_bail "Unable to validate runtime cancpl_ver=$curr_cancpl_ver"
fi
export cancpl_ver cancpl_repo

echo "### CanCPL runtime: cancpl_repo   = $cancpl_repo"
echo "### CanCPL runtime: cancpl_ver    = $cancpl_ver"

if [ -z "\$cpl_cancpl_repo" -o -z "\$cancpl_ver" ]; then
  echo "cancpl_repo and cancpl_ver must be defined when using cpl_prelude"
  exit 2
fi

# Touch cpl_access_log so that it will exist even if it never gets apppended to
rm -f cpl_access_log
touch cpl_access_log

if [ -n "$model" -a -n "$start" ]; then
  # If model and start are defined then we are likely running from gcmjcl

  # Extract year and month from the file name
  # The variable model is a common prefix for file names
  # This assumes that model has the form *_YYYY_mMM_ or *_YYYY_mMM
  # if not then cpl_model_mon and cpl_model_year will be empty
  cpl_model_mon=`echo $model |awk -F_ '{if(length($NF)>0){i=NF}else{i=NF-1};
                                        if(i>0){if($i~/^[mM][0-9][0-9]$/){print substr($i,2)}}}' -`
  cpl_model_year=`echo $model|awk -F_ '{if(length($NF)>0){i=NF}else{i=NF-1}; i=i-1;
                                        if(i>0){if($i~/^[0-9][0-9]*$/){print $i}}}' -`
  if [ -n "$cpl_model_mon" -a -n "$cpl_model_year" ]; then
    # If not empty then both cpl_model_mon and cpl_model_year will be integers and
    # most likely (but not a necessarily) they will be the current model year/month
    # Use these values to determine the previous year/month and define a modelrs string
    cpl_model_part=`echo $model|awk -F_ '{if(length($NF)>0){i=NF}else{i=NF-1}; i=i-2;
                                if(i>0){if(i>0){for(n=1; n<=i; n++){s=s $n "_"}; print s}}}' -`
    cpl_modelrs_part=`echo $cpl_model_year $cpl_model_mon|\
                      awk '{if($2<1||$2>12){exit};
                            if($2>1){s=sprintf("%3.3d_m%2.2d_",$1,$2-1)}
                            else{s=sprintf("%3.3d_m12_",$1-1)};
                            print s}' -`
    [ -z "$cpl_modelrs_part" ] &&
        bail "Invalid date: cpl_model_year = $cpl_model_year   cpl_model_mon = $cpl_model_mon"
    cpl_modelrs=${cpl_model_part}$cpl_modelrs_part
  else
    cpl_modelrs_mon=''
    cpl_modelrs_year=''
    cpl_modelrs=''
    cpl_bail "Unable to determine year/month from model = $model"
  fi

  echo "===== cpl_prelude:  start = $start  model = $model  cpl_modelrs = $cpl_modelrs"
  echo "===== cpl_prelude:  cpl_model_year = $cpl_model_year  cpl_model_mon = $cpl_model_mon"

  # Define boolean flags first_month_in_curr_job and last_month_in_curr_job
  # that will be used to determine if the current invocation is at the
  # beginning or end of a multi month job submission
  # This is only meaningful when running from gcmjcl
  if [ -n "$month_counter" -a -n "$months" ]; then
    # months and month_counter are defined
    # These variables are define when running in gcmjcl mode
    # Assume month_counter counts down from the value of months to 1
    if [ $months -gt 1 ]; then
      if [ $month_counter -eq $months ]; then
        # This should be the first month of the current submission job
        first_month_in_curr_job=1
        last_month_in_curr_job=0
      elif [ $month_counter -eq 1 ]; then
        # This should be the last month of the current submission job
        first_month_in_curr_job=0
        last_month_in_curr_job=1
      else
        first_month_in_curr_job=0
        last_month_in_curr_job=0
      fi
    else
      # months must be 1 otherwise
      first_month_in_curr_job=1
      last_month_in_curr_job=1
    fi
  else
    # months and month_counter are not defined. Set first/last to False
    first_month_in_curr_job=0
    last_month_in_curr_job=0
  fi
  [ $first_month_in_curr_job -eq 1 ] &&
    echo "===== cpl_prelude: First month in current job  year = $cpl_model_year  month = $cpl_model_mon"
  [ $last_month_in_curr_job -eq 1 ]  &&
    echo "===== cpl_prelude:  Last month in current job  year = $cpl_model_year  month = $cpl_model_mon"

  # Look for a coupler restart for the current month
  if [ $first_month_in_curr_job -eq 1 ]; then
    cpl_cplrs_name=${start}cplrs.tar
  else
    cpl_cplrs_name=${cpl_modelrs}cplrs.tar
  fi
  found_cplrs=0
  
  
  # require_cplrs = on  means abort when the coupler restart does not exist
  # require_cplrs = off means do not abort when the coupler restart does not exist
  require_cplrs=${require_cplrs:=on}
  ToF require_cplrs

  # A coupler restart exists in the file name database
  rm -f cplrs_cpl_main cplrs_cpl_restart.nc
  rm -f CPL_RESTART_ARC

  # Try to access the restart directory. If that fails, look for the tar file.
  access CPL_RESTART_ARC `basename $cpl_cplrs_name .tar` nocp=off || access CPL_RESTART_ARC $cpl_cplrs_name
 
  if ! tar tf CPL_RESTART_ARC &> /dev/null; then
     # This is the directory. Checksum all files inside it.
     sha1sum CPL_RESTART_ARC/* >> cpl_access_log
     mv CPL_RESTART_ARC/* . || bail "Cannot get files from restart directory"
  else
     # This is the tar file. Checksum it.
     sha1sum CPL_RESTART_ARC >> cpl_access_log
     # Ensure that we can overwrite existing files with files from the restart
     tar tf CPL_RESTART_ARC | grep -v '\.nc$' | xargs -I'{}' chmod u+rw {} || :
     tar xf CPL_RESTART_ARC || bail "Cannot extract files from $cpl_cplrs_name"
  fi

  release CPL_RESTART_ARC
  chmod 644 cplrs_*

  release cpl_restart.nc
  [ -s cplrs_cpl_restart.nc ] && mv cplrs_cpl_restart.nc cpl_restart.nc

  # If there was no coupler restart file found then conditionally abort
  if [ $require_cplrs -eq 1 ]; then
    [ -s cpl_restart.nc ] || cpl_bail "cplrs_cpl_restart.nc is missing"
  fi

  # Commenting this and replacing with the logic below, b/c DB queries are slow.

  # Look for a coupler executable in the filename database named ${start}cpl.exe
  # If this file exists then assume it was created in gcmjcl by the current submission job
  #found_cplexe=0
  #fdb exists ${start}cpl.exe && found_cplexe=1
  release cpl_main

  # Try to access (na) the executable. If this fails, then use the one out of the rs.
  access cpl_main ${start}cpl.exe nocp=off na

  if [ -s cpl_main ]; then
    sha1sum cpl_main >> cpl_access_log
    # Use the executable that was recently compiled by this submission job
    #cpl_acc_chksum cpl_main ${start}cpl.exe nocp=off
    #[ -s cpl_main ] || cpl_bail "${start}cpl.exe is missing ..access failed"
  else
    # Use the executable found in the coupler restart archive
    [ -s cplrs_cpl_main ] && mv cplrs_cpl_main cpl_main
    [ -s cpl_main ] || cpl_bail "The coupler executable was not found in the restart $cpl_cplrs_name"
  fi
  chmod 755 cpl_main

  read_agcm_grid_area_file=0
  if [ $read_agcm_grid_area_file -eq 1 ]; then
    # Extract an AGCM grid area file from the coupler repo
    gitrip $cancpl_ver data/areacella_fx_CanESM2_historical_r0i0p0.nc repo=$cancpl_repo
    [ -s areacella_fx_CanESM2_historical_r0i0p0.nc ] &&
        agcm_grid_area_file=${agcm_grid_area_file:=areacella_fx_CanESM2_historical_r0i0p0.nc}
  fi

  read_nemo_mesh_mask_file=0
  if [ $read_nemo_mesh_mask_file -eq 1 ]; then
    if [ -z "$nemo_mesh_mask_file" ]; then
      # If nemo_mesh_mask_file is not defined in the current environment then look on disk
      if [ -s rs_mesh_mask.nc ]; then
        # If a file named rs_mesh_mask.nc is present then assume it came from the NEMO restart
        # that was unpacked in the current execution directory
        nemo_mesh_mask_file=rs_mesh_mask.nc
      fi
    fi
  fi

  # Modify coupler namelist entries
  env_model=$model
  env_start=$start
  env_months=$months
  ocn_grid_desc=${nemo_mesh_mask_file:-''}
  if [ $found_cplrs -eq 0 -a $require_cplrs -eq 0 ]; then
    cpl_use_initial_conditions=.true.
  else
    cpl_use_initial_conditions=.false.
  fi
  cpl_zero_runoff=${cpl_zero_runoff:=off}
  ToF cpl_zero_runoff
  if [ $cpl_zero_runoff -eq 1 ]; then
    zero_runoff_sent_to_ocean=.true.
  fi
  cpl_mod_nl nl_coupler_par _char_env_start _char_env_model env_months \
             _char_agcm_grid_area_file _char_nemo_mesh_mask_file _char_ocn_grid_desc \
             cpl_use_initial_conditions zero_runoff_sent_to_ocean _char_windstress_remap \
             landfrac_bug

  echo "Modified coupler namelist:"
  cat nl_coupler_par

  # Create a file containing a snapshot of the shell environment
  # This will be saved in the restart archive after the current run completes
  set > coupler_env

###DBG
## [ -e cplrs_ocn_grid.nc ] ||
## access cplrs_ocn_grid.nc cplrs_cpl_ocn_grid-testing.nc
## [ -e cplrs_atm_grid.nc ] ||
## access cplrs_atm_grid.nc cplrs_cpl_atm_grid-testing.nc
## [ -e grid_desc_orca1_coordinates_with_caspian.nc ] ||
## access grid_desc_orca1_coordinates_with_caspian.nc grid_desc_orca1_coordinates_with_caspian.nc
## [ -e grid_desc_orca1_nemo_3.4_orca1_coordinates_ukorca1_with_mask.nc ] ||
## access grid_desc_orca1_nemo_3.4_orca1_coordinates_ukorca1_with_mask.nc grid_desc_orca1_nemo_3.4_orca1_coordinates_ukorca1_with_mask.nc
## [ -e grid_desc_t63_o_gcm3.5_landmask_128x64v5.nc ] ||
## access grid_desc_t63_o_gcm3.5_landmask_128x64v5.nc grid_desc_t63_o_gcm3.5_landmask_128x64v5.nc

else
  cpl_bail "model must be defined"
fi  # end of if model block

echo " "
echo "#################### Stop coupler pre-processing #################"
