#!/bin/bash
# 
# Testing the installation: the version, paths and number of extensions should be correct
# This test entirely depends on the CamitK version (version string, number of extensions...)
# (see the expectedConfigOutput)
# 
# For a CamiTK major or minor version please update the expected number and release date
# in function initTestData
# 
# echo $? get the last returned value of the script
# a return value of 0 indicates success (by convention)
# The value return by this script corresponds to the config test that failed
# (see log for config test id)
# 

set -e

# Uncomment next line to debug
# set -x

# ---------------------- initTestData ----------------------
# values to check
initTestData() {
    #-- fill test data arrays
    nextVersion="6.1"
    
    # Number of component, action and viewer extensions
    componentExtensionCount=( [$nextVersion]=15 [6.0]=15 [5.2]=15  [5.1]=14  [5.0]=14  [4.1]=14  [4.0]=14   )
    actionExtensionCount=(    [$nextVersion]=39 [6.0]=39 [5.2]=34  [5.1]=33  [5.0]=33  [4.1]=27  [4.0]=27   )
    viewerExtensionCount=(    [$nextVersion]=10 [6.0]=10 [5.2]=10  [5.1]=10  [5.0]=10                       )
    
    # Number of different file format/extension manages by the component extensions
    fileExtensionCount=(      [$nextVersion]=38 [6.0]=38 [5.2]=38  [5.1]=37  [5.0]=37  [4.1]=37  [4.0]=37   )
    
    # Number of actions provided by the action extensions
    actionCount=(             [$nextVersion]=131 [6.0]=131 [5.2]=115 [5.1]=111 [5.0]=111 [4.1]=105 [4.0]=105 )
    
    # Number of viewers managed by the viewer extensions
    viewerCount=(             [$nextVersion]=13 [6.0]=13 [5.2]=13  [5.1]=13  [5.0]=13                       )

    #-- extensionCount is just the sum of all three extension counts
    extensionCount=(          [$nextVersion]=$((componentExtensionCount[$nextVersion] + actionExtensionCount[$nextVersion] + viewerExtensionCount[$nextVersion]))
                              [6.0]=$((componentExtensionCount[6.0] + actionExtensionCount[6.0] + viewerExtensionCount[6.0]))
                              [5.2]=$((componentExtensionCount[5.2] + actionExtensionCount[5.2] + viewerExtensionCount[5.2]))
                              [5.1]=$((componentExtensionCount[5.1] + actionExtensionCount[5.1] + viewerExtensionCount[5.1]))
                              [5.0]=$((componentExtensionCount[5.0] + actionExtensionCount[5.0] + viewerExtensionCount[5.0]))
                              [4.1]=$((componentExtensionCount[4.1] + actionExtensionCount[4.1])) 
                              [4.0]=$((componentExtensionCount[4.0] + actionExtensionCount[4.0]))  )

    #-- Release date
    releaseDate=(             [$nextVersion]="not yet released, current development version" \
                              [6.0]="19 December 2025" \
                              [5.2]="15 February 2024" \
                              [5.1]="28 July 2023" \
                              [5.0]="30 April 2021" \
                              [4.1]="15 July 2018" \
                              [4.0]="22 July 2016" \
                              [3.5]="29 January 2016"
                              [3.4]="31 October 2014" \
                              [3.3]="4 March 2014" \
                              [3.2]="26 June 2013" \
                              [3.1]="1 March 2013" \
                              [3.0]="7 July 2012" )

}

# ---------------------- declareTestData ----------------------
declareTestData() {
    # declare all associative arrays (-g is to declare the arrays
    # in the global scope)
    declare -Ag extensionCount
    declare -Ag componentExtensionCount
    declare -Ag actionExtensionCount
    declare -Ag viewerExtensionCount
    declare -Ag fileExtensionCount
    declare -Ag actionCount
    declare -Ag viewerCount
    declare -Ag releaseDate
}

# ---------------------- cleanup ----------------------
# cleanup on exit
cleanup() {
    # backup the current exit status
    currentExitValue=$?
    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
    # cleanup current dir (but not build dir!)
    if [ "$inBuild" == "0" ]; then
        echo "Cleaning up working directory $workingDir..."
        rm -rf $workingDir
    fi
    # 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 ----------------------
# usage: checkcommand name 
checkcommand() {
    if [ "$inBuild" == "0" ] ; then
        # check if current build is on windows debug version
        if ! hash ${1} 2>/dev/null; then
            echo "Executable not found"
        else
            echo "[OK]"
        fi
    else
        if [ ! -x ${1} ] ; then 
            echo "File not found or not executable"
        else
            echo "[OK]"
        fi
    fi
}

# ---------------------- init ----------------------
init() {
    echo "========== checking camitk configuration =========="
    exitStatus=0 # nothing bad. By convention exit 0 indicates success

    if [ $# -lt 1 -o "$1" != "-inbuild" ] ; then
        echo "===== Testing installed version ====="
        inBuild=0
        workingDir=$(mktemp --tmpdir -d camitk-test-tmp.XXXXXXXXXX)
        cd $workingDir
        echo "===== Temporary directory created $workingDir ====="
        camitkConfig="camitk-config"        
    else
        # if -inbuild option is specified, then the next argument should be the build dir (as set by ${PROJECT_BINARY_DIR} by cmake
        workingDir=$2
        echo "===== Testing in build dir $workingDir ====="
        inBuild=1
        cd $workingDir
        camitkConfig="bin/camitk-config"
    fi

    echo "===== Check OS ====="
    unameOS=$(uname)
    if [[ "$unameOS" =~ ^MINGW64.* || "$unameOS" =~ ^MSYS_NT.* ]]; then
        osName="Windows"
    else
        osName="Linux"
    fi
    echo "===== Uname is $unameOS ===== OS is $osName ====="

    if [[ "$osName" != "Windows" ]]; then
        echo "===== Configuring xvfb ====="
        displayID=10
        # 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 "PID of Xvfb: $xvfbPid"
        export DISPLAY=:$displayID
        export XAUTHORITY=/dev/null
    fi

    # Checking config executable
    echo "===== Checking $camitkConfig ====="
    checkCamiTKConfig=$(checkcommand $camitkConfig)
    echo $checkCamiTKConfig
    if [ "$checkCamiTKConfig" != "[OK]" ] ; then
        if [[ "$osName" == "Windows" ]]; then
            camitkConfig=$camitkConfig-debug
            echo "===== Checking ${camitkConfig} ====="
            checkCamiTKConfig=$(checkcommand $camitkConfig)
            echo $checkCamiTKConfig
        fi
    fi
}

# ---------------------- getconfig ----------------------
getconfig() {
    # initialize config output
    echo "===== Get CamiTK configuration ====="
    $camitkConfig --config 2>/dev/null > ./config-output
    camitkConfig=$(cat config-output | sed "s/QStandardPaths.*'.*'//")

    echo "===== config-output ====="
    cat ./config-output

    echo "===== camitkConfig ====="
    echo $camitkConfig
}

# ---------------------- expected value ----------------------
getExpectedValue() {
  case "$1" in
    "Global Installation Directory")
      # for package test: it should always be /usr
      echo "/usr"
      ;;
    "Current Working Directory")
      # this is an upstream test, it should be ran in build dir (for windows, remplace ^/c by C:
      echo $(pwd) | sed -e "s+^/c+C:+"
      ;;
    "Number of Component Extensions")
      echo ${componentExtensionCount[$shortVersion]}
      ;;
    "Number of Action Extensions")
      echo ${actionExtensionCount[$shortVersion]}
      ;;
    "Number of Viewer Extensions")
      echo ${viewerExtensionCount[$shortVersion]}
      ;;
    "Number of File Extensions Supported")
      echo ${fileExtensionCount[$shortVersion]}
      ;;
    "Number of Actions")
      echo ${actionCount[$shortVersion]}
      ;;
    "Number of Viewers")
      echo ${viewerCount[$shortVersion]}
      ;;
  esac
}

# ---------------------- getInstalledVersion ----------------------
getInstalledVersion() {
  echo $(echo $camitkConfig | head --lines=1 | cut -f5 -d" ")
}

# ------------------- getReleaseDate -------------------
getReleaseDate() {
    if [ ! ${releaseDate[$1]+validCamiTKVersion} ]; then
      echo "unknown version"
    else
        echo ${releaseDate[$1]}
    fi
}

# ---------------------- extension count ----------------------
getExtensionCount() {
  echo $(echo "$camitkConfig" | grep "^  - \[$1\] " | wc -l)
}

getExpectedExtensionCount() {
  echo ${extensionCount[$1]}
}

# ---------------------- get config ----------------------
# get a specific value from config, text to parse from
# camitk-config --config is the first parameter of the function
# get the value after the string "... " and before the first space
getConfigValue() {
  echo $(echo "$camitkConfig" | grep "$1" | sed 's/^.*\.\.\. //g' | cut -f1 -d" ")
}

# ---------------------- check value ----------------------
# use camitk-config to check a value and compare to 
# expected value
checkValue() {
  checkedValue="$1"
  value=$(getConfigValue "$checkedValue")
  echo "===== $checkValueId- $checkedValue: $value ====="
  expected=$(getExpectedValue "$checkedValue")
  if [ "$value" != "$expected" ]; then
    echo "Error: unexpected $checkedValue (found $value vs $expected expected)"
    exitStatus=$checkValueId
  else
    echo "OK"
  fi
  # 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

declareTestData
initTestData
init $*
getconfig

detectedVersion=$(getInstalledVersion)
shortVersion=$(echo $detectedVersion | cut -f1,2 -d".")
echo "===== 1- Detected installed CamiTK version is: [$detectedVersion] aka [$shortVersion] ====="
releaseDate=$(getReleaseDate $shortVersion)
if [ "$releaseDate" = "unknown version" ]; then
  echo -n "Error: unknown version "
  exitStatus=1
else
  echo -n "OK "
fi
echo "(release date: $releaseDate)"

if [ "$inBuild" == "0" ] ; then
  extensionRepository="G" # check for globally installed extension
else
  extensionRepository="W" # check extension in current build dir
fi

value=$(getExtensionCount $extensionRepository)
echo "===== 2- Number of extensions: $value ====="
expected=$(getExpectedExtensionCount $shortVersion)
if [ "$value" -ne "$expected" ]; then
  echo "Error: unexpected number of globally installed extensions (found $value vs $expected expected)"
  exitStatus=1
else
  echo "OK"
fi

# init the id (next test is the third test)
checkValueId=3
if [ "$inBuild" == "0" ] ; then
  checkValue "Global Installation Directory"
else
  checkValue "Current Working Directory"
fi
checkValue "Number of Component Extensions"
checkValue "Number of Action Extensions"
checkValue "Number of Viewer Extensions"
checkValue "Number of File Extensions Supported"
checkValue "Number of Actions"
checkValue "Number of Viewers"

exit $exitStatus
