#!/usr/bin/bash
#shellcheck disable=SC1090,SC2164

. "$(sfpath)" || exit 3

shellfu import pretty

shellfu import jats

usage() {
    mkusage "$@" "[options] PLANID" \
        -- \
            "Run every test in JATS plan."                                   \
            ""                                                               \
        -o                                                                   \
            "-k         Keep run directory."                                 \
            "-p PARAM=VALUE   Set test parameter named PARAM to value VALUE."\
            "           Can be specified multiple times.  Note that VALUE"   \
            "           must be a simple word (see JATS specification)."     \
            "-t TIMEOUT   Kill test after TIMEOUT seconds.  Default: 0,"     \
            "           which disables the timeout.       "                  \
        --                                                                   \
            "Test body should consist of asserts and/or phases documented"   \
            "in jat.sh Shellfu module; use \`sfdoc jat\` to access its"      \
            "documentation."
}

mkutil() {
    #
    # Deploy planner utility $1
    #
    local util=$1
    mkdir -p bin
    #shellcheck disable=SC2016
    case "$util" in
        jats_lstests)
            echo '#!/bin/bash'
            echo '. "$(sfpath)" || exit 3'
            echo 'shellfu import pretty'
            echo 'test -n "$__JATS_PLANNER_SUITEHOME" || die "no SuiteHome?"'
            #shellcheck disable=SC1003
            echo 'cd "$__JATS_PLANNER_SUITEHOME" \'
            echo ' || die "could not chdir to suite home: $__JATS_PLANNER_SUITEHOME"'
            echo 'jattool tfind | sed "s|^$__JATS_PLANNER_SUITEHOME/||"'
            ;;
        jats_param)
            echo '#!/bin/bash'
            echo '. "$(sfpath)" || exit 3'
            echo 'shellfu import pretty'
            echo 'main() {'
            echo '    local want=$1   # wanted parameter name'
            echo '    local pair      # each pair in $__JATS_PLANNER_PARAMS'
            echo '    local pname     # each parameter value'
            echo '    local pvalue    # each parameter name'
            echo '    local es=0      # exit status'
            echo '    for pair in ${__JATS_PLANNER_PARAMS//,/ }; do'
            echo '        case $pair in'
            echo '            *=*)    pname=${pair%=*}; pvalue=${pair#$pname=} ;;'
            echo '            *)      warn "malformed parameter expression: $pair" ;;'
            echo '        esac'
            echo '        test "$pname" == "$want" || continue'
            echo '        test -n "$pvalue"; es=$?'
            echo '        echo "$pvalue"'
            echo '        return $es'
            echo '    done'
            echo '    die "no such parameter: '"'"'$want'"'"' in '"'"'$__JATS_PLANNER_PARAMS'"'"'"'
            echo '}'
            echo 'main "$@"'
            ;;
        jats_enum)
            echo '#!/bin/bash'
            echo '. "$(sfpath)" || exit 3'
            echo 'shellfu import pretty'
            echo 'main() {'
            echo '    local tpath=$1  # test path'
            echo '    local epath="$tpath/enum"'
            echo '    local es=0      # enumerator exit status'
            echo '    test -f "$epath" || die "no enumerator for test: $epath"'
            echo '    bash -n "$epath" || die "syntax error in enumerator: $epath"'
            echo '    bash "$epath"; ees=$?'
            echo '    test $ees -eq 0  || die "enumerator exited with non-zero status: $ees, $epath"'
            echo '}'
            echo 'main "$@"'
            ;;
        jats_mkplan)
            case "$PlanName" in
                "")
                    echo '#!/bin/bash'
                    echo 'jats_lstests | LC_ALL=C sort'
                    ;;
                *)
                    cat "$SuiteHome/_jats/plans/$PlanName" \
                     || die "could not read plan script: $SuiteHome/_jats/plans/$PlanName"
             esac
             ;;
    esac >"bin/$util"
    chmod +x "bin/$util"
}

mkplan() {
    #
    # Run plan $1
    #
    local pes
    mkutil jats_mkplan
    mkutil jats_lstests
    mkutil jats_param
    mkutil jats_enum
    PATH="$PWD/bin:$PATH" \
    __JATS_PLANNER_SUITEHOME=$SuiteHome \
    __JATS_PLANNER_PARAMS=$PlanParams \
        "./bin/jats_mkplan" >plan.out 2>plan.err; pes=$?
    test -s plan.err && {
        warn "plan returned errors:"
        while read -r errline; do
            warn "    $errline"
        done <plan.err
        es=3
    }
    return $pes
}

JATS__PATH=${JATS__PATH:-/usr/share/jats/suite}

runplan() {
    #
    # Run all tests in plan file $1
    #
    local pfile=$1
    local testid
    local head=true
    local es=0
    local tes=0
    test -s "$pfile" || {
        warn "test plan is empty"
        return 2
    }
    if $NoRun; then
        while read -r testid; do
            echo "$SuiteId$testid"
        done <"$pfile"
        return 0
    else
        while read -r testid; do
            $head || { echo; echo "---"; echo; }
            $head && head=false
            think -l "running test: $SuiteId$testid" ""
            jattool runtest "$SuiteId$testid"; tes=$?
            test "$tes" -gt "$es" && es=$tes
        done <"$pfile"
        return $es
    fi
}

main() {
    local PlanSpec
    local SuiteHome
    local PlanTmp
    local PlanParams
    local PlanName
    local SuiteId
    local keeptmp=false
    local NoRun=false
    local es=0
    while true; do case $1 in
        -k) keeptmp=true; shift ;;
        -n) NoRun=true; shift ;;
        -p) PlanParams+=",$2"; shift 2 || usage -w "missing K=V" ;;
        -*) usage ;;
        *)  break ;;
    esac done
    PlanSpec=$1
    case $PlanSpec in
        "")
            usage -w "no PLANID?"
            ;;
        jats://*//%*)
            PlanName=$(jats__plidparse pln "$PlanSpec")
            SuiteId=$(jats__plidparse suite "$PlanSpec")
            PlanParams+=",$(jats__plidparse params "$PlanSpec")"
            debug -v PlanName SuiteId
            SuiteHome=$(jats__slocate "$SuiteId") || die "could not locate suite $SuiteId"
            ;;
        *)
            die "invalid PLANID format: $PlanSpec"
            ;;
    esac
    PlanParams=$(
        sed '
            s/,,*/,/g
            s/,$//
            s/^,//
        ' <<< "$PlanParams"
    )
    if test -n "$PlanName"; then
        test -f "$SuiteHome/_jats/plans/$PlanName" \
         || die "plan script not found: $SuiteHome/_jats/plans/$PlanName"
    fi
    PlanTmp=$(mktemp -dt jattool-runplan.XXXXXXXX)
    debug -v SuiteHome PlanTmp
    pushd "$PlanTmp" >/dev/null
        mkplan
    popd >/dev/null
    runplan "$PlanTmp/plan.out"; es=$?
    $keeptmp || rm -rf "$PlanTmp"
    $keeptmp && warn "leaving temporary directory behind: $PlanTmp"
    return $es
}

main "$@"
