#!/bin/bash
# Testing the installation of the dev tools
# cepgenerator and devtools
# 
# echo $? get the last returned value of the script
#
# TODO add complete library tests using cepgenerator
# This can be done using exampleLibraryAction.xml 
# + adding a real action in there 
# + adding a component
# + adding a test file
# + adding source code files :
#   ActionDoSomething.cpp in 
#   EmptyComponent.cpp to use the library
#   EmptyLibrary.h EmptyLibrary.cpp
# + add "echo "#include "ActionDoSomething.cpp"" >> actions/emptyaction/Action.cpp"
# and compile only then
# @see the shaker lib turorial
#
# TODO add a complete example with all the possible Property types
# @see the property tutorial
#
# TODO add another family of tests using testaction and testcomponent on cepgenerated action/components
#
# TODO distribute all the files from the ./sdk/applications/cepgenerator/testdata directory 
# in the package $(pkg-dev) so that they are installed in /usr/share/camitk-$(VER_SHORT)/testdata/cepgenerator/*
# In this script, just copy all files from /usr/share/camitk-$(VER_SHORT)/testdata/cepgenerator/* to the tmpdir
# and run a foreach on each .xml files

set -e

# Uncomment next line to debug
set -x

#DEBUG
#To test with different library versions, you can use different install path, for instance:
# CMAKE_OPTIONS="-DVTK_DIR:PATH=/opt/vtk6/lib/cmake/vtk-6.3 -DITK_DIR:PATH=/opt/vtk6/lib/cmake/ITK-4.9 -DGDCM_DIR:PATH=/opt/vtk6/lib/gdcm-2.6"

# ---------------------- cleanup ----------------------
cleanup() {
    # cleanup on exit

    # backup the current exit status
    currentExitValue=$?
    echo
    echo "*** Cleaning up before exiting..."
    echo
    if [[ "$osName" != "Windows" ]]; then
        # kill the xfvb if still exist
        if [ -f /proc/$xvfbPid/status ]; then
            echo "Killing running xvfb server (pid $xvfbPid)..."
            kill $xvfbPid    
        fi        
    fi
    if [ "$currentExitValue" -ne "0" ]; then
        echo
        echo "*** Test failed "
        echo
        # output all possible files
        cd $workingDir
        # Test exist status of every file and directory otherwise the script abort and the temp directory is not removed
        if [ -f "./generated-$testDirName" ]; then
            echo "===== FAILED generated-$testDirName ====="
            cat ./generated-$testDirName
            echo "[FAIL] generation"
        else 
            echo "===== File $workingDir/generated-$testDirName not found ====="
        fi
        if [ -d "$testDirName/build" ]; then
            cd $testDirName/build
            if [ -f "../cmake-log" ]; then
                echo "===== FAILED cmake-log ====="
                cat ../cmake-log
            else
                echo "===== File $testDirName/build/../cmake-log not found ====="
            fi
            if [ -f "../cmake-error" ]; then
                echo "===== FAILED cmake-error ====="  
                cat ../cmake-error
                echo "[FAIL] CMake configuration"
            else
                echo "===== File $testDirName/build/../cmake-error not found ====="
            fi
            if [ -f "../make-log" ]; then
                echo "===== FAILED make-log ====="
                cat ../make-log                
            else
                echo "===== File $testDirName/build/../make-log not found ====="
            fi
            if [ -f "../make-error" ]; then
                echo "===== FAILED make-error ====="  
                cat ../make-error
                echo "[FAIL] Build"
            else
                echo "===== File $testDirName/build/../make-error not found ====="
            fi
        else
            echo "===== Directory $workingDir/$testDirName/build not found ====="            
        fi
        cd
    fi
    # finally cleanup working dir
    echo "Cleaning up working directory $workingDir..."
    rm -rf $workingDir
    # use the backup value (otherwise the result of the "rm -rf" command above will
    # be used, and that's probably always 0 !)
    exit $currentExitValue
}

# ---------------------- checkcommand ----------------------
checkcommand() {
    # usage: checkcommand name 
    if [ "$inBuild" == "0" ] ; then
        # check if current build is on windows debug version
        if ! hash ${1} 2>/dev/null; then
            echo "[FAIL] Error: executable not found"
        else
            echo "[OK]"
        fi
    else
        if [ ! -x ${1} ] ; then 
            echo "[FAIL] Error: file not found or not executable"
        else
            echo "[OK]"
        fi
    fi
}

# ---------------------- init ----------------------
init() {
    echo
    echo "*** Checking configuration..."
    echo
    exitStatus=0 # nothing bad. By convention exit 0 indicates success
    checkValueId=1 # test id starts at 1

    echo "===== Test script directory ====="
    scriptDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
    echo "[OK] Test script directory is $scriptDir"

    echo "===== Creating temporary test directory ====="
    workingDir=$(mktemp --tmpdir -d camitk-test-tmp.XXXXXXXXXX)
    echo "[OK] Temporary test directory set to $workingDir"
    
    echo "===== Checking test parameters ====="
    totalNbOfArguments=$#
    nbOfParameters=$((totalNbOfArguments-1))
    echo "[OK] Test launch with $nbOfParameters parameters: \"$1\" and \"$2\""

    echo "===== CamiTK environment ====="
    if [ $# -lt 1 -o "$1" != "-inbuild" ] ; then
        echo "[OK] Test using installed CamiTK version"
        inBuild=0
        # for installed camitk, just run the corresponding executables
        camitkGenerator=camitk-cepgenerator
        camitkConfig=camitk-config
    else
        echo "[OK] Test using inbuild directory \"$2\" (source code in \"$3\")"
        # if -inbuild option is specified, then the next argument should be the build dir (as set by ${PROJECT_BINARY_DIR} by cmake
        inBuild=1
        # for in build test, use specific path for executables
        camitkGenerator=$2/bin/camitk-cepgenerator
        camitkConfig=$2/bin/camitk-config
        # specify CamiTK dir 
        # Although it is not an install dir, it is better to use the build dir than to temporary installed, test and uninstall
        export CAMITK_DIR=$2
        # Add extra cmake module path to find the CMake macros that are indeed not installed in the build dir
        CMAKE_OPTIONS="$CMAKE_OPTIONS -DCMAKE_MODULE_PATH:PATH=$3/sdk/cmake/modules;$3/sdk/cmake/modules/macros"
    fi

    echo "===== Checking OS ====="
    unameOS=$(uname)
    if [[ "$unameOS" =~ ^MINGW64.* || "$unameOS" =~ ^MSYS_NT.* ]]; then
        osName="Windows"
    else
        osName="Linux"
    fi
    echo "[OK] uname is $unameOS → Test on OS $osName"

    if [[ "$osName" != "Windows" ]]; then
        echo "===== Configuring xvfb ====="
        displayID=15
        # Starts the server first (to avoid a distracting warning output due to OpenGL context)
        Xvfb :$displayID -screen 0 1600x1200x24 -ac +extension GLX +render -noreset -v -fbdir $workingDir/ &
        xvfbPid=$!
        echo "[OK] PID of Xvfb: $xvfbPid"
        export DISPLAY=:$displayID
        export XAUTHORITY=/dev/null
    fi    

    # Checking if current build is on windows debug version
    echo "===== Checking camitk-config ====="
    checkCamiTKConfig=$(checkcommand $camitkConfig)
    if [ "$checkCamiTKConfig" != "[OK]" ] ; then
        if [[ "$osName" == "Windows" ]]; then
            camitkConfig=$camitkConfig-debug
            echo "===== Checking camitk-config-debug ====="
            checkCamiTKConfig=$(checkcommand $camitkConfig)
            echo "$checkCamiTKConfig"
            if [ "$checkCamiTKConfig" != "[OK]" ] ; then            
                echo "[FAIL] Error: cannot find camitk-config nor camitk-config-debug"
            else
                buildType="Debug"
            fi
        fi
    else
        echo "[OK] executable camitk-config found"
        buildType="Release"
    fi

    if [[ "$osName" == "Windows" ]]; then
        echo "==== Windows build type ===="
        echo "$buildType"
    fi
    
    echo "===== camitk-config configuration ====="
    echo "[OK] using $camitkConfig on $osName"

    echo "===== Checking camitk-generator ====="
    checkCamiTKGenerator=$(checkcommand $camitkGenerator)
    if [ "$checkCamiTKGenerator" != "[OK]" ] ; then
        if [[ "$osName" == "Windows" ]]; then
            camitkGenerator=$camitkGenerator-debug
            echo "===== Checking camitk-generator-debug ====="
            checkCamiTKGenerator=$(checkcommand $camitkGenerator)
            echo "$checkCamiTKGenerator"
        fi
    else
        echo "[OK] executable camitk-generator found"
    fi
    echo "===== camitk-generator configuration ====="
    echo "[OK] using $camitkGenerator on $osName"
    
}

# ---------------------- getConfig ----------------------
getConfig() {
  $camitkConfig --config 2>/dev/null # | sed "s/QStandardPaths.*'.*'//"
}

# ---------------------- generateConfigureAndMake ----------------------
getWorkingDirExtensionCount() {
  echo $(getConfig | grep "^  - \[W\] " | wc -l)
}

# ---------------------- generateConfigureAndMake ----------------------
generateConfigureAndMake() {
  # generate
  testDirName=$(basename $1 .xml)
  echo
  echo "*** $checkValueId.1 Generate, configure and build $testDirName..."
  echo
  echo "===== Generating source code from XML... ====="
  cd $workingDir
  rm -rf $testDirName
  mkdir $testDirName
  $camitkGenerator -f $1 -d $workingDir/$testDirName > ./generated-$testDirName
  if [ -s ./generated-$testDirName ] ; then
    cat ./generated-$testDirName
  fi

  cd $testDirName
  # get the created dir name
  srcDirName=$(ls)
 
  # check if there is a library (in this case copy dummy test lib to the given library name source dir
  if [ "$#" == 2 ]; then
    echo "===== Adding library code... ====="
    cp ../TestLib.* $srcDirName/libraries/$2
  fi

  # configure
  mkdir build
  cd build
  echo "===== Configuring... ====="
  if [[ "$osName" == "Windows" ]]; then
    # choose the default msvc version and config from current install
    cmake $CMAKE_OPTIONS -Wno-dev  ../$srcDirName > ../cmake-log 2> ../cmake-error
  else
    cmake $CMAKE_OPTIONS ../$srcDirName > ../cmake-log 2> ../cmake-error
  fi
  if [ -s ../cmake-log ] ; then
    echo "===== cmake log ====="
    cat ../cmake-log
  fi
  if [ -s ../cmake-error ] ; then
    echo "===== cmake error log ====="  
    cat ../cmake-error
  fi

  echo "===== building... ====="
  if [[ "$osName" == "Windows" ]]; then
    cmake --build . --config $buildType --parallel 9 > ../make-log 2> ../make-error
  else
    # build (parallel)
    make -j9 > ../make-log 2> ../make-error
  fi
  if [ -s ../make-log ] ; then
    echo "===== make log ====="
    cat ../make-log
  fi
  if [ -s ../make-error ] ; then
    echo "===== make error log ====="  
    cat ../make-error
  fi
}

# ---------------------- testcepfile ----------------------
# @param xmlfile
# @param expected number of created extensions
testcepfile() {
  generateConfigureAndMake $1 $3
  expectedValue="$2"

  echo
  echo "*** $checkValueId.2 Checking $1 installation..."
  echo

  # check if everything is compiled and can be loaded
  value=$(getWorkingDirExtensionCount)
  echo "Number of extensions for $1: $value found ($expectedValue expected)"
  echo "$(getConfig | grep "^  - \[W\] ")"
  if [ "$value" -ne "$expectedValue" ]; then
    echo "[FAIL] Error: unexpected number of extensions installed in the working directory ($value != $expectedValue)"
    exitStatus=$checkValueId
  else
    echo "[OK]"
  fi
  echo
  # increase id
  checkValueId=$((checkValueId+1))
}

# --------------------------------------------------------------------------
#
# All tests are here
#
# --------------------------------------------------------------------------

# if a problem occurs, call the clean method
trap "cleanup" 0 INT QUIT ABRT PIPE TERM EXIT

init $*
cd $workingDir
$scriptDir/generate-coreschema-files.sh
$scriptDir/generate-cpp-files.sh

#testcepfile cep.xml nrOfExpectedNewExtensions
testcepfile actionAndComponentUsingViewerExtension.xml 2

# test that is too difficult to manage on Windows
# TODO: describe the reason why it is not easy to perform it on Windows
if [[ "$osName" == "Windows" ]]; then
    echo "[OK] Windows: skip testing cep with lib"
else
    testcepfile completeTest1.xml 3 testlib
fi

testcepfile exampleComponents.xml 2
testcepfile actionsExamplesLicence.xml 2
testcepfile actionsExamplesNoLicence.xml 2
testcepfile actionAndComponent.xml 2
testcepfile empty.xml 0 
testcepfile viewerExample.xml 2

exit $exitStatus
