#!/bin/bash

# This file is part of IKR SimTree
# (C) 2009-2014 University of Stuttgart, IKR

# Hook file template which calls the simulation binary with the appropriate command line parameters

# %%HOOK_FILE_SOURCE_COMMENT%%

### Parameter parts

# File lists, -b, -e and -i Option
PARTIAL_RESULT_FILENAMES="%%PARTIAL_RESULT_FILENAMES%%"
EXPORT_RESULT_FILENAMES="%%EXPORT_RESULT_FILENAMES%%"
IMPORTED_RESULT_FILENAMES="%%IMPORTED_RESULT_FILENAMES%%"

# Number of batches, -n Option
NUM_BATCHES="%%NUM_BATCHES%%"

# Name of simulation parameter file, -p Option
SIMULATION_PARAMETER_FILENAME="%%SIMULATION_PARAMETER_FILENAME%%"

# Name of parser logfile, -g Option
PARSER_LOG_FILENAME="%%PARSER_LOG_FILENAME%%"

# Name of filter file, -f Option
FILTER_FILENAME="%%FILTER_FILENAME%%"

# Name of final result file, -l Option
FINAL_RESULT_FILENAME="%%FINAL_RESULT_FILENAME%%"

# Seed value, -s Option
SEED_VALUE="%%SEED_VALUE%%"

# Name of simulation binary
SIMULATION_PROGRAM_CALL="%%SIMULATION_PROGRAM_CALL%%"

# Nice level
CALLSIM_NICE_LEVEL="%%CALLSIM_NICE_LEVEL%%"

### Boolean, Y or N

# Whether the result files should be compressed by this script (SimTree) 
COMPRESS_RESULT_FILES_BY_SIMTREE="%%COMPRESS_RESULT_FILES_BY_SIMTREE%%"

# Whether the result files should be compressed by the SimLib (simulation binary), requires SimLib 2.7.1 or later
COMPRESS_RESULT_FILES_BY_SIMLIB="%%COMPRESS_RESULT_FILES_BY_SIMLIB%%"

# Whether export result files are deleted after a success collect run
DELETE_EXPORT_RESULT_FILES_AFTER_COLLECT="%%DELETE_EXPORT_RESULT_FILES_AFTER_COLLECT%%"

### Integers

# select compression method (1 = gzip, 2 = bzip2, 3 = lzma)
COMPRESSION_METHOD="%%COMPRESSION_METHOD%%"

############

# Parameters passed to the simulation program and to the custom program

SIM_PARAMETERS=""

############
# Methods

#########
# Print an error message on stderr
#  $1 err text

ErrMsg()
{
  echo "[Error] (`basename $0`): $1" >/dev/stderr
}

#########
# Print an error message of the child on stderr
#  $1 err text

ChildErrMsg()
{
  echo "[Error] (`basename $SIMULATION_PROGRAM_CALL`): $1" >/dev/stderr
}

#########
# Add a command line parameter with argument to the list of parameters of the simulation program
# when the argument is empty, the call is ignored
#  $1   switch char (without the -)
#  $2   argument

AddToSimParameters()
{
  [ -n "$2" ] && SIM_PARAMETERS="$SIM_PARAMETERS -${1} $2"
}

#########
# Add a list of strings with a command line char to the list of parameters of the simulation program
# The list may be empty
#  $1   switch char (without -)
#  $$   arguments

AddStringListToSimParameters()
{
  local ch=$1
  shift
  shopt -s nullglob
  for str in $*; do
    AddToSimParameters "$ch" "$str"
  done
  shopt -u nullglob
}

#########
# Check an argument for being readable and executable
# The list may be empty
#  $1   file name
#  return 0, when ok, else 1

isExecutable()
{
  local bin="$1"
  [ ! -r "$bin" ] && { ErrMsg "$bin is not readable"; return 1; }
  [ ! -x "$bin" ] && { ErrMsg "$bin is not executable"; return 1; }
  return 0
}

############
# Main

### early checks and actions, do not use RETVAL

# cd to working directory to make this script self-contained

if ! cd "`dirname $0`"; then
  ErrMsg "Cannot cd to working directory"
  exit -1
fi

# check for invalid compression selection

if [ "$COMPRESS_RESULT_FILES_BY_SIMLIB" = "Y" -a "$COMPRESS_RESULT_FILES_BY_SIMTREE" = "Y" ]; then
  ErrMsg "Cannot select compression both by SimTree and by SimLib"
  exit -1
fi

### Prepare return value
RETVAL=0

# select compression command and parameter to simulation binary

case "$COMPRESSION_METHOD" in
  0 )
    COMPRESSION_CMD=""
    COMPRESSION_METHOD=""
    ;;
  1 )
    COMPRESSION_CMD="gzip -9 -f"
    COMPRESSION_METHOD="gzip"
    ;;
  2 )
    COMPRESSION_CMD="bzip2 -9 -f"
    COMPRESSION_METHOD="bzip2"
    ;;
  3 )
    COMPRESSION_CMD="lzma -9 -f"
    COMPRESSION_METHOD="lzma"
    ;;
  * )
    ErrMsg "Invalid compression method"
    ;;
esac

# send PID to upstream process
echo "[#SimTreeControl#EXEC#PID#] $$"

# Reset compression parameter when compression by SimLib is not requested

[ "$COMPRESS_RESULT_FILES_BY_SIMLIB" = "N" ] && COMPRESSION_METHOD=""
 
# Add file lists to the simulation program parameter list

AddStringListToSimParameters "b" "$PARTIAL_RESULT_FILENAMES"
AddStringListToSimParameters "e" "$EXPORT_RESULT_FILENAMES"
AddStringListToSimParameters "i" "$IMPORTED_RESULT_FILENAMES"

# Add other parameters

AddToSimParameters "n" "$NUM_BATCHES"
AddToSimParameters "p" "$SIMULATION_PARAMETER_FILENAME"
AddToSimParameters "g" "$PARSER_LOG_FILENAME"
AddToSimParameters "f" "$FILTER_FILENAME"
AddToSimParameters "l" "$FINAL_RESULT_FILENAME"
AddToSimParameters "s" "$SEED_VALUE"
AddToSimParameters "z" "$COMPRESSION_METHOD"

# temp file for output of time (name also in VFS)

TMPF="simtree-time.tmp"

# Call simulation binary

SDATE=`date +"%d.%m.%Y %R:%S"`
if [ "$RETVAL" = "0" ]; then
  if ! isExecutable "$SIMULATION_PROGRAM_CALL"; then RETVAL=1; fi
  if [ "$RETVAL" = "0" ]; then
    /usr/bin/time --output=$TMPF --format="%e %U %S" nice -${CALLSIM_NICE_LEVEL} $SIMULATION_PROGRAM_CALL $SIM_PARAMETERS
    RETVAL=$?
  fi
fi
EDATE=`date +"%d.%m.%Y %R:%S"`

# tell status upstream, remove tmp file

[ "$RETVAL" = 0 ] && echo "[#SimTreeControl#CS##] Start $SDATE, End $EDATE (`cat $TMPF`)"
rm -f $TMPF

# Remove invalid generated files

shopt -s nullglob
for fname in $PARTIAL_RESULT_FILENAMES $EXPORT_RESULT_FILENAMES $FINAL_RESULT_FILENAME; do
  # handle uncompressed file, may exist even when SimLib should compress (and did not)
    [ -f "$fname" ] && [ "`stat --format=%s "$fname"`" -lt 50 ] && { ErrMsg "$fname too short, deleted"; rm -f $fname; }
    [ -f "$fname" ] && [ -z "`head -2 "$fname" | grep "^<SimulationResults"`" ] && { ErrMsg "$fname has invalid/missing start, deleted"; rm -f $fname; }
    [ -f "$fname" ] && [ -z "`tail -1 "$fname" | grep "^</SimulationResults"`" ] && { ErrMsg "$fname has invalid/missing end, deleted"; rm -f $fname; }
  # when SimLib may have compressed, check files with compress extensions too
    if [ "$COMPRESS_RESULT_FILES_BY_SIMLIB" = "Y" ]; then
      # delete too short files, cannot check xml validity (or use bzcat-family, performance?)
      for ext in lzma bz2 gz; do
        fc=${fname}.$ext
        [ -f "$fc" ] && [ "`stat --format=%s "$fc"`" -lt 50 ] && { ErrMsg "$fc too short, deleted"; rm -f $fc; }
      done
    fi
done
shopt -u nullglob

# Pack the generated result files, if requested

if [ "$COMPRESS_RESULT_FILES_BY_SIMTREE" = "Y" ]; then
  shopt -s nullglob
  for f in $PARTIAL_RESULT_FILENAMES $FINAL_RESULT_FILENAME; do
    [ -f "$f" ] && nice -${CALLSIM_NICE_LEVEL} $COMPRESSION_CMD $f
  done
  shopt -u nullglob
fi

# Delete export result files after successful collect

if [ "$RETVAL" = "0" -a "$DELETE_EXPORT_RESULT_FILES_AFTER_COLLECT" = "Y" ]; then
  [ -n "$IMPORTED_RESULT_FILENAMES" ] && rm -f $IMPORTED_RESULT_FILENAMES
fi

# Remove lock file (ignore errors)

rm -f %%LOCK_FILENAME%%

# map away special exit code of ssh in case of ssh failure

[ "$RETVAL" = "255" ] && RETVAL=-1

# return exit value 

exit $RETVAL

# End of file
