#!/bin/bash
set -e

### cross format read/(write) test ###

PNAME=${PNAME:-./gpsbabel}
BASEPATH=`dirname $0`
REFGPX="${BASEPATH}/reference/expertgps.gpx"	# reference file for all tests
EXCL="exif ozi vitosmt xol navigonwpt gopal"	# exclude formats from test
CAPS=""
TEMPDIR=${GBTEMP:-/tmp}/gb-test-all
CATALOG=${GBTEMP:-/tmp}/gb-test-all.done
LOGFILE=${GBTEMP:-/tmp}/gb-test-all.log
RNDFILE=${GBTEMP:-/tmp}/gb-random.gpx

# options
vg=0
prep=0
tally=0
judge=0

function tally_log()
{
    local exceptions=`grep '^cmd([0-9]*)\*[*]*:' $LOGFILE | wc -l`
    local onlyunexpected=`grep '^cmd([0-9]*)\*:' $LOGFILE | wc -l`
    local nonfatals=`grep '^cmd([0-9]*)\*\*:' $LOGFILE | wc -l`
    local fatals=`grep '^cmd([0-9]*)\*\*\*:' $LOGFILE | wc -l`
    local totals=`grep '^cmd([0-9]*)[*]*:' $LOGFILE | wc -l`
    echo "Fatal Error Cases:"
    grep '^cmd([0-9]*)\*\*\*:' $LOGFILE || true
    echo ""
    echo Error Summary:
    echo "tests with errors and/or unexpected output: $exceptions"
    echo "  tests without error but with unexpected output: $onlyunexpected"
    echo "  tests with non-fatal errors: $nonfatals"
    echo "  tests with fatal errors: $fatals"
    echo "total tests: $totals"
    if [ $fatals -gt 0 ]; then
        return 1
    else
        return 0
    fi
}

function log_entry()
{
    touch $LOGFILE
    echo "-----------------------------------------------------------------------" >> ${LOGFILE}
    date >> ${LOGFILE}
    echo "$*" >> ${LOGFILE}
}

function try_run() # command line
{
    local CMD="$*"
    local RES=0
    local SEVERITY=""
    
    [ $vg -ne 0 ] && CMD="valgrind -q $CMD"

    ${CMD} > $TEMPDIR/.result 2>&1
    RES=$?
    if [ $RES -ne 0 -o -s $TEMPDIR/.result ]; then
        if [ $RES -ne 0 ]; then
            echo " -- Signal $RES --"
            if [ -s $TEMPDIR/.result ]; then
                echo "---------------------------output-follows------------------------------"
                cat $TEMPDIR/.result
                echo "-----------------------------------------------------------------------"
            fi
        else
            echo " -- unexpected output exists, see $LOGFILE --"
        fi
        if [ $RES -gt 128 ]; then
            SEVERITY="***"
        elif [ $RES -gt 0 ]; then
            SEVERITY="**"
        else
            SEVERITY="*"
        fi
        log_entry "cmd($RES)$SEVERITY: $CMD"
        test -s $TEMPDIR/.result && cat $TEMPDIR/.result >> ${LOGFILE}
        return 1
    else
        log_entry "cmd($RES): $CMD"
        return 0
    fi
}

function STAGE_1 () # type format
{
    local TYP=$1
    local FMT=$2
    local CMD1 CMD2 IFILE OFILE
    
    echo "$CAPS" |
    
    while read type caps format comment; do
    
        for i in $EXCL; do
            if [ "$format" == "$i" ]; then
            caps="------"
            fi
        done
        
        grep "$TYP: $FMT & $format" ${CATALOG} > /dev/null && continue
        
        echo -n "testing "
        case $TYP in
            w)
            echo -n "waypoints"
            caps=${caps:0:2}
            ;;
            t)
            echo -n "tracks"
            caps=${caps:2:2}
            ;;
            r)
            echo -n "routes"
            caps=${caps:4:2}
            ;;
        esac

        echo -n ": \"$FMT\" with \"$format\" "
        
        IFILE=$TEMPDIR/$TYP-$FMT
        OFILE=$TEMPDIR/$TYP-$FMT.$format
        
        case $caps in
            -w)
            echo -n "*"
            CMD1="${PNAME} -$TYP -i $FMT -f $IFILE -o $format -F $OFILE"
            try_run "${CMD1}" || continue
            ;;
            
            rw)
            echo -n "*"
            CMD1="${PNAME} -$TYP -i $FMT -f $IFILE -o $format -F $OFILE"
            try_run "${CMD1}" || continue
            echo -n "*"
            CMD2="${PNAME} -$TYP -i $format -f $OFILE -o $FMT -F $OFILE.$FMT"
            try_run "${CMD2}" || continue
            ;;
        esac
        
        echo "*"
        echo "$TYP: $FMT & $format" >> $CATALOG
    done
    return 0
}

function STAGE_0 ()
{
    echo "$CAPS" |
    
    while read type caps format comment; do
    
    for i in $EXCL; do
        if [ "$format" == "$i" ]; then
            caps="------"
        fi
    done
    
    case ${caps:0:2} in
        rw)
        CMD="${PNAME} -i gpx -f $REFGPX -x nuketypes,routes,tracks -o $format -F $TEMPDIR/w-$format"
        try_run "${CMD}" || continue
        STAGE_1 "w" $format || exit 1
        ;;
        -w)
        CMD="${PNAME} -i gpx -f $REFGPX -x nuketypes,routes,tracks -o $format -F $TEMPDIR/w-$format"
        try_run "${CMD}" || continue
        ;;
    esac
    case ${caps:2:2} in
        rw)
        CMD="${PNAME} -t -i gpx -f $REFGPX -x nuketypes,waypoints,routes -x track,fix=2D -o $format -F $TEMPDIR/t-$format"
        try_run "${CMD}" || continue
        STAGE_1 "t" $format || exit 1
        ;;
        -w)
        CMD="${PNAME} -t -i gpx -f $REFGPX -x nuketypes,waypoints,routes -x track,fix=2D -o $format -F $TEMPDIR/t-$format"
        try_run "${CMD}" || continue
        ;;
    esac
    case ${caps:4:2} in
        rw)
        CMD="${PNAME} -r -i gpx -f $REFGPX -x nuketypes,waypoints,tracks -o $format -F $TEMPDIR/r-$format"
        try_run "${CMD}" || continue
        STAGE_1 "r" $format || exit 1
        ;;
        -w)
        CMD="${PNAME} -r -i gpx -f $REFGPX -x nuketypes,waypoints,tracks -o $format -F $TEMPDIR/r-$format"
        try_run "${CMD}" || continue
        ;;
    esac
    done
    rm -f $TEMPDIR/.result
}

while [ $# -gt 0 ]; do
    case $1 in
    -s|--start)	# remove catalog. run the full test.
        rm -f $CATALOG
        ;;
    -v|--valgrind)
        vg=1
        ;;
    -p|--prepare)	# prepare for valgrind check.
        prep=1
        ;;
    -c|--clean)
        trap "rm -fr $TEMPDIR; exit 1" 0 1 2 3 15
        ;;
    -n|--random)
        ${PNAME} -i random -w -f - -i random,points=48 -r -f - -i random,points=120 -t -f - -o gpx,gpxver=1.1 -F $RNDFILE
        REFGPX=$RNDFILE
        ;;
    -r|--reference)
        shift
        REFGPX=$1
        ;;
    -j|--judge)	# implies tallying so we have something to judge.
        tally=1
        judge=1
        ;;
    -J|--rejudge)	# re-judge a previous run and exit without running more tests.
        tally=1
        judge=1
        tally_log
        exit $?
        ;;
    -t|--tally)
        tally=1
        ;;
    -T|--retally)	# re-tally a previous run and exit without running more tests.
        tally=1
        tally_log
        exit 0
        ;;
    -W|--wipe)	# clean up files and exit
        rm -rf $TEMPDIR > /dev/null
        rm -f $CATALOG
        rm -f $LOGFILE
        rm -f $RNDFILE
        exit 0
        ;;
    esac
    shift
done

if [ $prep -ne 0 ]; then
    test -s Makefile && make clean
    CFLAGS="-O0" ./configure || exit 1	#  -O0 is suggested by vg.
    make || exit 1
    echo "All fine. You can do now a 'test-all -v'"
    exit 0
fi

if test ! -s $REFGPX; then
    echo "GPX reference \"$REFGPX\" doesn't exist!"
    exit 1
fi

rm -rf $TEMPDIR > /dev/null
mkdir -p $TEMPDIR > /dev/null
rm -f $LOGFILE
touch $LOGFILE
touch $CATALOG

log_entry "test-all started."
echo "Catalog: $CATALOG" >> $LOGFILE

CAPS=`${PNAME} -^2 | grep "^file"`
STAGE_0
if [ $tally -ne 0 ]; then
    tally_log
    judgement=$?
    if [ $judge -ne 0 ]; then
        exit $judgement
    fi
fi
exit 0
