#!/bin/bash

MOUNT_OPTIONS=$(findmnt -nu -oOPTIONS -T/ | tr ',' '\n' | grep '^r[w|o]')
NIPEXEC_PID="$(cat /var/run/nipexec.pid)"
LOGFILE=/var/log/nip-update.log

log()
{
	echo "NIP Update - $1" >> ${LOGFILE}
}

die()
{
	log "$1"
	rm -f /REBOOT
	rm -f /SHUTDOWN

	mount -o remount,${MOUNT_OPTIONS} /
	python3 -m nomad_utils.fpga --set-led 1
	exit 1
}

resume()
{
	log "$1"

	rm -f /var/run/nipexec.pid
	mount -o remount,${MOUNT_OPTIONS} /

	if [[ ! -z "${NIPEXEC_PID}" ]] ; then
		systemctl start rppl-nip.service
	fi

	exit 0
}

kill_nipexec()
{
	if [[ -z "${NIPEXEC_PID}" ]] ; then
		echo "$$" > /var/run/nipexec.pid
	else
		python3 -m nomad_utils.fpga --disable-watchdog
		kill -TERM ${NIPEXEC_PID}
		python3 -m nomad_utils.fpga --set-led 2
		sleep ".5"
	fi

	#if it didn't stop kill with extreme prejudice
	pid=$(pidof nipexec)
	if (( $? == 0 )) ; then
		log "Forcefully terminating nipexec (${pid})"
		python3 -m nomad_utils.fpga --disable-watchdog
		kill -KILL ${pid}
		python3 -m nomad_utils.fpga --set-led 5
		rm -f /var/run/nipexec.pid
	fi

	#stop nipexec from running
	echo "$$" > /var/run/nipexec.pid
}


#todo: better checking here
check_update()
{
	local update="$1"

	if [[ ! -r ${update} ]] ; then
		log "${update} invalid."
		return 1
	fi

	if [[ ! -f ${update} ]] ; then
		log "${update} is not a regular file."
		return 1
	fi

	fname=$(basename ${update})
	if [[ ${fname} != rppl-nip-update-* ]] ; then
		log "${update} is not a valid file"
		return 1
	fi

	return 0
}

install_update()
{
	local update="$1"
	local dir="/tmp/current-update"

	log "installing update: ${update#*t/}"

	rm -rf ${dir}
	mkdir -p ${dir}

	log "extracting update: ${update} to dir: ${dir}"
	python3 -m nomad_utils.fpga --set-led 7
	tar -C ${dir} -xvmf ${update} >> ${LOGFILE}

	sync

	log "running update: ${update}"
	if [[ ! -e ${dir}/updexec ]] ; then
		log "no update entry point."
		return 1
	fi

	( cd ${dir}; ./updexec )
	if (( $? != 0 )) ; then
		log "updexec returned: $?"
		return 1
	fi

	rm -rf ${dir}
	return 0
}


install_from_directory()
{
	local directory="${1%/}"
	local ret=0

	for update in ${directory}/rppl-nip-update-*
	do
		if ! check_update ${update} ; then
			continue
		fi

		if ! install_update ${update} ; then
			log "update ${update} failed."
			ret=1
			break
		fi
	done

	rm -rf /tmp/current-update
	return $ret
}


check_directory_for_updates()
{
    local noglob=$(shopt nullglob | cut -f2)
    if [[ "$noglob" == "on" ]]; then
        shopt -u nullglob
    fi
    ls -dv $1/rppl-nip-update-* > /dev/null 2>&1
    rc=$?
    if [[ "$noglob" == "on" ]]; then
        shopt -s nullglob
    fi
    return $rc
}


main()
{
	shopt -s nullglob

	if [[ -e "/DONTUPDATE" ]] ; then
		exit 0
	fi

	log "requested update on : $1"
	mount -o remount,rw /
	mount -o remount,size=2G /tmp
	kill_nipexec

	if [[ -b $1 ]] ; then
		if ! mount -o ro $1 /mnt ; then
			resume "Unable to mount device: $1"
		fi

		if ! check_directory_for_updates "/mnt" ; then
			umount /mnt
			resume "No updates found on: $1"
		fi

		log "install $1 from /mnt"
		install_from_directory "/mnt"
		if (( $? != 0 )) ; then
			umount /mnt
			die "install failed"
		fi

		umount /mnt
		log "install from /mnt completed"

	elif [[ -d $1 ]] ; then
		if ! check_directory_for_updates $1 ; then
			resume "No updates found in : $1"
		fi

		install_from_directory $1
		if (( $? != 0 )) ; then
			die "install failed"
		fi

	elif [[ -f $1 ]] ; then
		if ! check_update $1 ; then
			resume "Not a valid update: $1"
		fi

		install_update $1
		if (( $? != 0 )) ; then
			die "install failed"
		fi
	else
		die "Unable to update."
	fi

	python3 -m nomad_utils.fpga --set-led 3

	if [[ -e "/SHUTDOWN" ]] ; then
		rm -f /SHUTDOWN
		rm -f /REBOOT
		sync

		microcontroller --hard-shutdown
		halt
	elif [[ -e "/REBOOT" ]] ; then
		rm -f /REBOOT
		sync

		# this should do a reboot shutdown -r now
		# but right now that leads to loops where an update is run
		# repeatedly.
		microcontroller --hard-shutdown
		halt
	else
		resume "resuming nipexec."
	fi
}

main "$@"
