#!/bin/bash
export DIR_BRHCLUS=""
if [[ ! -f orthologer_conf.sh ]]; then
    echo "fatal: no orthologer_conf.sh found in $(pwd)!" 1>&2
    exit 255
fi
eval $(grep "^DIR_BRHCLUS" orthologer_conf.sh)

export TESTDIR=""
export TESTNAME=""
export LOGFILE=""
export EXTRA_INFO=""

# if running in docker whoami may not find a valid user
export SYS_WHOAMI="$(whoami 2>/dev/null)"
[[ -n $SYS_WHOAMI ]] || SYS_WHOAMI="uid$(id -u)"

# Error codes to be used by testfun()
EC_OK=0
EC_CMP_ALMOST=1
EC_CMP_POOR=2
EC_CMP_FAILED=3
EC_BUSCO_ALMOST=11
EC_BUSCO_POOR=12
EC_BUSCO_NONE=13
EC_BUSCO_BADID=14
EC_BUSCO_FAILED=15

EC_FAIL=255

dated_logfile() {
    echo -n "$1"
    local D=$(date +'%y%m%d_%H%M')
    echo "_${D}.log"
}

check_env() {
    [[ -d Results ]] || { echo "error: environment is missing Results dir! Please run setup.sh."; return 255; }
    [[ -d PWC     ]] || { echo "error: environment is missing PWC dir! Please run setup.sh.";     return 255; }
}

set_test_name() {
    TESTDIR=$(basename $(pwd))
    TESTNAME=$(basename "$1" .sh)
    LOGFILE=RunLogs/$(dated_logfile "$TESTNAME")
}

exitfunc() {
    __exit_value__=$?
    if [[ $__exit_value__ -eq 0 ]]; then
        echo "OK$EXTRA_INFO"
    else
        echo "FAILED$EXTRA_INFO"
    fi
    trap - EXIT
    exit $__exit_value__
}
trap exitfunc EXIT

TEST_NFAILED=0
TEST_NPOOR=0
TEST_NNEAR=0
TEST_NOK=0
TEST_T=0
update_nfailed() {
    local ec=$1
    if (( ec == $EC_OK )); then
        TEST_NOK=$((TEST_NOK+1))
    elif (( ec == $EC_CMP_ALMOST )); then
        TEST_NNEAR=$((TEST_NNEAR+1))
    elif (( ec == $EC_CMP_POOR )); then
        TEST_NPOOR=$((TEST_NPOOR+1))
    elif (( ec == $EC_BUSCO_ALMOST )); then
        TEST_NNEAR=$((TEST_NNEAR+1))
    elif (( ec == $EC_BUSCO_POOR )); then
        TEST_NPOOR=$((TEST_NPOOR+1))
    else
        TEST_NFAILED=$((TEST_NFAILED+1))
    fi
}

# error code:
#  0   - all ok
#  1   - busco ran OK but match not 100
#  2   - busco ran OK but nodeid is not expected
BUSCO_RES=
BUSCO_ID=
check_busco_result() {
    BUSCO_RES=""
    BUSCO_ID=""
    local run_label=$1
    local expected=$2  # expected node id
    local ec=$EC_OK

    #C:100.0% S:99.5% D:0.5% F:0.0% M:0.0% n:440
    local result=( $(./orthomapper.sh BUSCO_RESULT "$run_label" 2>/dev/null) )
	BUSCO_RES="${result[0]}"
    ec=$EC_BUSCO_ALMOST
	[[ "$BUSCO_RES" == "C:100.0%" ]] && ec=$EC_OK
    [[ "$BUSCO_RES" == "<NONE>"   ]] && ec=$EC_BUSCO_NONE

    # 4. check node id found
    if [[ $ec -ne $EC_BUSCO_NONE ]]; then
        BUSCO_ID=$(./orthomapper.sh BUSCO_RESULT $run_label what=nodeid)
        [[ "$BUSCO_ID" == "$expected" ]] || ec=$EC_BUSCO_BADID
    fi
    
    return $ec
}

check_map_result_files() {
    local run_label="$1"
    # check existance of result
    local res="${run_label}.og"
    local fclus="Cluster/$res"
    local fbase="Results/$res"
    [[ -f ${fclus}      ]] || { echo "error: missing result file ${fclus}";      return $EC_FAIL; }
    [[ -f ${fbase}.odb  ]] || { echo "error: missing result file ${fbase}.odb";  return $EC_FAIL; }
    [[ -f ${fbase}.desc ]] || { echo "error: missing result file ${fbase}.desc"; return $EC_FAIL; }
    [[ -f ${fbase}.hits ]] || { echo "error: missing result file ${fbase}.hits"; return $EC_FAIL; }
    [[ -f ${fbase}.annotations ]] || { echo "error: missing result file ${fbase}.annotations"; return $EC_FAIL; }
    return $EC_OK
}

run_test() {
    [[ -n $TESTNAME ]] || {
        echo "no test given"
        return 255
    }
    check_env || return 255
    printf "%-30s %-60s" "$TESTNAME" "$TESTDIR/$LOGFILE ... "
    local rstr="OK"
    local T0=$(date '+%s%N')
    local ec=0
    testfun >& $LOGFILE
    ec=$?
    update_nfailed $ec
    if (( ec == $EC_CMP_ALMOST )); then
        rstr="OK, F1=$CMPREF_F1"
    elif (( ec == $EC_CMP_POOR )); then
        rstr="POOR, F1=$CMPREF_F1"
    elif (( ec == $EC_CMP_FAILED )); then
        rstr="FAILED"
    elif(( ec == $EC_BUSCO_ALMOST )); then
        rstr="OK, BUSCO=$BUSCO_RES"
    elif (( ec == $EC_BUSCO_POOR )); then
        rstr="POOR, BUSCO=$BUSCO_RES"
    elif (( ec == $EC_BUSCO_NONE )); then
        rstr="BUSCO NONE"
    elif (( ec == $EC_BUSCO_BADID )); then
        rstr="BUSCO bad id: $BUSCO_ID"
    elif (( ec == $EC_BUSCO_FAILED )); then
        rstr="BUSCO FAILED"
    elif (( ec > $EC_BUSCO_FAILED )); then
        rstr="FAILED; ec=$ec"
    fi
    local T1=$(date '+%s%N')
    local expr="int((${T1}-${T0})*1.0e-9)"
    local dT=$(awk "BEGIN{ print $expr }")
    TEST_T=$dT
    printf "%-24s %s\n" "$rstr"    "T(secs) = $dT"
    trap - EXIT
    
    # near is good enough
    (( ec==1 )) && ec=0
    return $ec
}

download_fasta() {
    local fbase=$1
    local fref=refs/${fbase}

    if [[ ! -f $fref ]]; then
        local url="https://data.orthodb.org/v11/download/test/orthologer/fasta/${fbase}.gz"
        curl --silent "$url" -o refs/${fbase}.gz || {
            echo "error: failed downloading fasta $fbase"
            echo "url: $url"
            rm -f ${fbase}.gz
            return 255
        }
        gunzip ${fref}.gz || { echo "error: failed unzipping fasta"; rm -f ${fref}.gz; return 255; }
    fi
}

calc(){ awk "BEGIN{ print $T1 }" ;}
# compare with reference
# fsrc - local file with path
# fref - remote path relative to URL
#        eg "proj_prot/reference.og" (no .gz)
# will search for https://data.orthodb.org/current/download/test/orthologer/proj_prot/reference.og.gz
export CMPREF_F1=
cmp_with_ref() {
    CMPREF_F1=
    [[ $# -eq 2 ]] || return 255
    local fsrc=$1
    local fref=$2
    [[ -f $fsrc ]] || {
        echo "error: com_with_ref - missing source file at $fsrc"
        return 255
    }
    
    local tsturl="https://data.orthodb.org/current/download/test/orthologer/${fref}.gz"
    local frefbase=$(basename $fref)
    local f="refs/$frefbase"
    if [[ ! -f $f ]]; then
        echo "info: downloading reference result $fref"
	    echo "info: $tsturl"
	    curl --silent $tsturl -o ${f}.gz > /dev/null
        if [[ $? -eq 0 ]]; then
            gunzip ${f}.gz || {
                echo "warning: failed unzipping reference result at $f"
                rm -f "${f}.gz"
                f=""
            }
        else
            echo "warning: failed downloading reference result $f"
            rm -f "${f}.gz"
            f=""
        fi
    fi
    
    # compare source with ref
    echo
    echo "----------------------------------------------------------------"
    local ec=0
    if [[ -f $f ]]; then
	    echo "info: comparing reference with test result - log at RunLogs/cmp_${frefbase}.log"
        $DIR_BRHCLUS/cmpclus mismatch --noexact --A $f --B $fsrc >& RunLogs/cmp_${frefbase}.log
        if [[ $? -eq 0 ]]; then
            echo "SUCCESS - perfect match with reference"
            ec=0
        else
            CMPREF_F1=$(grep 'GLOB: mean all F1' "RunLogs/cmp_${frefbase}.log" | awk '{print$6}')
            local F1ok=$(echo "$CMPREF_F1 > 0.98" | bc -l)
            if (( F1ok )); then
                echo "NEAR PERFECT MATCH - F1 = $CMPREF_F1"
                ec=1
            else
                echo "FAILED - does not match perfectly with reference"
                ec=2
            fi
        fi
    else
	    EXTRA_INFO=" - but missing reference at $tsturl"
        echo "SUCCESS - but unable to compare result with reference"
    fi
    echo "----------------------------------------------------------------"
    echo
    return $ec
}
