#! /bin/bash

status=1
command="$0 $*"
architecture=""
keep_log=0
tmpdir=${TMPDIR:-/tmp}
log_file="$tmpdir/tractor$$_log"
expect_file="$tmpdir/tractor$$_expect"
trap 'rm -f $expect_file; [ $keep_log -eq 0 ] && rm -f $log_file; exit $status' 0 1 2 15

config_file="/dev/null"
output_level='Warning'
write_history=1
show_options=0
rprofile_backed_up=0
quiet=0
profile_performance=0
parallelisation_factor=1
batch_mode=0
verbose_level=1
working_dir=${TRACTOR_WORKING_DIR:-.}
distribution_version="ersion unknown"

command_flags=""

type expect >/dev/null 2>&1
expect_available=$?

usage()
{
    echo "tractor (program v3.5.0, distribution v$distribution_version)"
    echo "Run a TractoR experiment script in R"
    echo
    echo "Usage: tractor [-ldzqfbi] [-v level] [-a architecture] [-w working_dir]"
    echo "               [-c config_file] script [arg1 [arg2 ...]]"
    echo "       tractor -o [-w working_dir] script"
    echo "       tractor -h"
    echo
    echo "  -h          Display this usage information and exit"
    echo "  -o          Do not run the script, but instead produce a list of the"
    echo "              options that it supports, along with their default values"
    echo "  -l          Direct output to a log file as well as to stdout"
    echo "  -d          Produce debugging output. Equivalent to '-v 3'"
    echo "  -z          Do not write the command line used into a history log file"
    echo "  -q          Run in quiet mode. The tractor script will not produce any"
    echo "              output of its own"
    echo "  -f          Profile the performance of the script"
    echo "  -b          Run R in batch mode, which is entirely noninteractive, and"
    echo "              will produce no output until it finishes running. This can"
    echo "              be useful when running multiple experiments in parallel"
    echo "  -i          Ignore any personal config files in ~/.tractor"
    echo "  -v {0-3}    Adjust the verbosity of output generated. The level should"
    echo "              be between 0 (least) to 3 (most). Default is 1"
    echo "  -a arch     Specify a subarchitecture (e.g. 'x86_64'), which is passed"
    echo "              to R. Relevant only for multiarchitecture systems"
    echo "  -w dir      Specify the working directory, which will be created if"
    echo "              necessary. Default is '.', the current directory"
    echo "  -c file     Specify a configuration file in YAML format"
    echo
    echo "The script, a text file containing R code, need not be specified with the"
    echo "'.R' extension. The program searches in the current working directory for"
    echo "the specified script first, followed by any directory specified using the"
    echo "'-w' option, then ~/.tractor, and finally the share/tractor/experiments"
    echo "directory under \$TRACTOR_HOME. The \$TRACTOR_PATH and \$TRACTOR_PACKAGES"
    echo "environment variables can be used to specify additional paths. The man"
    echo "page has details."
    echo
    echo "To find out what scripts are available, type \"tractor list\". To find out"
    echo "what a given script does, type \"tractor -o (script name)\"."
    echo
}

if [ -z "${TRACTOR_HOME}" ]; then
    echo "Note: The TRACTOR_HOME environment variable is not set; it will be guessed"
    TRACTOR_HOME=`echo $0 | sed 's/\/bin\/tractor$//'`
else
    # Replace the specified path with a fully-qualified version
    TRACTOR_HOME=`unset CDPATH; cd "$TRACTOR_HOME" && pwd`
fi
export TRACTOR_HOME

[ -f "${TRACTOR_HOME}/VERSION" ] && distribution_version=`cat "${TRACTOR_HOME}/VERSION"`

supress_config=`echo "$@" | grep -c '\-i' -`
[ $supress_config -eq 0 -a -f "$HOME/.tractor/config" ] && source "$HOME/.tractor/config"

while getopts "hldozqfbiv:p:a:w:c:" opt; do
    TRACTOR_FLAGS="$TRACTOR_FLAGS -$opt $OPTARG"
    case "$opt" in
        h) usage; status=0; exit ;;
        l) keep_log=1 ;;
        d) verbose_level=3 ;;
        o) show_options=1 ;;
        z) write_history=0 ;;
        q) quiet=1 ;;
        f) profile_performance=1; command_flags="-f ${command_flags}" ;;
        b) batch_mode=1 ;;
        i) supress_config=1 ;;
        v) verbose_level=$OPTARG ;;
        p) parallelisation_factor=$OPTARG; echo "The '-p' option is deprecated; use \"plough\" instead" 1>&2 ;;
        a) architecture=$OPTARG ;;
        w) working_dir=`echo $OPTARG | sed 's/\/$//'` ;;
        c) config_file="$config_file:$OPTARG" ;;
        ?) usage 1>&2; exit ;;
    esac
done

shift "$(($OPTIND-1))"
export TRACTOR_FLAGS

[ $# -eq 0 ] && {
    echo "Error: No script name given. Type \"tractor -h\" for help" 1>&2
    exit
}

[ -z "$R" ] && R=R

[ ! -z "${architecture}" ] && R="$R --arch=${architecture}"

script_name=`echo $1 | sed 's/\.R$//'`

[ $supress_config -eq 0 -a -f "$HOME/.tractor/${script_name}.yaml" ] && config_file="$HOME/.tractor/${script_name}.yaml:$config_file"

[ $keep_log -eq 1 ] && log_file="$working_dir/tractor_${script_name}${TRACTOR_PLOUGH_ID+.}${TRACTOR_PLOUGH_ID}.log"

[ -d "${TRACTOR_HOME}/lib/R" ] && export R_LIBS="${TRACTOR_HOME}/lib/R"

shift
args="$@"
export TRACTOR_COMMANDLINE="tractor $script_name $args"

script_file=`echo "library(utils); library(tractor.utils); cat(findExperiment('$script_name'))" | "$R" --slave --vanilla 2>&1`
[ $? -eq 0 ] || {
    echo "Error: Script file \"${script_name}.R\" not found" 1>&2
    exit
}

[ -z $COLUMNS ] && {
    type tput >/dev/null 2>&1
    tput_available=$?
    [ $tput_available -eq 0 ] && COLUMNS=`tput cols` || COLUMNS=80
    export COLUMNS
}

if [ $show_options -eq 1 ]; then
    echo "library(utils); library(tractor.utils); describeExperiment('$script_file', $COLUMNS)" | "$R" --slave --vanilla 2>&1
    status=0
    exit
fi

deprecation_message=`grep '#@deprecation' $script_file | sed 's/#@deprecation //'`
[ -n "$deprecation_message" -a $quiet -eq 0 ] && echo "NOTE: $deprecation_message" 1>&2

interactive=`grep -ci '#@interactive TRUE' $script_file`

if [ $write_history -eq 1 ]; then
    nohistory_flag=`grep -ci '#@nohistory TRUE' $script_file`
    [ $nohistory_flag -eq 1 ] && write_history=0
fi

[ ! -e "$working_dir" ] && mkdir -p "$working_dir"

export verbose_level
if [ $verbose_level -eq 1 ]; then
    output_level='Info'
elif [ $verbose_level -eq 2 ]; then
    output_level='Verbose'
elif [ $verbose_level -eq 3 ]; then
    output_level='Debug'
fi

[ $expect_available -ne 0 -a -f .Rprofile ] && {
    echo "Ignoring current .Rprofile file"
    mv .Rprofile .Rprofile.bak
    rprofile_backed_up=1
}

[ -t 1 -a -t 2 -a -z "$TRACTOR_NOCOLOUR" -a -z "$TRACTOR_NOCOLOR" ] || command_flags="-m $command_flags"

[ $quiet -eq 0 ] && echo "Starting TractoR environment..." 1>&2

if [ -x "$TRACTOR_HOME/libexec/tractor" ]; then
    "$R" --vanilla CMD "$TRACTOR_HOME/libexec/tractor" $command_flags -w "$working_dir" -l "$output_level" -c "$config_file" -p "$parallelisation_factor" -g "$log_file" "$script_file" $args 2>&1
elif [ -x "$TRACTOR_HOME/bin/exec/tractor" ]; then
    "$R" --vanilla CMD "$TRACTOR_HOME/bin/exec/tractor" $command_flags -w "$working_dir" -l "$output_level" -c "$config_file" -p "$parallelisation_factor" -g "$log_file" "$script_file" $args 2>&1
elif [ $batch_mode -eq 1 ]; then
    cat >"$expect_file" <<EOF
library(utils)
library(tractor.utils)
bootstrapExperiment('$script_file', '$working_dir', OL\$$output_level, '$config_file', '$args', $parallelisation_factor, $profile_performance)
EOF
    "$R" CMD BATCH --slave --vanilla $expect_file $log_file
elif [ $interactive -eq 0 ]; then
    echo "library(utils); library(tractor.utils); bootstrapExperiment('$script_file', '$working_dir', OL\$$output_level, '$config_file', '$args', $parallelisation_factor, $profile_performance)" | "$R" --slave --vanilla 2>&1 | tee $log_file
elif [ $expect_available -eq 0 ]; then
    cat >"$expect_file" <<EOF
log_user 0
spawn $R --quiet --vanilla
set timeout 3
send "library(utils)\n"
expect -re ">.+\r\n"
send "library(tractor.utils)\n"
expect -re ">.+\r\n"
send "bootstrapExperiment('$script_file', '$working_dir', OL\\\$$output_level, '$config_file', '$args', $parallelisation_factor, $profile_performance)\n"
expect -re ">.+\r\n"
interact
EOF
    expect -f $expect_file | tee $log_file
else
    echo "library(utils); library(tractor.utils); bootstrapExperiment('$script_file', '$working_dir', OL\$$output_level, '$config_file', '$args', $parallelisation_factor, $profile_performance)" >.Rprofile
    "$R" --slave --no-save --no-restore --no-site-file --no-environ 2>&1 | tee $log_file
fi

warnings=`grep -c WARNING $log_file`
errors=`grep -c ERROR $log_file`

[ $batch_mode -eq 1 ] && cat $log_file

[ -f "$working_dir/tractor_history.log" ] && mv "$working_dir/tractor_history.log" "$working_dir/tractor-history.log"

[ $write_history -eq 1 ] && echo "[`date`] $command [${warnings}W/${errors}E]" >> "$working_dir/tractor-history.log"

[ $expect_available -ne 0 ] && {
    rm -f .Rprofile
    [ $rprofile_backed_up -eq 1 ] && mv .Rprofile.bak .Rprofile
}

[ $profile_performance -eq 1 ] && {
    "$R" CMD Rprof "$working_dir/tractor-Rprof.out" > "$working_dir/${script_name}.Rprof"
    rm -f "$working_dir/tractor-Rprof.out"
}

[ $quiet -eq 0 ] && echo "Experiment completed with $warnings warning(s) and $errors error(s)" 1>&2

[ $errors -eq 0 ] && status=0
