#!/bin/bash

# Function to draw WinREST API Objects
function W() {
	wcall "$@" || return 1
}

# Function to draw WinREST API Objects, the fast way
function W_fast() {
	wcall -use-environment "$@" || return 1
}

# Function to draw WinREST API Objects with no return
function WN() {
	wcall -async "$@" || return 1
}

# Translate strings by request the fast way
function Trans_fast() {
	local Dictionary="/etc/plugins/plugins.dic"
	if [ -n "$1" ]; then
		[ -n "$2" ] && Dictionary="$2"
		translate -use-environment "$Dictionary" "$1"
	else
		TRANSLATE_RETURN="$1"
	fi
}

# Translate strings by request
function Trans() {
	local Dictionary="/etc/plugins/plugins.dic"
	if [ -n "$1" ]; then
		[ -n "$2" ] && Dictionary="$2"
		translate "$Dictionary" "$1"
	else
		echo "$1"
	fi
}

# Chech if a specific directory is empty
function Dir_Empty() {
	[ -n "$( ls $1 -1 )" ] && return 1 || return 0
}

# Function to determine if parameter is numeric
function IsNumeric() {
	local str="$1" char=""
	local -i i=0 tamStr=${#str}
	[ $tamStr -le 0 ] && return 1
	for((i=0; i<$tamStr; i++)); do
		char="${str:$i:1}"
		( [ $(( $char )) -eq 0 ] && [ "$char" != "0" ] ) && \
			return 1
	done
	return 0
}

# Detect if wconnect is active
function IsWConnectActive() {
	wconnect 2> /dev/null
	return $?
}

# Show a "Please Wait" Window
function PleaseWait_fast() {
	# Initialize a few variables
	local FWindowObjects="" j=""
	local -i i
	local -ax StringsToShow

	# Get and Translate StringsToShow
	if ( IsNumeric "$3" ) || [ -z "$3" ]; then
		# Modern multiple lines Window
		Fold "$2" $3
	else
		# Legacy one/two lines Window
		StringsToShow[0]="$2"
		StringsToShow[1]="$3"
	fi
	local -i WindowHeight=$(( 5 + ${#StringsToShow[*]} * 4 ))

	# Manage Window
	case "$1" in
		"show")
			local -x WWINDOW && MakeWObject "Window" "WWINDOW" 12 $(( ( 55 - $WindowHeight ) / 2 )) 44 $WindowHeight "Processing"
			local -x RRelevo && MakeWObject "Relevo" "RRelevo" "$WWINDOW" 1 1 42 $(( 6 + $WindowHeight - 9 )) 1 1
			for (( i=0; i<${#StringsToShow[*]}; i++ )); do
				local -x TXTText$i && MakeWObject "Texto" "TXTText$i" "$WWINDOW" 3 $(( 3 + $i * 4 )) "${StringsToShow[$i]}" 3 255 -1 0
			done
			W_fast $WWINDOW Show 0
			FWindowObjects="$WWINDOW $RRelevo $(
				for (( i=0; i<${#StringsToShow[*]}; i++ )); do
					j="TXTText$i"
					echo -n "${!j} "
				done )"
		;;
		"kill")
			for (( i=${#@}; i>1; i-- )); do
				WN 0 DeleteObject ${!i} > /dev/null
			done
		;;
	esac
	PleaseWait_return=$FWindowObjects
}

function PleaseWait() {
	PleaseWait_fast "$@"
	echo "$PleaseWait_return"
}

# Set Hardware clock equal to system time
function SetHardwareClock() {
	[ -f /etc/winrest.conf ] && . /etc/winrest.conf
	[ ${NTPSETHWCLOCK:-0} -eq 1 ] && hwclock -w -l
}

# Set machine to a state where shutdown and reboot will do no harm to the filesystem
function TurnToSafeMode() {
	[ -f /etc/winrest.conf ] && . /etc/winrest.conf

	# Create needed files to assure that binaries stay off
	for i in stoprest stopconsoles stopvncserver stopcomserver; do
		> /tmp/$i
	done

	# Kill WinREST
	[ "$1" != "keepwinrestup" ] && \
		KillProgram "$( CheckInstalledApplication )" 2

	# Kill ComServer if no connection to Image Server is established
	if [ $( netstat -an | grep ":7678" | grep -c "ESTABLISHED" ) -eq 0 ]; then
		cd /home/comserver
		#./comserver -t > /dev/null 2>&1
		KillProgram comserver 2
	fi

	# Sync HW Clock to localtime if needed
	KillProgram ntpd 2
	SetHardwareClock

	# Kill Samba
	KillProgram nmbd 2
	KillProgram smbd 2

	# Sync filesystem
	sync

	# Mount rootfs and company as readonly
	[ $( df -h | grep -c "/tmp/extra" ) -gt 0 ] && mount -o remount,ro /tmp/extra
	mount -o remount,ro /
	echo -n "s" > /proc/sysrq-trigger
	sleep 0.1
	echo -n "u" > /proc/sysrq-trigger
	sleep 0.1
	echo -n "s" > /proc/sysrq-trigger

	# Final sync
	sync
}

# Function to make sure program gets killed
function KillProgram() {
	# Parameters
	# $1: program name / PID
	# $2: time to wait bettwen TERM and KILL SIGSPECS
	local i="" PIDLIST=""
	local -i j=0 k=0 MUSTKILL=0 ALLKILLED=1 Timeout=${2:-1}

	IsNumeric $1 && PIDLIST=$1 || PIDLIST=$( pidof $1 | sed 's/ /\n/g' | sort )
	for j in $PIDLIST; do
		kill -TERM $j 2> /dev/null
		sleep 0.1
		[ $( ps -A | grep -w -c "$j" ) -gt 0 ] && MUSTKILL=1
	done
	if [ $MUSTKILL -eq 1 ]; then
		# Wait specified timeout
		for ((j=0; j<$(( $Timeout * 2 )); j++)); do
			sleep 0.5
			ALLKILLED=1
			for j in $PIDLIST; do
				[ $( ps -A | grep -w -c "$j" ) -gt 0 ] && ALLKILLED=0
			done
			[ $ALLKILLED -eq 1 ] && break
		done
		if [ $ALLKILLED -eq 0 ]; then
			# Send KILL signal
			for j in $PIDLIST; do
				kill -KILL $j 2> /dev/null
				sleep 0.1
				# No action taken... hope it dies...
			done
		fi
	fi
}

function Fold() {
	local -i Lenght=${2:-40} Counter=0 i=0
	local StringToDisplay="" TempParam=""
	set - $( echo $( Trans "$1" ) )
# 	Trans_fast "$1"
# 	set - $TRANSLATE_RETURN
	for (( i=1; i<=${#*}; i++ )); do
		TempParam="${!i}"
		if [ "${TempParam}" == "\n" ]; then
			StringsToShow[$Counter]="$StringToDisplay"
			let Counter++
			StringToDisplay=""
		elif [ $(( ${#StringToDisplay} + 1 + ${#TempParam} )) -gt $Lenght ]; then
			StringsToShow[$Counter]="$StringToDisplay"
			let Counter++
			StringToDisplay=""
			let i--
		elif [ "${TempParam: -2 :2}" == "\n" ]; then
			StringToDisplay="$StringToDisplay ${TempParam:0:$(( ${#TempParam} - 2 ))}"
			StringsToShow[$Counter]="$StringToDisplay"
			let Counter++
			StringToDisplay=""
		elif [ -z "$StringToDisplay" ]; then
			StringToDisplay="$TempParam"
		else
			StringToDisplay="$StringToDisplay $TempParam"
		fi
	done
	[ -n "$StringToDisplay" ] && StringsToShow[$Counter]="$StringToDisplay"
}

function Warning() {
	# Initial variables
	local -ax StringsToShow
	local j=""
	local -i i=0 FoldColumns=40

	# Get and Translate StringsToShow
	if ( IsNumeric "$2" ) || [ -z "$2" ]; then
		# Modern multiple lines Window
		FoldColumns=$(( ${2:-$FoldColumns} ))
		Fold "$1" $FoldColumns
	else
		# Legacy one/two lines Window
		StringsToShow[0]="$1"
		StringsToShow[1]="$2"
	fi
	local -i WindowHeight=$(( 11 + ${#StringsToShow[*]} * 4 ))
	local -i WindowLenght=$(( 4 + $FoldColumns ))

	# Draw WObjects
	local -x WWarn && MakeWObject "Window" "WWarn" $(( 32 - ( $WindowLenght / 2 ) )) $(( ( 55 - $WindowHeight ) / 2 )) $WindowLenght $WindowHeight "Warning"
	local -x RWarn && MakeWObject "Relevo" "RWarn" "$WWarn" 1 1 $(( $WindowLenght - 2 )) $(( $WindowHeight - 9 )) 1 1
	for (( i=0; i<${#StringsToShow[*]}; i++ )); do
		local -x TXTWarn$i && MakeWObject "Texto" "TXTWarn$i" "$WWarn" 3 $(( 3 + $i * 4 )) "${StringsToShow[$i]}" 3 255 -1 0
	done
	local -x BWarnOk && MakeWObject "Botao" "BWarnBOk" "$WWarn" $(( $WindowLenght - 11 )) $(( $WindowHeight - 7 )) 10 6 "OK" 1 "OK_COLOR" "ENTER"

	# Manage for events
	local -i WRet=-1
	while [ $WRet -ne 1 ]; do
		W_fast $WWarn DoEvents 0 0
		WRet=$WCALL_RETURN
	done

	# Delete WObjects
	for i in $WWarn $RWarn $BWarnOk; do WN 0 DeleteObject $i; done
	for (( i=0; i<${#StringsToShow[*]}; i++ )); do j="TXTWarn$i"; WN 0 DeleteObject ${!j}; done
	return 0
}

function Question() {
	# Initial variables
	local -ax StringsToShow
	local j=""
	local -i i=0 FoldColumns=40 NStrings=0

	# Get and Translate StringsToShow
	if ( IsNumeric "$2" ) || [ -z "$2" ]; then
		# Modern multiple lines Window
		FoldColumns=$(( ${2:-$FoldColumns} ))
		Fold "$1" $FoldColumns
	else
		# Legacy one/two lines Window
		StringsToShow[0]="$1"
		StringsToShow[1]="$2"
	fi
	local -i WindowHeight=$(( 11 + ${#StringsToShow[*]} * 4 ))
	local -i WindowLenght=$(( 4 + $FoldColumns ))

	# Draw WObjects
	local -x WQuestion && MakeWObject "Window" "WQuestion" $(( 32 - ( $WindowLenght / 2 ) )) $(( ( 55 - $WindowHeight ) / 2 )) $WindowLenght $WindowHeight "Confirmation"
	local -x RQuestion && MakeWObject "Relevo" "RQuestion" "$WQuestion" 1 1 $(( $WindowLenght - 2 )) $(( $WindowHeight - 9 )) 1 1
	NStrings=${#StringsToShow[*]}
	for (( i=0; i<$NStrings; i++ )); do
		local -x TXTQuestion$i && MakeWObject "Texto" "TXTQuestion$i" "$WQuestion" 3 $(( 3 + $i * 4 )) "${StringsToShow[$i]}" 3 255 -1 0
	done
	local -x BQuestionOk && MakeWObject "Botao" "BQuestionOk" "$WQuestion" $(( $WindowLenght - 11 )) $(( $WindowHeight - 7 )) 10 6 "OK" 1 "OK_COLOR" "ENTER"
	local -x BQuestionCancel && MakeWObject "Botao" "BQuestionCancel" "$WQuestion" $(( $WindowLenght - 22 )) $(( $WindowHeight - 7 )) 10 6 "Cancel" 2 "CANCEL_COLOR" "ESC"

	# Manage events
	local -i QRet=-1
	until [ $QRet -eq 1 ] || [ $QRet -eq 2 ]; do
		W_fast $WQuestion DoEvents 0 0
		QRet=$WCALL_RETURN
	done

	# Delete WObjects
	for i in $WQuestion $RQuestion $BQuestionOk $BQuestionCancel; do WN 0 DeleteObject $i; done
	for (( i=0; i<${#StringsToShow[*]}; i++ )); do j="TXTQuestion$i"; WN 0 DeleteObject ${!j}; done

	# Return correct value
	[ $QRet -eq 1 ] && return 0 || return 1
}

function GetWinRESTColor_fast() {
	local -i Color=0
	case "$1" in
		"BLUE")			Color=3		;;
		"GREEN")		Color=18	;;
		"RED")			Color=108	;;
		"RED_BOX")		Color=400	;;
		"GREEN_DARK")	Color=126	;;
		"GREEN_BOX")	Color=140	;;
		"YELLOW")		Color=210	;;
		"YELLOW_BOX")	Color=252	;;
		"WHITE")		Color=255	;;
		"OK_COLOR")		Color=511	;;
		"CANCEL_COLOR")	Color=767	;;
		"HELP_COLOR")	Color=1023	;;
		"LEFT_COLOR")	Color=1279	;;
		"RIGHT_COLOR")	Color=1535	;;
		"UP_COLOR")		Color=1791	;;
		"DOWN_COLOR")	Color=2047	;;
		"GREEN_COLOR")	Color=4351	;;
		"YELLOW_COLOR")	Color=4607	;;
		"RED_COLOR")	Color=4863	;;
		"BLUE_COLOR")	Color=5119	;;
		"NOVO_COLOR")	Color=6911	;;
		"LIXO_COLOR")	Color=7167	;;
		"POSTO_COLOR")	Color=12287	;;
		"SWAP_COLOR")	Color=17407	;;
		"TODISK_COLOR")	Color=24831	;;
		"EDIT_COLOR")	Color=25343	;;
		"")				Color=0		;;
		*)				Color=$1	;;
	esac
	GetWinRESTColor_return=$Color
}

function GetWinRESTColor() {
	GetWinRESTColor_fast "$@"
	echo "$GetWinRESTColor_return"
}

function GetWinRESTHotKey_fast() {
	local -i HotKey
	case "$1" in
		"")		HotKey=0	;;
		"ESC")		HotKey=1	;;
		"ENTER")	HotKey=28	;;
		"F1")		HotKey=59	;;
		"F2")		HotKey=60	;;
		"INS")		HotKey=182	;;
		"HOME")		HotKey=171	;;
		"DEL")		HotKey=183	;;
		*)		HotKey=$1	;;
	esac
	GetWinRESTHotKey_return=$HotKey
}

function GetWinRESTHotKey() {
	GetWinRESTHotKey_fast "$@"
	echo "$GetWinRESTHotKey_return"
}

function GetEditType_fast() {
	local -i EditType=0
	case "$1" in
		"ALPHA" | "")	EditType=0	;;
		"NUMERIC")	EditType=1	;;
		"CALCULATOR")	EditType=2	;;
		"DATE")		EditType=3	;;
		"MONEY")	EditType=4	;;
		*)		EditType=$1	;;
	esac
	GetEditType_return=$EditType
}

function GetEditType() {
	GetEditType_fast "$@"
	echo "$GetEditType_return"
}

function GetBevelType_fast() {
	local -i BevelType=0
	case "$1" in
		"GUI_IN" | "")	BevelType=0	;;
		*)		BevelType=$1	;;
	esac
	GetBevelType_return=$BevelType
}

function GetBevelType() {
	GetBevelType_fast "$@"
	echo "$GetBevelType_return"
}

function GetTabstopAlignment() {
	local TABSTOP_LEFT="16#00000"
	local TABSTOP_CENTER="16#10000"
	local TABSTOP_RIGHT="16#20000"
	local tabstop hex
	local -i count i=0

	[ $# -gt 16 ] && count=16 || count=$#
	
	local tabstop="";
	for((i=1; i <= $count; i++)); do
		hex=( $( printf "%08x" $(( ${!i} )) ) )
		tabstop="$tabstop${hex:6:2}${hex:4:2}${hex:2:2}${hex:0:2}"
	done
	echo "$tabstop"
	return 0
}

function MakeWObject() {
	OBJID=$(( ${OBJID:-1} + 1 ))
	export ${2}=$OBJID

	case "$1" in
		"Window")
			WN 0 CreateObjectWithID Window 0 $OBJID
			# name left top width height caption
			Trans_fast "$7"
			WN ${!2} Init $3 $4 $5 $6 "$TRANSLATE_RETURN"
		;;
		"Botao")
			WN 0 CreateObjectWithID Button 0 $OBJID
			# name object left top width height caption code color hotkey
			GetWinRESTColor_fast ${10}
			GetWinRESTHotKey_fast ${11}
			Trans_fast "$8"
			WN ${!2} Init $3 $4 $5 $6 $7 "$TRANSLATE_RETURN" $9 $GetWinRESTColor_return $GetWinRESTHotKey_return
		;;
		"TextBox")
			WN 0 CreateObjectWithID Edit 0 $OBJID
			# name object left top width text pnum edit code caption hotkey limit password sidesize
			GetEditType_fast $8
			GetWinRESTHotKey_fast ${12}
			Trans_fast "${11}"
			WN ${!2} Init $3 $4 $5 $6 "$7" $GetEditType_return $9 ${10} "$TRANSLATE_RETURN" $GetWinRESTHotKey_return ${13} ${14} ${15}
		;;
		"Relevo")
			WN 0 CreateObjectWithID Bevel 0 $OBJID
			# name object left top width height type depth
			GetBevelType_fast $8
			WN ${!2} Init $3 $4 $5 $6 $7 $GetBevelType_return $9
		;;
		"Texto")
			WN 0 CreateObjectWithID Label 0 $OBJID
			# name object left top text fontsize color alignment centered
			Trans_fast "$6"
			WN ${!2} Init $3 $4 $5 "$TRANSLATE_RETURN" $7 $8 $9 ${10}
		;;
		"Lista")
			WN 0 CreateObjectWithID ListBox 0 $OBJID
			# name object left top width height caption hotkey
			GetWinRESTHotKey_fast $9
			Trans_fast "$8"
			WN ${!2} Init $3 $4 $5 $6 $7 "$TRANSLATE_RETURN" $GetWinRESTHotKey_return
		;;
		"CheckBox")
			WN 0 CreateObjectWithID CheckBox 0 $OBJID
			# name object left top width caption code hotkey
			Trans_fast "$7"
			GetWinRESTHotKey_fast $9
			WN ${!2} Init $3 $4 $5 $6 "$TRANSLATE_RETURN" $8 $GetWinRESTHotKey_return
		;;
		"ColorBox")
			WN 0 CreateObjectWithID ColorBox 0 $OBJID
			# name object left top color code height edit
			GetWinRESTColor_fast $6
			WN ${!2} Init $3 $4 $5 $GetWinRESTColor_return $7 $8 $9
		;;
		"Bar")
			WN 0 CreateObjectWithID Progress 0 $OBJID
			# name object left top width color caption maximum
			GetWinRESTColor_fast $7
			Trans_fast "$8"
			WN ${!2} Init $3 $4 $5 $6 $GetWinRESTColor_return "$TRANSLATE_RETURN" $9 ${10}
		;;
		"WPrintJob")
			WN 0 CreateObjectWithID WPrintJob 0 $OBJID
			# no Init needed
		;;
	esac
}

function LoadModule() {
	# If empty, exit
	[ -z "$1" ] && return 1

	# Get excluded modules list
	[ -f /etc/winrest.conf ] && . /etc/winrest.conf
	for i in $EXCLUDED_MODULES; do
		# exit function if module is not to be loaded
		[ "$i" == "$1" ] && Load_Module=1 && return 1
	done
	modprobe $1
	return $?
}

function GetInterfaceAddress() {
	[ ! -z "$1" ] && echo "$( ifconfig -a | grep -A1 "$1" | grep -v "$1" | grep "inet addr" | \
		sed 's/:/ /g' | awk '{print $3}' )"
}

function GetConfiguredLanguage() {
	local TmpLanguage="${1:-Autodetect}"
	local Application="$( CheckInstalledApplication )"

	case "$Application" in
		"winrest")
			local WinRESTFile="/home/$Application/config/wrstsc01.000"
			if [ ! -f "$WinRESTFile" ]; then
				TmpLanguage="en-GB"
			elif [ "$TmpLanguage" == "Autodetect" ]; then
				[ -f /home/winrest/files/data/foconfig ] && WinRESTFile="/home/$Application/files/data/foconfig"
				TmpLanguage="$( grep MAINLG $WinRESTFile | sed -r 's/^([ \t]*0MAINLG)([ a-zA-Z\-]{,5}).*$/\2/' | \
					tr -d [:space:] )"
				[ -z "$TmpLanguage" ] && TmpLanguage="en-GB" || \
					TmpLanguage="${TmpLanguage:0:3}$( tr [:lower:] [:upper:] <<< "${TmpLanguage:3:2}" )"
			fi
		;;
		"pingwin")
			TmpLanguage="$( GetPingWinPublicInfo "language" )"
			if [ "$TmpLanguage" == "notdetected" ]; then
				TmpLanguage="en-GB"
				[ -f /etc/winrest.conf ] && . /etc/winrest.conf
				TmpLanguage="${DetectedLanguage:-"en-GB"}"
			fi
		;;
	esac

	echo "$TmpLanguage"
}

function CheckDir() {
	[ -e $1 ] && [ ! -d $1 ] && rm -f $1
	[ ! -e $1 ] && mkdir $1
}

function CheckInstalledApplication() {
	local Application="winrest"

	[ -d /home/pingwin ] && Application="pingwin"

	if [ "$1" == "formal" ]; then
		case "$Application" in
			"winrest")	Application="WinREST"	;;
			"pingwin")	Application="PingWin"	;;
		esac
	fi
	
	echo "$Application"
}

function GetFBResolution() {
	local FBResolution="800x600"
	[ -e /sys/class/graphics/fb0/virtual_size ] && \
		FBResolution="$( sed 's/,/x/' < /sys/class/graphics/fb0/virtual_size )"
	echo -n "$FBResolution"
}

function CheckWinRESTResolution() {
	# Check WinREST path
	local -i Terminal=1
	( IsNumeric "$1" ) && Terminal=$1
	local Application="$( CheckInstalledApplication )"
	local WinRESTPath="${3:-/home/${Application}}"
	# Check if Pingwin and exit, as is adjust itself
	[ "$Application" == "pingwin" ] && return 0
	# Check if it is WinREST
	[ -f "$WinRESTPath/config/wrstsc01.000" ] || return 1

	# Change WinREST Resolution according to framebuffer settings
	local ReportedFBResolution="$( GetFBResolution )" WinRESTResolution=""
	[ $Terminal -ne 1 ] && [ -n "$2" ] && ReportedFBResolution="$( awk -F "+" '{print $1}' <<< "$2" )"
	case "$ReportedFBResolution" in
		"320x240")	WinRESTResolution="2"	;;
		"640x480")	WinRESTResolution="0"	;;
		"1024x768")	WinRESTResolution="3"	;;
		"800x480")	WinRESTResolution="4"	;;
		"1024x600")	WinRESTResolution="5"	;;
		"1366x768"|"1368x768")	WinRESTResolution="6"	;;
		*)		WinRESTResolution="1"	;;
	esac
	cp -f $WinRESTPath/config/wrstsc01.000 /tmp/wrstsc01.000
	dos2unix /tmp/wrstsc01.000
	local WinRESTCfgLine="$( grep "  ${Terminal}RES860" /tmp/wrstsc01.000 )"
	local WinRESTCfgResolution="${WinRESTCfgLine: -1 :1}"
	if [ "$WinRESTCfgResolution" != "$WinRESTResolution" ]; then
		local WinRESTCfgLineNew="${WinRESTCfgLine:0: $(( ${#WinRESTCfgLine} - 1 )) }${WinRESTResolution}"
		echo "sed -i 's/$WinRESTCfgLine/$WinRESTCfgLineNew/' /tmp/wrstsc01.000" > /tmp/cwres
		/bin/bash /tmp/cwres
		rm -f /tmp/cwres && unset WinRESTCfgLineNew
		unix2dos /tmp/wrstsc01.000
		cp -f /tmp/wrstsc01.000 $WinRESTPath/config/wrstsc01.000
		[ $Terminal -eq 1 ] && [ -e /etc/lastcalibrated ] && rm -f /etc/lastcalibrated
	fi
	rm -f /tmp/wrstsc01.000
	unset ReportedFBResolution && unset WinRESTResolution && unset WinRESTCfgLine && \
		unset WinRESTCfgResolution && unset WinRESTPath
}

function ModuleRequiredDistro() {
	if [ -z "$1" ]; then
		echo "499"
	else
		LANGUAGE="en-GB" Trans "RequiredDistroToRun" "$1"
	fi
}

function RequiredApplicationToRun() {
	local Application=""
	if [ -n "$1" ] && [ -f "$1" ]; then
		LANGUAGE="en-GB" Trans_fast "RequiredApplicationToRun" "$1"
		Application="$TRANSLATE_RETURN"
		[ "$Application" == "RequiredApplicationToRun" ] && Application=""
	fi
	echo "$Application"
}

function DistroVersion() {
	head -n 1 /bin/distro_version
}

function ModuleVersion() {
	if [ -z "$1" ]; then
		VersionToReport="0.0.0"
	else
		VersionToReport="$( LANGUAGE="en-GB" Trans "[descrip]" "$1" | head -n 3 | tail -n 1 | awk '{print $1}' )"
		VersionToReport="${VersionToReport:2: $(( ${#VersionToReport} - 3 )) }"
	fi
	echo "$VersionToReport"
}

function IsPenEmpty() {
	local ReturnValue=1
	[ $(( $( df | grep "$1" | awk '{print $4}' ) )) -eq 0 ] && ReturnValue=0
	return $ReturnValue
}

function lparse() {
	# Parameters:
	# $1: TAG to find
	# $2: File to look at

	# Exit if no TAG
	[ -z "$1" ] && return 1

	# Local variables
	local Application="$( CheckInstalledApplication )"
	local LicenseFile="${2:-/home/$Application/config/wrstsc00.lic}"
	local LineToParse="" TAGValue="" TagToFind="$1" OriginalTagToFind="$1"
	local -i TAGStart=0 TAGEnd=0 TAGOffset=0 i=0

	# Apply individual application licenses
	case "$Application" in
		"winrest")
			# Create a temporary file with PRODUCT subgroup only
			grep -A 1000 "<PRODUCT>" "$LicenseFile" | grep -B 1000 "<\\\\PRODUCT>" > /tmp/license.tmp
		;;
		"pingwin")
			# Redefine license file
			LicenseFile="${2:-/home/$Application/config/license.xml}"
			# Create a temporary license file
			cp "$LicenseFile" /tmp/license.tmp
			# Provide compatibility for old scripts
			case "$TagToFind" in
				"SERIALNUMBER")		TagToFind="serial_number"	;;
				"EXPIRYDATE")		TagToFind="expiry_date"		;;
				"NOME")				TagToFind="name"			;;
				"PRODUCTNUMBER")	TagToFind="product_number"	;;
				"VERSION")			TagToFind="version_high"	;;
				"NCONTRIBUINTE")	TagToFind="tax_id"			;;
			esac
		;;
	esac

	while true; do
		# Just get the needed TAG line and remove unwanted characters
		dos2unix /tmp/license.tmp 2> /dev/null
		LineToParse="$( grep "<$TagToFind>" /tmp/license.tmp )" && rm -f /tmp/license.tmp
		# Find start and end of TAG Value
		for (( i=0; i<$(( ${#LineToParse} - ${#TagToFind} )); i++ )); do
			[ "${LineToParse:$i:${#TagToFind}}" == "$TagToFind" ] && break
		done
		TagStart=$(( $i + ${#TagToFind} + 1 ))
		for (( i=$TagStart; i<$(( ${#LineToParse} - ${#TagToFind} )); i++ )); do
			[ "${LineToParse:$i:${#TagToFind}}" == "$TagToFind" ] && break
		done
		TagEnd=$(( $i - 2 ))
		# Get TAG Value
		TAGOffset=$(( $TagEnd - $TagStart ))
		[ $TAGOffset -lt 0 ] && TAGOffset=3000
		TAGValue="${LineToParse:$TagStart:$TAGOffset}"
		if [ -z "$TAGValue" ] && [ "$TagToFind" == "product_number" ]; then
			TagToFind="PRODUCTNUMBER"
		else
			break
		fi
	done
	
	# Return value with an echo
	echo "$TAGValue"
}

function GetGroupProcesses() {
	# Get all child processes, including parent
	local i=""
	local ReportedProcesses=""
	echo $@
	for i in $@; do
		ReportedProcesses="$( ps h --ppid $i | awk '{print $1}' )"
		[ -n "$ReportedProcesses" ] && GetGroupProcesses "$ReportedProcesses"
	done
}

function SyncPEN() {
	# If no argument, exit
	( [ -z "$1" ] || [ ! -d "$1" ] ) && return 0
	# Sync PEN by mounting device read-only and read-write again
	mount "$1" -o remount,ro
	mount "$1" -o remount,rw
}

function WPing {
	wconnect <<< "wcall 0 GetVersion" > /dev/null 2>&1
	return $?
}

function GetWVersion {
	local Version="-1"

	( WPing ) && Version="$( wconnect <<< "wcall 0 GetVersion" )"

	# Return Value
	echo "$Version"
}

function WaitForWServer() {
	local -i Timeout=60
	local -i Counter=0
	[ $(( $1 )) -gt 0 ] && Timeout=$(( $1 ))
	while [ $Counter -lt $Timeout ]; do
		WPing
		[ $? -eq 0 ] && break
		let Counter++
		sleep 1
	done
	# If unsuccesfull, do NOT execute mirror
	[ $Counter -ge 60 ] && return 1 || return 0
}

function LogToConsole() {
	Trans_fast "$1"
	echo "$TRANSLATE_RETURN" > /dev/vc/1
}

function LogToKernel() {
	Trans_fast "$1"
	logger -p daemon.info -t mirror "$TRANSLATE_RETURN"
	LogToConsole "$TRANSLATE_RETURN"
}

function ShowOnWinREST() {
	local -i ErrorRet=0
	local EchoRet=""
	if ( WPing ); then
		EchoRet="$( wconnect showonwinrest "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" )"
		ErrorRet=$?
	fi
	[ -n "$EchoRet" ] && echo "$EchoRet"
	return $ErrorRet
}

function ConfirmBContinuityDate {
	# Local variables
	local ListedDirs="$1" j=""
	local -i ReturnDir=0 i=0 Counter=0 CDRet=-1

	# Confirm date
	if [ -n "$ListedDirs" ] && [ $(( $( wc -l <<< "$ListedDirs" ) )) -gt 0 ]; then
		# Create window to select date
		local -x WConfirmDate && MakeWObject "Window" "WConfirmDate" 17 12 36 25 "Date Selection"
		local -x LCDSelectDate && MakeWObject "Lista" "LCDSelectDate" "$WConfirmDate" 2 2 32 15 "Available Dates" 0
		local -x BCDOk && MakeWObject "Botao" "BCDOk" "$WConfirmDate" 2 18 32 6 "Select Restore Date" 1 255 "ENTER"
		# Populate Listbox
		#for j in $( echo "$ListedDirs" ); do
		for j in $ListedDirs; do
			WN $LCDSelectDate Add "${j:0:4}-${j:4:2}-${j:6:2}" 0
		done

		# Show window to select date
		W_fast $LCDSelectDate Size
		if [ $(( $WCALL_RETURN )) -gt 0 ]; then
			# Add Dates to ListBox
			W_fast $LCDSelectDate Size
			WN $LCDSelectDate SetSelectedIndex "$WCALL_RETURN"
			# Manage events
			until [ $CDRet -eq 1 ] || [ $Counter -gt 2 ]; do
				W_fast $WConfirmDate DoEvents 0 0
				CDRet=$WCALL_RETURN
				[ $CDRet -eq -1 ] && let Counter++
			done
			W_fast $LCDSelectDate SelectedIndex
			ReturnDir=$(( $WCALL_RETURN + 1 ))
		fi
		# DeleteWObjects
		for i in $WConfirmDate $LCDSelectDate $BCDOk; do WN 0 DeleteObject $i; done
	fi

	echo $ReturnDir
}

function GetWinRESTWorkDate() {
	local Application="${1:-$( CheckInstalledApplication )}"
	local Date="" OPWD=""

	case "$Application" in
		"winrest")
			Date="$( head -n 1 /home/$Application/files/data/wrstdata.000 2> /dev/null | \
				dos2unix | awk -F "/" '{print $3$1$2}' )"
		;;
		"pingwin")
			Date="$( GetPingWinPublicInfo "workdate" )"
		;;
	esac

	echo "$Date"
}

function GetPingWinPublicInfo() {
	local Info="${1,,}"
	local iRet=""

	if ( WPing ); then
		case "$Info" in
			"language")
				iRet="$( wconnect <<< "wcall 0 GetLanguage" 2> /dev/null )"
			;;
			"workdate")
				iRet="$( wconnect <<< "wcall 0 GetWorkDate" 2> /dev/null )"
				if [ -n "$iRet" ]; then
					iRet="$(( ( $iRet - 25202 ) * 86400 ))"
					iRet="$( date '+%Y%m%d' --date=@${iRet} )"
				fi
			;;
		esac
	else
		case "$Info" in
			"language")	iRet="notdetected"	;;
			"workdate")	iRet="0"			;;
		esac
	fi

	echo "$iRet"
}

function CreateSnapshot() {
	( [ -z "$1" ] || [ -e "$1" ] ) && return 1
	local SnapshotName="$1"
	local SnapshotMountDir="${2:-/tmp/$1}"
	CheckDir "$SnapshotMountDir"
	[ ! -d "$SnapshotMountDir" ] && return 1
	lvcreate -l80%FREE -p r -s -n $SnapshotName /dev/vg00/lvroot > /dev/null 2>&1
	mount /dev/vg00/$SnapshotName "$SnapshotMountDir" -o ro > /dev/null 2>&1 3>&1 0>&1
}

function RemoveSnapshot() {
	[ -z "$1" ] && return 1
	local SnapshotName="$1"
	local SnapshotMountDir="${2:-/tmp/$1}"
	[ ! -d "$SnapshotMountDir" ] && return 1
	umount "$SnapshotMountDir" > /dev/null 2>&1
	rmdir "$SnapshotMountDir"
	lvremove -f /dev/vg00/$SnapshotName > /dev/null 2>&1
}

function GetKernelArchitecture() {
	local Architecture="x86"
	local ReadArchitecture="$( uname -m | head -n 1 )"
	[ "${ReadArchitecture:0:3}" == "arm" ] && Architecture="arm"
	echo "$Architecture"
}
