#!/bin/bash
 
# Define variables
rp_version="1.4a"		# Processes Respawn Version
rspawn_delay=3			# Monitor delay
log_data=0				# Log Data
rp_log=""				# Processes Respawn Log File
chPIDCount=4			# Minimum chromium PID count to assume chromium is running
chGoneCount=3			# Maximum number of times Chromium is not detected
ts_file=""				# Touch Screen File

# Assign file names
rp_log="$HOME/eeTeam/rp_log.txt"
ts_file="$HOME/g4dev/project/scripts/nts.tjk"

# Create ~/eeTeam directory as needed
if [ ! -d ~/eeTeam ]
then
	mkdir ~/eeTeam
fi

cd ~/g4dev/project/

# Get System specific information
inet_address=$(hostname -I | cut -f1 -d' ')
curr_directory=$(pwd) 

# Control variables
checkCount=1

# Respawn count
projectCount=0
chCount=0
somCount=0
memCount=0


# f_RespawnProject
# Respawns project.exe if not running
f_RespawnProject ()
{
	count=0
	for ((count=0 ; count < checkCount ; count++));
	do
		pidArray=($(pgrep project.exe))
		if [ ${#pidArray[@]} -ne 0 ]
		then
			return 0
		fi
		sleep 0.5
	done

	# If we made it this far, project.exe was not
	# detected 5 times in a row, Respawn it.
	((projectCount++))
	if [ $log_data -ne 0 ]
	then
		f_LogRespawnData "Respawning project.exe"
	fi

	# Terminate chromium
	f_killProcess chromium-browse

	# Run project.exe (chromium will be automatically launched shortly after)
	cd ~/g4dev/project/
	sudo setcap cap_net_bind_service=+ep ~/g4dev/project/bin/debug/project.exe
	./bin/debug/project.exe &

	return 1
}


# f_RespawnChromium
# Respawns chromium if not running
badChCount=0
f_RespawnChromium ()
{
	# If project.exe is not running, don't bother
	pidArray=($(pgrep project.exe))
	if [ ${#pidArray[@]} -eq 0 ]
	then
		if [ $log_data -ne 0 ]
		then
			echo "Skipping chromium-browser spawn,  project.exe not running, $(date +"%D, %T")" | tee -a $rp_log
		else
			echo "Skipping chromium-browser spawn,  project.exe not running, $(date +"%D, %T")"
		fi

		return 999
	fi

	# Check for the Touch Screen file
	if [ -f $ts_file ]
	then
		# Terminate chromium
		f_killProcess chromium-browse
		return 0
	fi

	count=0
	for ((count=0 ; count < checkCount ; count++));
	do
		pidArray=($(pgrep chromium-browse))

		# If we have 4 or more chromium instances, it's all good
		if [ ${#pidArray[@]} -ge $chPIDCount ]
		then
			badChCount=0
			return 0
		fi

		sleep 0.5
	done

	# We made it this far because of less than 4 chromium instances
	# Is chromium running with less than 4 instances (not zero)
	# and this is the second time around in a row?
	if [ ${#pidArray[@]} -ne 0 ]
	then
		if [ $badChCount -lt $chGoneCount ]
		then
			((badChCount++))

			if [ $log_data -ne 0 ]
			then
				echo "Invalid chromium-browser instances count (${#pidArray[@]}), $badChCount of $chGoneCount, $(date +"%D, %T")" | tee -a $rp_log
			else
				echo "Invalid chromium-browser instances count (${#pidArray[@]}), $badChCount of $chGoneCount, $(date +"%D, %T")"
			fi

			return 2
		else

			if [ $log_data -ne 0 ]
			then
				echo "Invalid chromium-browser instances count (${#pidArray[@]}), $badChCount of $chGoneCount, killing chromium, $(date +"%D, %T")" | tee -a $rp_log
			else
				echo "Invalid chromium-browser instances count (${#pidArray[@]}), $badChCount of $chGoneCount, killing chromium, $(date +"%D, %T")"
			fi

			badChCount=0

			# Terminate chromium, let it try to respawn again
			f_killProcess chromium-browse

			return 3
		fi
	fi

	# If we made it this far, Chromium was not
	# detected 5 times in a row, Respawn it.
	((chCount++))
	if [ $log_data -ne 0 ]
	then
		f_LogRespawnData "Respawning chromium-browser"
	fi

	# For production
	chromium-browser --incognito --kiosk http://0.0.0.0:8080 &

	# For debugging
	# chromium-browser --enable-logging --v=1 --log-level=0 --incognito --kiosk http://0.0.0.0:8080 &

	return 1
}


# f_RespawnSOM_Mon
# Respawns SOM_Mon.sh if not running
f_RespawnSOM_Mon ()
{
	count=0
	for ((count=0 ; count < checkCount ; count++));
	do
		pidArray=($(pgrep SOM_Mon.sh))
		if [ ${#pidArray[@]} -ne 0 ]
		then
			return 0
		fi
		sleep 0.5
	done

	# If we made it this far, SOM_Mon.sh was not
	# detected 5 times in a row, Respawn it.
	((somCount++))
	if [ $log_data -ne 0 ]
	then
		f_LogRespawnData "Respawning SOM_Mon.sh"
	fi
	
	~/g4dev/project/scripts/SOM_Mon.sh &

	return 1
}


# f_RespawnMemMon
# Respawns MemMon.sh if not running
f_RespawnMemMon ()
{
	count=0
	for ((count=0 ; count < checkCount ; count++));
	do
		pidArray=($(pgrep MemMon.sh))
		if [ ${#pidArray[@]} -ne 0 ]
		then
			return 0
		fi
		sleep 0.5
	done

	# If we made it this far, MemMon.sh was not
	# detected 5 times in a row, Respawn it.
	((memCount++))
	if [ $log_data -ne 0 ]
	then
		f_LogRespawnData "Respawning MemMon.sh"
	fi

	# Start the Memory Monitor
	#cd ~/eeTeam
	if [ $log_data -ne 0 ]
	then
		~/g4dev/project/scripts/MemMon.sh 10 -kchmem -maxchmem=6000 -kchswap -maxchswap=10000 -flushonkill -flushonswap -maxflushovswap=20000 -flushwindow=300 -log &
	else
		~/g4dev/project/scripts/MemMon.sh 10 -kchmem -maxchmem=6000 -kchswap -maxchswap=10000 -flushonkill -flushonswap -maxflushovswap=20000 -flushwindow=300 &
	fi

	return 1
}



# f_killProcess - Kills a specified process
# Arguments: $1 - Process Name
# Returns:   1  - Process terminated normally (-SIGINT  / -2)
#            2  - Process killed forcefully   (-SIGKILL / -9)
#            10 - No process name specified
#            11 - No process PIDs found
f_killProcess ()
{
	# Was a process name specified (first argument)
	if [ -z $1 ]
	then
		# No process name, get out
		#chAction="No Proc Name"
		return 10
	fi

	# Get Process PIDs
	#vArray=($(echo "$top_buf" | grep "$1" | awk '{print $1}'))
	#vArray=($(pgrep chromium-browse))
	vArray=($(pgrep $1))
	if [ ${#vArray[@]} -le 0 ]
	then
		# No PIDs found for process
		#chAction="No Proc PID"
		return 11
	fi

	# Kill process gracefully, convince it to die
	#chAction="Kill SIGINT"
	pkill -SIGINT $1

	# Verify that all the previously detected PIDs are gone...
	for ((loop=0 ; loop <= 5 ; loop++));
	do
		sleep 1
		count=0
		for val in "${vArray[@]}"
		do
			if ps -p $val > /dev/null
			then
				((count++))

				# Something is still alive,
				# no point on checking other PIDs
				if [ $loop -lt 5 ]
				then
					break
				fi
			fi
		done

		# Was any PID still active?
		if [ $count -eq 0 ]
		then
			#chAction="Kill SIGINT ($loop)"
			# No, we are done, just get out
			return 0
		fi
	done

	# If I made it this far, there were still some active PIDs
	# Euthanize process...
	#chAction="Kill SIGKILL"
	pkill -SIGKILL $1
	
	return 0
}




# f_LogRespawnData
# Logs latest respawn information
f_LogRespawnData ()
{

	if [ $log_data -ne 0 ]
	then
		echo "$1 (project.exe: $projectCount / Chromium: $chCount / SOM_Mon.sh: $somCount / MemMon.sh: $memCount), $(date +"%D, %T")" | tee -a $rp_log
	else
		echo "$1 (project.exe: $projectCount / Chromium: $chCount / SOM_Mon.sh: $somCount / MemMon.sh: $memCount), $(date +"%D, %T")"
	fi
}



#########################
# Get parameters
#
for ((i=1 ; i <= $# ; i++));
do

	case "${!i}" in

		# Log Data
		"-log")
			log_data=1
			;;

		"-nolog")
			log_data=0
			;;


		*)
			rspawn_delay=`expr ${!i}`
			#rspawn_delay=$(echo ${!i} | awk '{printf "%2f" , $1}')
			;;

	esac

done;


if [ $rspawn_delay -le 0 ] || [ $rspawn_delay -gt 10 ]
then
	rspawn_delay=3
fi

#
# Get Parameters
#########################


# Initialize log file
if [ $log_data -ne 0 ]
then

	# Does file exist?
	if [ ! -e $rp_log ]
	then
		echo "$rp_log does not exist"
		echo "Creating file" > $rp_log
	else
		echo "$rp_log exists, appending" >> $rp_log
	fi

	echo "" >> $rp_log
	echo "$0 - Processes Respawn, v$rp_version" >> $rp_log
	echo " Time Stamp:     $(date +"%D, %T")" >> $rp_log
	echo " INet Address:   $inet_address" >> $rp_log
	echo " Current Directory: $curr_directory" >> $rp_log
	echo " Process ID: $$" >> $rp_log

else

	echo ""
	echo "$0 - Processes Respawn, v$rp_version"
	echo " Time Stamp:     $(date +"%D, %T")"
	echo " INet Address:   $inet_address"
	echo " Current Directory: $curr_directory"
	echo " Process ID: $$"

fi


# Control variables (useless, it was already defined at the top of this file)
checkCount=1

# Check for running processes every 3 seconds
while [ true ]
do
	# Check for running project.exe (and respawn as needed)
	f_RespawnProject

	# Allow time for application to boot and begin serving pages
	sleep 2

	# Check for running chromium (and respawn as needed)
	f_RespawnChromium

	# Check for running SOM_Mon.sh (and respawn as needed)
	f_RespawnSOM_Mon

	# Check for running MemMon.sh (and respawn as needed)
	f_RespawnMemMon

	# Set checkCount to 5...
	checkCount=3

	# Delay and repeat
	sleep $rspawn_delay
done

