#!/bin/sh -T

#
# variable name convention: 
# lowcase - local (block/function), ProperCase - script-wide global, ALL_CAPS - system-wide environment or export
#
# --------------------------------------------------------------------------------------------
# logging utils 
# --------------------------------------------------------------------------------------------
# Ensure logs are readable
umask 002

#------------------- 1 ---- 2 ----- 3 ---- 4 ---- 5 ------ 6 ------- 7 --- 8 ---
PocoLogLevelsList="fatal critical error warning notice information debug trace"
WMC_LogLevelsList="FATAL CRITICAL ERROR WARN NOTICE INFO DEBUG TRACE"

# initial value
LogLevel=${WMC_LogLevel:-6}

# NON-CHECKED VERSION. USE log_error, log_info, etc INSTEAD
# First param SHALL be log level, e.g. ERROR, INFO, etc. If missed it will eat the message silently
logmsg() {
    level=$1
	shift
    count=1
    for w in $WMC_LogLevelsList; do
        [ ".$w" = ".$level" ] && echo "[`date +'%Y-%m-%d %H:%M:%S'`] [$level] $Prog> $@"
        [ $count -eq $LogLevel ] && break
        count=$(($count+1))
    done
}

# most popular:
log_fatal()  { logmsg FATAL "$@"; }
log_critical()  { logmsg CRITICAL "$@"; }
log_error()  { logmsg ERROR "$@"; }
log_warn()   { logmsg WARN "$@";  }
log_notice() { logmsg NOTICE "$@";  }
log_info()   { logmsg INFO "$@";  }
log_debug()  { logmsg DEBUG "$@"; }
log_trace()  { logmsg TRACE "$@"; }

# params: $exit_code $message First parameter is optional (default to 1)
die() {
    # check and fix first parameter. Expected to be the error code
    rc=`echo $1 | sed -ne '/^[[:digit:]]*$/ p'`
    if [ -z "$rc" ]; then
        rc=1
    else
        shift
    fi
	# adding word [ERROR] so one could easily grep for FATAL *or* ERROR
    logmsg FATAL "[ERROR]" "=$rc>" "$@"
    exit $rc    # trap 0 assumed
}


# --------------------------------------------------------------------------------------------
# Working directory tree definition: use cmdline like the following to overwrite default behavior:
# --------------------------------------------------------------------------------------------
#    WMC_WD=. sh ../ThisScript.sh
#
Prog=`basename $0 .sh`
Bin=`echo $0 | sed -e 's:^.* ::g'`       # remove leading tokens till last whitespace, eg "sudo /bin/myscript.sh"
if [ -f $Bin ]; then
    Bin=`dirname $Bin`       # remove leading tokens till last whitespace, eg "sudo /bin/myscript.sh"
else
    # smth goes completely wrong... use `pwd` at last resort
    log_warn "Bin=$Bin seems to be incorrect, will use pwd instead"
    Bin=`pwd`
fi
Bin=`realpath $Bin` || die $? "Failed to determine the binaries' location (realpath)"
WMC_WD=${WMC_WD:-"$Bin"}

logmsg DEBUG "Bin = $Bin"
logmsg DEBUG "WMC_WD = $WMC_WD"
logmsg DEBUG "Prog = $Prog"

#
# Property file is shared by the whole package
# Package name is the same as the main executable in the package
# By default, the property file is installed with a package and located in Bin
#
PropertyFile=$Bin/$Prog.properties
logmsg DEBUG "PropertyFile = $PropertyFile"

# --------------------------------------------------------------------------------------------
# Read default property file and set logging level
# --------------------------------------------------------------------------------------------
if [ -r $PropertyFile ]; then
	log_debug "Property file $PropertyFile found"
    log_level=`sed -ne '/^logging.loggers.root.level[[:space:]].*=[[:space:]].*/ s/.*=[[:space:]]//g p' $PropertyFile`
	log_debug "log_level=$log_level"
    if [ ".$log_level" != "." ]; then 
        LogLevel=1
        for w in $PocoLogLevelsList; do
            [ ".$w" != ".$log_level" ] || break
            LogLevel=$(($LogLevel+1))
        done
    fi
fi



# <--! stubs; overwrite this in the main script body
Options() {
    return 1
}

Finalize() {
    return 0
}
# -->

# log-level and working-dir options will overwrite LogLevel and WMC_WD variables
OPT_DryRun=
OPT_WorkingDir=
OPT_LogLevel=
BaseOptions() {
    case $1 in
        l|log-level)    
            case $2 in
                1|fatal|FATAL)           	LogLevel=1; OPT_LogLevel='--log=::fatal';;
                2|critical|CRITICAL)   	    LogLevel=2; OPT_LogLevel='--log=::critical';;
                3|error|ERROR)          	LogLevel=3; OPT_LogLevel='--log=::error';;
                4|warning|WARN|WARNING)	    LogLevel=4; OPT_LogLevel='--log=::warning';;
                5|notice|NOTICE)         	LogLevel=5; OPT_LogLevel='--log=::notice';;
                6|info|information|INFO)	LogLevel=6; OPT_LogLevel='--log=::information';;
                7|debug|DEBUG)          	LogLevel=7; OPT_LogLevel='--log=::debug';;
                8|trace|TRACE)           	LogLevel=8; OPT_LogLevel='--log=::trace';;
                *)                         	die "Invalid log level: $2"
            esac
            ;;
        n|dry-run)
			log_trace "Dry run mode"
            OPT_DryRun="--dry-run"  # so the variable can be directly sent to WMCApplications
            ;;
        d|working-dir)
            WMC_WD=$2
            [ -d $WMC_WD ] || mkdir -p $WMC_WD || die "Can't create working directory $WMC_WD"
			OPT_WorkingDir="--working-dir=$WMC_WD"
			log_trace "working-dir=$WMC_WD"
            ;;
        *)  Options $1 $2 || return $?
    esac
}


OPTIONS_LIST='nl:d:-:'
ProcessOptions() {
    [ $# -gt 0 ] || return 0

    OPTIND=1
    while getopts $OPTIONS_LIST OPTION
    do
        case $OPTION in
            -)  #echo "-- was triggered: $OPTARG"
                longOpt=`echo $OPTARG | sed -e 's/=.*//'`
                longArg=`echo $OPTARG | sed -ne '/=/ s/.*=// p'`
                BaseOptions $longOpt $longArg || { echo "Invalid option: --$longOpt"; exit 1; }
                ;;
            \?) #echo "Invalid option: -$OPTARG"
                exit 1
                ;;
            :)  #echo "Option -$OPTARG requires an argument."
                exit 1
                ;;
	        *)  BaseOptions $OPTION $OPTARG || return $?
                ;;
        esac
    done
    shift $(($OPTIND - 1))

#    ProcessCommands "$@"
#    return $?
}


finis() {
    ret=${1:-'0'}
    Finalize $ret
    log_trace finis $ret
    exit $ret
}

atexit () {
    ret=${1:-'42'}
    log_fatal "Terminated: atexit ${ret}"
	TrapHandled=$1
    exit $ret       # 'finis' to do cleanup
}

trap 'finis $?' 0
trap 'atexit 2' 2
trap 'atexit 15' 15 
trap 'atexit 30' 30 

#TRAP=`trap`
#log_debug "${TRAP}"


# <-------------------------------------------------------------------------------------------
# Import config:
# --------------------------------------------------------------------------------------------
loadConfig() {
	export WMC_CONFIG=${WMC_CONFIG:-'/place/wmconsole/wmconsole.cfg'}
	[ -r $WMC_CONFIG ] || die "Config file $WMC_CONFIG not found"

	log_trace "Loading config $WMC_CONFIG"
	. $WMC_CONFIG || die $? "Failed to load config file $WMC_CONFIG"
}
# -->

#==========================================================================================
# Variables OPT_DryRun, OPT_LogLevel, OPT_WorkingDir and WMC_WD are configured now (via cmdline options)
#==========================================================================================

# User shall overwrite Finalize() and Options() functions

#OPTIONS_LIST="${OPTIONS_LIST}c:"
#Options() {
#    case $1 in
#        c|continue)
#            # Resume execution
#            OPT_CONTINUE = 1
#            ;;
#        *)  return 1
#    esac
#}

# --------------------------------------------------------------------------------------------
# pid logging and trap 
# --------------------------------------------------------------------------------------------
PidFile=$WMC_WD/$Prog.pid

Finalize() {
    [ -z $PidFile ] || $rmPidFile
}

log_pids() {
#   echo -n $$ `jobs -p` > $PidFile         # bash
	rmPidFile="rm -f $PidFile"
    echo -n `jobs -s` $$ > $PidFile         # sh
}


# Script main body ----------------------------------------------------------------------------------
