#!/bin/bash
# -*- mode: sh; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: nil -*-
# vi: set shiftwidth=4 tabstop=8 softtabstop=4 expandtab:
# :indentSize=4:tabSize=8:noTabs=true:
# vim: filetype=sh

# ---- error handling
set -o errexit;
set -o posix;
set -o pipefail;
set -o errtrace;
unexpected_error() {
    local errstat=$?
    echo "${g_prog:-$(basename "$0")}: Error! Encountered unexpected error at 'line $(caller)', bailing out..." 1>&2
    exit $errstat;
}
trap unexpected_error ERR;

# Force the path to only what we need, saving off the original path
PATH_ORIG=$PATH;
PATH=/usr/bin:/bin

g_prog=$(basename "$0");
g_progdir=$(dirname "$0");
g_progdir_abs=$(dirname "$(readlink -f "$0")");

# ---- global env

. "$g_progdir_abs/../../private/runtime-common/lib/globalenv.ish"

# ---- error functions
merror() {
    echo "$g_prog: Error! ""$@" 1>&2;
    exit 1;
}
minterror() {
    echo "$g_prog: Internal Error! ""$@" 1>&2;
    exit 1;
}
mwarn() {
    echo "$g_prog: Warning! ""$@" 1>&2;}


# ---- usage
usage() {
    local exitstat=2;
    if [[ ! -z "${2:-}" ]] ; then
        if [[ ! $2 =~ [[:digit:]]+ ]] ; then
            minterror "usage(): exitstat ($exitstat) must be numeric."
        fi
        exitstat=$2;
    fi

    # Only redirect to stderr on non-zero exit status
    if [[ $exitstat -ne 0 ]] ; then
        exec 1>&2;
    fi

    if [[ ! -z "${1:-}" ]] ; then
        echo "$g_prog: Error! $1"
    fi

    echo "Usage: $g_prog \\"
    echo "             --skip-jmstest|--no-jmstest \\"
    echo "             --jmstest-timeout N \\"
    echo "             --timeout N \\"
    echo "             [ arg1 [argN ...]]"
    echo ""
    echo "         --skip-jmstest|--no-jmstest"
    echo "                             -- do not run rumjmscmd test"
    echo "         --jmstest-timeout   -- timeout for rumjmscmd test, in seconds"
    echo "                                (default: 300)"
    echo "         --pbservice-timeout|--timeout"
    echo "                             -- timeout for pbservice run-sat-services command,"
    echo "                                in seconds (default: 1800)"
    echo "         argN                -- extra args pbservice run-sat-services"
    echo "         --help              -- print this usage";
    echo

    if [[ $exitstat -ne 0 ]] ; then
        # Print error again, useful for long usages messages
        if [[ ! -z "${1:-}" ]] ; then
            echo ""
            echo "$g_prog: Error! $1"
        fi
    fi

    # bash only:
    if [[ $exitstat -ne 0 ]] ; then
        echo "  at: $(caller)";
    fi
    exit $exitstat;
}

# ---- argument parsing
# Save off the original args, use as "${g_origargs[@]}" (with double quotes)
declare -a g_origargs;
g_origargs=( ${1+"$@"} )

parseargs() {
    opt_skip_jmstest=false;
    opt_jmstest_timeout="";
    opt_pbservice_timeout="";
    opt_pbservice_args=();

    while [[ $# != 0 ]]; do
        opt="$1"; shift;
        case "$opt" in
            # Flag with no argument example:
            #   --flag|--fla|--fl|--f)
            #     opt_flag=true;;
            # Option with argument example:
            #   --arg|--ar|--a)
            #     [[ $# -eq 0 ]] && usage;
            #     opt_somearg=$1; shift;;
            --skip-jmstest|--no-jmstest) opt_skip_jmstest=true;;
            --jmstest-timeout)
                [[ $# -eq 0 ]] && usage;
                [[ ! $1 =~ ^[0-9]+$ ]] && usage;
                opt_jmstest_timeout=$1; shift;;
            ---pbservice-timeout|--timeout)
                [[ $# -eq 0 ]] && usage;
                [[ ! $1 =~ ^[0-9]+$ ]] && usage;
                opt_pbservice_timeout=$1; shift;;
            -h|-help|--help|--hel|--he|--h) usage "" 0;;
            *) opt_pbservice_args+=( "$opt" );
        esac
    done
}


# ---- globals

set_preglobals() {
    :
}

set_globals() {

    rootdir="$g_progdir/../.."
    rootdir_abs="$g_progdir_abs/../.."

    g_canneddata_dir="$rootdir_abs/bundles/smrtinub/current/private/pacbio/canneddata"
    g_pbservice_exe="$rootdir_abs/bundles/smrttools/smrtcmds/bin/pbservice"

    g_python3_exe="$rootdir_abs/bundles/smrttools/smrtcmds/bin/python3"
    g_serverconfigfile="$rootdir_abs/bundles/smrtlink-analysisservices-gui/current/private/pacbio/smrtlink-analysisservices-gui/smrtlink-system-config.json"

    g_userdata_dir="$g_progdir_abs/../../../../userdata"

    g_runjmscmd_exe="$g_progdir/runjmscmd"

    g_logdir="$rootdir_abs/rwdir/log"
    g_logfile="$g_logdir/run-sat-services.log"

}

# ---- subroutines

# ---- main

# Save off original cmdline args, use as "${g_origargs[@]}" (with doublequotes)
g_origargs=( ${1+"$@"} )

set_preglobals ${1+"$@"};
parseargs ${1+"$@"};
set_globals;

echo "Reading server configuration information..."
host="localhost"
port=$("$g_python3_exe" -c "import json; d = json.load(open('$g_serverconfigfile')); print(d['smrtflow']['server']['port'])")

# No need to import the canned data any more.  It should be imported
# automatically on the first services-start after an upgrade or install, so
# it should be up to date at this point.  We will just check that services
# are running with pbservice instead.

# Check to make sure the services are available
echo
echo "Checking server status with 'pbservice status'..."
cmdline="\"$g_pbservice_exe\" status --log-level DEBUG --host \"$host\" --port \"$port\""
echo "  Executing: $cmdline"
stat=0;
eval "$cmdline" || stat=$?
if [[ $stat -ne 0 ]] ; then
    merror "Services are not running properly."
fi

# Run a simple, quick job submission test to verify that cluster submits are
# workig properly
if ! $opt_skip_jmstest; then
    if [[ -e "$g_userdata_dir/generated/config/computecfg_00/jmsenv_00.ish" ]] ; then
        echo
        echo "Running simple cluster submission 'runjmscmd' test..."
        cmdline="\"$g_runjmscmd_exe\" --start --testmode --gen --exec --wait --cmd \"$g_userdata_dir/jobs_root/jmstest/rss-jmstestcmd.sh\" "
        if [[ ! -z "$opt_jmstest_timeout" ]] ; then
            cmdline+=" --timeout $opt_jmstest_timeout"
        fi
        echo "Executing: $cmdline"
        stat=0;
        eval "$cmdline" || stat=$?
        if [[ $stat -ne 0 ]] ; then
            merror "Cluster submission 'runjmstest' failed."
        fi
    fi
fi

# Set up tmp log file
rm -f "$g_logfile"
mkdir -p "$g_logdir"

# Run the tiny-lambda SAT test
echo
echo "Running tiny-lambda SAT test..."

cmdargs=(
     run-pipeline --debug
    --block --host "\"$host\"" --port "\"$port\""
    cromwell.workflows.pb_sat
    -e "\"$g_canneddata_dir/referenceset/lambdaNEB/referenceset.xml\""
    -e "\"$g_canneddata_dir/lambdaTINY/m54026_181219_010936_tiny.subreadset.xml\""
    --job-title "\"PacBio Example SAT Job\""
)
if [[ ! -z "$opt_pbservice_timeout" ]] ; then
    cmdargs+=( --timeout "$opt_pbservice_timeout" )
fi
cmdargs+=( "${opt_pbservice_args[@]+${opt_pbservice_args[@]}}" )

echo "  Executing: $g_pbservice_exe ""${cmdargs[@]}"

# Run pbservice, dumping to the tmp logfile as well as the console
stat=0;
eval "$g_pbservice_exe" "${cmdargs[@]}" | tee "$g_logfile" || stat=$?

# Grab the state from the tmp log file, then remove the temporary log file
statestr=$(grep -E '^[[:space:]]+state:' "$g_logfile" || true);
lastline=$(sed -ne '${s/^[[:space:]]*$/blank/p}' "$g_logfile");
rm -f "$g_logfile"

# Add a blank line if needed to set appart the success/fail line
if [[ x"$lastline" != x"blank" ]] ; then
    echo
fi

if [[ $stat -ne 0 ]]; then
    merror "Job failed, with exit code ${stat}"
else
    if [[ $statestr =~ ^[[:space:]]+state:[[:space:]]*(.*) ]] ; then
        if [[ x"${BASH_REMATCH[1]}" != x"SUCCESSFUL" ]] ; then
            merror "Job failed, with state '${BASH_REMATCH[1]}'."
        else
            # Job was successful and exited with zero status
            :
        fi
    else
        merror "Job failed, with unknown state."
    fi
fi

echo "Job successful."
exit 0;
