#!/usr/bin/bash
# MKit - simple install helper
# See LICENSE file for copyright and license details.

mkit_import target
mkit_import util

VDK_TEST_CYCLE__DELAY=${VDK_TEST_CYCLE__DELAY:-}

VDK_TEST_CYCLE__CLEAN=${VDK_TEST_CYCLE__CLEAN:-}

VDK_TEST_CYCLE__CLEAR=${VDK_TEST_CYCLE__CLEAR:-}


__vdk_test_cycle__sleep () {
    #
    # Sleep for $1 seconds, producing dots
    #
    local secs="$1"
    local secs_togo="$secs"
    echo -e "sleeping for $secs seconds" >&2
    (
        #shellcheck disable=SC2317,SC2329
        stopwait() {
            echo >&2 -e "interrupted!!!"
            exit 102
        }
        trap stopwait sigint
        while test "$secs_togo" -gt 0; do
            sleep 1
            echo -n . >&2
            ((secs_togo--))
        done
        echo >&2
    )
}

vdk_test_cycle__main() {
    #
    # Run tests
    #
    local Delay     # delay (in seconds) before running the next vdk_test
    local Clean     # policy of cleaning after cycle has stopped
    local Clear     # if true, clear the screeen before running the next vdk_test
    local es=0      # final exit status
    local tes=0     # last vdk_test exit status
    local ses       # sleep routine exit status (102 if interrupted)
    Delay=$(__vdk_test_cycle__load_delay)   || return 3
    Clean=$(__vdk_test_cycle__load_clean)   || return 3
    Clear=$(__vdk_test_cycle__load_clear)   || return 3
    while true; do
        target__route clean
        $Clear && clear
        VDK_TEST__SHELL=never \
            target__route vdk_test; tes="$?"
        test "$tes" -gt "$es" && es="$tes"
        __vdk_test_cycle__sleep "$Delay"; ses=$?
        warn "ses=$ses"
        test "$ses" -gt 0 \
         && __vdk_test_cycle__clean "$tes" "$ses" \
         && return "$tes"
    done
    __vdk_test_cycle__clean "$tes" "$ses"
    return "$es"
}

__vdk_test_cycle__clean() {
    #
    # Clean up or not, based on test status $1, sleep status $2 and $Clean policy
    #
    local tes="$1"
    local ses="$2"
    local tes_meaning=.
    local ses_meaning=.
    local reason
    local do_clean=false
    local cphint="(clean policy is '$Clean')"
    test "$tes" -eq 0 && tes_meaning=p
    test "$tes" -gt 0 && tes_meaning=F
    test "$ses" -eq 0 && ses_meaning=c
    test "$ses" -eq 102 && ses_meaning=I
    case $tes_meaning:$ses_meaning:$Clean in
        *:c:onint)      do_clean=false; reason="next vdk_test is coming.."      ;;
        *:I:onint)      do_clean=true;  reason="on interrupt"                   ;;
        p:*:onpass)     do_clean=true;  reason="on pass"               ;;
        F:*:onpass)     do_clean=false; reason="vdk_test failed with: $tes"     ;;
        p:I:onboth)     do_clean=true;  reason="on interrupt and pass" ;;
        *:*:onboth)     do_clean=false; reason="vdk_test failed with: $tes"     ;;
        *:always)       do_clean=true ;;
        *:never)        do_clean=false ;;
        *)              warn "bug: invalid option value: clean=$Clean"
                        return 3 ;;
    esac
    if "$do_clean"; then
        warn "cleaning up $reason $cphint"
        target__route clean
    else
        warn "skipping clean; $reason $cphint"
    fi
}

__vdk_test_cycle__load_clean() {
    #
    # Safely load 'clean' option
    #
    local allowed=(onpass onint onboth always never)
    util__loadenv_enum VDK_TEST_CYCLE__CLEAN "${allowed[@]}" && return 0
    plugin__option_enum clean "${allowed[@]}" && return 0
    warn "falling back to: clean = onboth" \
         " .. set VDK_TEST_CYCLE__CLEAN or [options:vdk_test_cycle:clean]" \
         " .. to onpass|onint|onboth|always|never to change it"
    echo onboth
}

__vdk_test_cycle__load_clear() {
    #
    # Safely load 'clear' option
    #
    util__loadenv_bool VDK_TEST_CYCLE__CLEAR && return 0
    plugin__option_bool clear && return 0
    warn "falling back to: clear = true" \
         " .. set VDK_TEST_CYCLE__CLEAN or [options:vdk_test_cycle:clear]" \
         " .. to a boolean (true|false) to change it"
    echo true
}

__vdk_test_cycle__load_delay() {
    #
    # Safely load 'delay' option
    #
    util__loadenv_posint VDK_TEST_CYCLE__DELAY && return 0
    plugin__option_posint delay && return 0
    warn "falling back to: delay = 5" \
         " .. set VDK_TEST_CYCLE__DELAY or [options:vdk_test_cycle:delay]" \
         " .. to a positive integer to change it"
    echo 5
}
