#!/bin/bash
# This script checks the Fortran code of the solver corresponding to this directory.
# Usage: flint [--compiler_name [--all]] or flint -c|--clean

# Parse inputs.
if ! [[ $# -eq 0 || $# -eq 1 || $# -eq 2 ]] ; then
    printf "Usage: flint [--compiler_name [--all]] or flint -c|--clean\n"
    exit 2
fi

TEST_ALL="N"
CLEAN="N"

# sunf95 is case sensitive. Put it as the first.
# ifx encounters internal errors when compiling BOBYQA. Disable xtest for now.
# Disable ntest and atest for now, since they encounter internal/licensing errors randomly
#COMPILER_LIST=(sunf95 gfortran nagfor g95 af95 ifort nvfortran flang aflang ifx)
#CLIST=(s g n 9 a i v f d x)
printf "\n****** XTEST is disabled ******\n"
printf "\n****** NTEST is disabled ******\n"
printf "\n****** ATEST is disabled ******\n"

COMPILER_LIST=(sunf95 gfortran g95 ifort nvfortran flang aflang)
CLIST=(s g 9 i v f d)
COMP_LIST=""
for i in "${!COMPILER_LIST[@]}"; do
   if  type "${COMPILER_LIST[$i]}" &> /dev/null ; then
       COMP_LIST="$COMP_LIST ${CLIST[$i]}"
   fi
done

# Parse the arguments
while [[ -n "$1" ]]; do
    case "$1" in
        --all)
            TEST_ALL="Y"
            ;;
        --clean)
            CLEAN="Y"
            ;;
        -g|--gfortran)
            COMP_LIST=" g"
            ;;
        -i|--ifort)
            COMP_LIST=" i"
            ;;
        -n|--nagfor)
            COMP_LIST=" n"
            ;;
        -a|--absoft)
            COMP_LIST=" a"
            ;;
        -9|--g95)
            COMP_LIST=" 9"
            ;;
        -s|--sunf95)
            COMP_LIST=" s"
            ;;
        -v|--nvfortran)
            COMP_LIST=" v"
            ;;
        -f|--flang)
            COMP_LIST=" f"
            ;;
        -d|--aflang)
            COMP_LIST=" d"
            ;;
        -x|--ifx)
            COMP_LIST=" x"
            ;;
        *)
            printf "Usage: flint [--compiler_name [--all]] or flint -c|--clean\n"
            exit 2
            ;;
    esac
    shift
done

# The default Fortran compiler options.
FFLAGS=''
# We export FFLAGS, which will be referred to by the Makefiles.
export FFLAGS

# The directory where this script resides. It is the solver's directory.
SOLVER_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"

# The solver's name.
SOLVER=$(basename "$SOLVER_DIR")

# The log directory in the solver's directory.
SOLVER_LOG_DIR="$SOLVER_DIR"/flog

# Root directory of this project.
ROOT_DIR=../..

# The testing directory.
TIME=$(date +%s)
RANDNUM="$((RANDOM*RANDOM))"
TEST_DIR=/tmp/"$(basename -- "$0")"_"$TIME"_"$RANDNUM"
printf  "Test directory:\n\n%s\n" "$TEST_DIR"
# We export TEST_DIR, which will be referred to by the Makefiles.
export TEST_DIR
TEST_ROOT="$TEST_DIR"/prima
FTEST_DIR="$TEST_ROOT"/fortran/tests
FTEST_SOLVER_DIR="$FTEST_DIR"/test."$SOLVER"

# The log directory in the testing directory.
TEST_LOG_DIR="$FTEST_SOLVER_DIR"/log

# The checktest script
CHCKTST="$FTEST_DIR"/checktest

# Remove the old logs.
mkdir -p "$SOLVER_LOG_DIR"
rm -f "$SOLVER_LOG_DIR"/*test*.log

# Conduct the test.
cd "$ROOT_DIR"/fortran/tests || exit 1

# Make clean (old logs in $SOLVER_LOG_DIR have been cleaned up in the above).
printf "\nCleaning up ... "
make cleanall."$SOLVER" > /dev/null
printf "Done.\n\n"

if [[ "$CLEAN" == "Y" ]] ; then
    exit 0
fi

# Check whether this is a 32-bit ARM machine (e.g., Raspberry Pi with 32-bit OS).
if [[ "$(uname -m)" = "aarch" || "$(uname -m)" = armv7* ]] ; then
    ARM32='Y'
else
    ARM32='N'
fi

printf "Tests to make:%s\n\n" "$COMP_LIST"

for COMP in $COMP_LIST; do
    if [[ $TEST_ALL == 'Y' && $ARM32 != 'Y' ]] ; then
        make  "$COMP"test_c."$SOLVER"
    else
        if [[ $COMP == 'f' || $COMP == 'v' || $COMP == 'd' || $COMP == 'x' || $ARM32 == 'Y' ]] ; then
            TESTS="i2_r4_d1 i8_r4_d0"
        else
            TESTS="i2_r16_d1 i8_r4_d0"
        fi
        for TEST in $TESTS ; do
            INFO="$(make "$COMP"test_"$TEST"_tst_c."$SOLVER" \
                | grep -i "starts\|warning\|error\|info\|abort\|invalid\|violation\|fault\|illegal\|fail\|questionable\|remark\|attention\|Could\ not\ resolve\|not\ defined\|not\ public\ entity" \
                | grep -vi "[0-9]\s*warning\|[0-9]\s*error\|[0-9]\s*info\|infos.f90\|information\|--warning\|--error" \
                | grep -vi "pedantic-errors\|Werror\|warn\ errors\|diag-error-limit\|colour=error\|rounding\ error" \
                | grep -v "^- \|^| \|^\* \|^+ \|^X \|\# " \
                )"
            echo "$INFO" | grep -i --color "starts\|warning\|error\|info\|abort\|invalid\|violation\|fault\|illegal\|fail\|questionable\|remark\|attention\|Could\ not\ resolve\|not\ defined\|not\ public\ entity"
            if echo "$INFO" | grep -iq "error\|abort\|invalid\|violation\|fault\|illegal\|fail\|Could\ not\ resolve\|not\ defined\|not\ public\ entity" ; then
                if [[ -f "$TEST_LOG_DIR"/"$COMP"test_"$TEST"_tst_c.log ]] ; then
                    LOGFILE="$COMP"test_"$TEST"_tst_c.log
                else
                    LOGFILE="$COMP"test_c.log
                fi
                mv "$TEST_LOG_DIR"/"$LOGFILE" "$SOLVER_LOG_DIR"
                cat "$SOLVER_LOG_DIR"/"$LOGFILE"
                exit 2
            fi
        done
    fi
    mv "$TEST_LOG_DIR"/"$COMP"test*.log "$SOLVER_LOG_DIR"
done

# Check the logfiles
LOGFILES=("$SOLVER_LOG_DIR"/*test*.log)
if [[ "$TEST_ALL" == "Y" ]] ; then
    for LOGFILE in "${LOGFILES[@]::${#LOGFILES[@]}}" ; do
        printf "\nChecking %s ...\n" "$LOGFILE"
        INFO="$(bash "$CHCKTST" --warnerror "$LOGFILE")"
        printf "%s" "$INFO"
        printf "\nDone!\n"
        if [[ -n "$INFO" ]] ; then
            printf "\nWarning or error found in log file.\n"
            exit 1
        fi
    done
else
    for LOGFILE in "${LOGFILES[@]::${#LOGFILES[@]}-1}" ; do
        printf "\nChecking %s ...\n" "$LOGFILE"
        bash "$CHCKTST" --error "$LOGFILE"  # Will lead to failure in case of error logged
        INFO="$(bash "$CHCKTST" --warning "$LOGFILE")"
        printf "%s" "$INFO"
        printf "\nDone!\n"
        if [[ -n "$INFO" ]] ; then
            read -n1 -s -r -p $'Continue? [Y/n] ' KEY
            printf "\n"
            if ! [[ "$KEY" == 'Y' || "$KEY" == 'y' || "$KEY" == "" ]]; then
                exit 0
            fi
        fi
    done
    # No pause needed for the last logfile.
    LOGFILE="${LOGFILES[-1]}"  # The last logfile; it needs Bash 4.x.
    printf "\nChecking %s ...\n" "$LOGFILE"
    bash "$CHCKTST" --error "$LOGFILE"  # Will lead to failure in case of error logged
    INFO="$(bash "$CHCKTST" --warning "$LOGFILE")"
    printf "%s" "$INFO"
    printf "\nDone!\n\n"
fi

rm -rf "$TEST_DIR"
export -n TEST_DIR && unset TEST_DIR  # De-export and unset TEST_DIR

export -n FFLAGS && unset FFLAGS  # De-export and unset FFLAGS

exit 0
