#!/bin/bash

NEW_FPGA_FW=""
NEW_MICROCONTROLLER_FW=""
NEW_LINUX_KERNEL=""
RESTART="restart"
host_name="$1"
pretty_name="$2"

verify_running_on_nomad()
{
	if [[ "$HOSTNAME" != "$host_name" ]]; then
		echo "Can only run this on the ${pretty_name}."
		./bin/setled red
		exit 1
	fi
}

most_recent() {
	echo "$(ls -1vr $1 2>/dev/null | head -n1)"
}

die() {
	msg="${1:-unexpected error}"
	echo "${msg}"
	exit 1
}

install_bin() {
	local file=$1
	local install_dir=${2:-/usr/local/bin}
	local mode=${3:-0755}

	if [[ ! -e "${file}" ]] ; then
		echo "Unable to find $(basename ${file})"
		return
	fi

	mkdir -p ${install_dir}
	install -t ${install_dir} -m ${mode}  ${file}
	echo "installed $(basename ${file})"
}

install_bin_as() {
	local file=$1
	local dest=${2}
	local mode=${3:-0755}

	if [[ ! -e "${file}" ]] ; then
		echo "Unable to find $(basename ${file})"
		return
	fi

	if [[ -z "${dest}" ]] ; then
		echo "must specify destination name"
		return
	fi

	mkdir -p $(dirname ${dest})
	install  -m ${mode} -T ${file} ${dest}
	echo "installed $(basename ${dest})"
}

install_deb() {
	local file=$1

	if [[ ! -e "${file}" ]] ; then
		echo "unable to find $(basename ${file})"
		return
	fi

	dpkg -i ${file}
	echo "installed $(basename ${file})"
	echo
}




add_nipc_user() {
	local user="nipc"
	local group="nipc"
	local login="/usr/sbin/nologin"
	local home="/usr/rppl"

	# add user if we need to
	if ! id -u ${user} &>/dev/null ; then
		echo "add user ${user}"
		useradd -r -d ${home} -s ${login} ${user} || {
			die "unable to add user ${user}" ; }

	else
		echo "user ${user} already exists"
	fi

	#add group if we need to
	if ! id ${group} &>/dev/null ; then
		echo "add group ${group}"
		groupadd -r ${group} || {
			die "unable to add group ${group}" ; }

	else
		echo "group ${group} already exists"
	fi

	#make sure user is a member of the group
	if id -nGz "${user}" | grep -qzxF "${group}" ; then
		echo "adding user ${user} to group ${group}"
		usermod -a -G ${group} ${user} || {
			die "unable to add user ${user} to group ${group}" ; }
	else
		echo "user ${user} is already a member of group ${group}"
	fi
}


add_ripple_user() {
	local user="rppl"
	local group="rppl"
	local login="/usr/sbin/nologin"
	local home="/home/rppl"
	local sftp_home="/var/rppl/storage"

	# add user if we need to
	if ! id -u "${user}" &>/dev/null ; then
		echo "add user ${user}"
		useradd -r -d ${home} -s ${login} ${user} || {
			die "unable to add user ${user}" ; }
	else
		echo "user ${user} already exists"
	fi

	#add group if we need to
	if ! id ${group} &>/dev/null ; then
		echo "add group ${group}"
		groupadd -r ${group} || {
			die "unable to add group ${group}" ; }
	else
		echo "group ${group} already exists"
	fi

	#make sure user is a member of the group
	if id -nGz "${user}" | grep -qzxF "${group}" ; then
		echo "adding user ${user} to group ${group}"
		usermod -a -G ${group} ${user} || {
			die "unable to add user ${user} to group ${group}" ; }
	else
		echo "user ${user} is already a member of group ${group}"
	fi

	echo "creating home directory for user ${user}"
	mkdir -p ${home}
	chown -f -R ${user}:${group} ${home}

	#default password is username
	echo "${user}:${user}" | chpasswd
}

#must be run after new fstab
set_ripple_permissions() {
	local sftp_home="/var/rppl/storage"
	umount -l ${sftp_home} || /bin/true

	mkdir -p ${sftp_home}
	chown -R rppl:rppl ${sftp_home}

	storage_dir=$(readlink -f /dev/disk/by-label/nomad-storage)
	mount ${storage_dir} ${sftp_home}
	mkdir -p ${sftp_home}/data
	chown -R rppl:rppl ${sftp_home}

	echo "set user permissions for ${sftp_home}"
}

remove_old_nomad_programs() {
	echo "Removing old ${pretty_name} programs"
	rm -f /usr/rppl/nipexec*
	rm -f {start,stop}-wifi
	rm -f {start,stop}-bluetooth

	echo "Removing ${pretty_name} shared libraries"
	dpkg --purge nomad-libnipboard
	dpkg --purge nomad-libs
	rm -rf /usr/local/rppl/lib

	#remove udev rules
	echo  "Removing ${pretty_name} udev rules"
	rm -f /etc/udev/rules.d/98-nip-extvfat.rule

	#remove SysV init scripts if they are there
	echo "Removing ${pretty_name} SysV scripts"
	rm -f /etc/init.d/rppl-nip
	rm -f /etc/rc2.d/S01rppl-nip

	#remove new services
	echo "Removing ${pretty_name} services"
	systemctl disable /etc/systemd/system/rppl-nip.service
	rm -f /etc/systemd/system/rppl-nip.service
	rm -f /etc/systemd/system/rppl-update@.service
	systemctl daemon-reload

	echo "Removing ${pretty_name} Python libraries"
	/usr/bin/yes | pip3 uninstall Nomad-Utils  > /dev/null
	/usr/bin/yes | pip3 uninstall Niptest > /dev/null

	#pip3 uninstall wasn't removing stuff
	rm -rf /usr/local/bin/*
	rm -rf /usr/local/lib/python3.4/dist-packages/[nN]iptest*
	rm -rf /usr/local/lib/python3.4/dist-packages/bench
	rm -rf /usr/local/lib/python3.4/dist-packages/[nN]omad*

	rm -f /usr/local/rppl/python/*

	echo "Removing ${pretty_name} configuration files"
	rm -f /usr/rppl/nipc.conf
	rm -f /etc/nipc.conf

	echo "${pretty_name} programs removed"
}

install_new_nomad_programs()
{
	echo "Installing ${pretty_name} programs"

	# /etc config files
	if [[ -d  "./etc/nomad" ]] ; then
		echo "copying /etc confguration files"
		cp -dR ./etc/nomad/* /etc
		echo "... /etc configuration files installed."
	fi

	# make wifi off on startup
	echo "Installing ${pretty_name} wifi configuration files"
	if [[ -e /etc/network/interfaces.d/wifi.cfg ]] ; then
		rm -f /etc/network/intefaces.d/wifi.cfg
	fi
	mkdir -p /etc/network/interfaces.d
	( cd /etc/network/interfaces.d && ln -fs ../wifi.cfg . )


	echo "installing ${pretty_name} utility programs"
	# /usr/local/bin
	install_bin "./bin/perf"

	install_bin "./urjtag/jtag"
	if [[ -d "./urjtag" ]] ; then
		mkdir -p /usr/local/share/urjtag
		cp -fR ./urjtag/* /usr/local/share/urjtag
		echo "installed jtag files"
	fi

	install_bin "./openocd/openocd"
	if [[ -d "./openocd" ]] ; then
		mkdir -p /usr/local/share/openocd
		cp -fR ./openocd/* /usr/local/share/openocd
		echo "installed openocd shared files"
	fi

	install_bin "./bin/nipspy"
	install_bin "./bin/nipserial"
	install_bin "./bin/cb_detect"
	install_bin "./bin/sys-detect"
	install_bin "./bin/niprom"
	install_bin "./bin/setled"

	#/usr/local/sbin
	if [[ -e "./bin/force-logrotate" ]] ; then
		mkdir -p /usr/local/sbin
		cp -f ./bin/force-logrotate /usr/local/sbin
		echo "installed force-logrotate"
	fi

	if [[ -e "./bin/nomad-rppl-update" ]] ; then
		mkdir -p /usr/local/sbin
		cp -f ./bin/nomad-rppl-update /usr/local/sbin/rppl-update
		echo "installed rppl-update"
	fi

	if [[ -e "./bin/nomad-run-rppl-update" ]] ; then
		mkdir -p /usr/local/sbin
		cp -f ./bin/nomad-run-rppl-update /usr/local/sbin/run-rppl-update
		echo "installed run-rppl-update"
	fi

	if [[ -e "./bin/start-cob" ]] ; then
		mkdir -p /usr/local/sbin
		cp -f ./bin/start-cob /usr/local/sbin
		echo "installed start-cob"
	fi

	if [[ -e "./bin/stop-cob" ]] ; then
		mkdir -p /usr/local/sbin
		cp -f ./bin/stop-cob /usr/local/sbin
		echo "installed stop-cob"
	fi



	#/usr/local/rppl
	if [[ -d "./deb" ]] ; then
		mkdir -p /usr/local/rppl
		cp -fd ./deb/linux*.deb /usr/local/rppl

		echo "copied linux *.deb files"
		echo
	fi

	#/usr/local/rppl/python
	local PYDIR=/usr/local/rppl/python
	echo "installing python packages"

	local pyutils=$(most_recent ./python/Nomad_Utils*.whl)
	if [[ ! -z "${pyutils}" ]] ; then
		mkdir -p ${PYDIR}
		cp -f ${pyutils} ${PYDIR}
		pip3 install ${PYDIR}/$(basename ${pyutils})

		echo "installed $(basename ${pyutils})"
	fi

	local niptest=$(most_recent ./python/Niptest*whl)
	if [[ ! -z "${niptest}" ]] ; then
		mkdir -p ${PYDIR}
		cp -f ${niptest} ${PYDIR}
		pip3 install ${PYDIR}/$(basename ${niptest})
		echo  "installed $(basename ${niptest})"
	fi
	echo "installed python packages"
	echo


	#/usr/rppl
	install_bin "./bin/start-wifi"  "/usr/rppl"
	install_bin "./bin/stop-wifi"  "/usr/rppl"
	install_bin "./bin/start-bluetooth" "/usr/rppl"
	install_bin "./bin/stop-bluetooth"  "/usr/rppl"
	echo

	install_bin "./bin/${NIPEXEC}" "/usr/rppl"
	( cd /usr/rppl && ln -fs ${NIPEXEC} nipexec )

	install_bin "./bin/${NIPEXEC}-debug" "/usr/rppl"
	echo
	
	if [[ -e "./nipexec_release_notes.md" ]] ; then
		echo "Installing release notes..."
		install_bin_as ./nipexec_release_notes.md /usr/rppl/nipexec_release_notes.md 0644
	fi	

	#/usr/local/rppl/lib
	install_deb ./deb/nomad-libs*.deb
	install_deb ./deb/nomad-libnipboard*.deb

	#nipc.conf
	_RIPPLE_SYSTEM=$(./bin/nomad-exec ./bin/sys-detect)
	if [[ -e $(which nomad-version) ]] ; then
		_tmp_sys=$(nomad-version -r)
		case ${_tmp_sys} in
		"2000")
			if [[ "${_RIPPLE_SYSTEM}" != "NOMAD" ]] ; then
				echo "inconsistent RIPPLE SYSTEM detected."
				echo "${_RIPPLE_SYSTEM} != ${_tmp_sys}"
				echo "using SYSTEM = NOMAD"
			fi
			_RIPPLE_SYSTEM="NOMAD"
			;;
		"3153")
			if [[ "${_RIPPLE_SYSTEM}" != "NAKED_NOMAD" ]] ; then
				echo "inconsistent RIPPLE SYSTEM detected."
				echo "${_RIPPLE_SYSTEM} != ${_tmp_sys}"
				echo "using SYSTEM = NAKED_NOMAD"
			fi

			_RIPPLE_SYSTEM="NAKED_NOMAD"
			;;
		"4000")
			if [[ "${_RIPPLE_SYSTEM}" != "QUESTHD" ]] ; then
				echo "inconsistent RIPPLE SYSTEM detected."
				echo "${_RIPPLE_SYSTEM} != ${_tmp_sys}"
				echo "using SYSTEM = QUESTHD"
			fi

			_RIPPLE_SYSTEM="QUESTHD"
			;;
		"4001")
			if [[ "${_RIPPLE_SYSTEM}" != "QUESTHD_STIM" ]] ; then
				echo "inconsistent RIPPLE SYSTEM detected."
				echo "${_RIPPLE_SYSTEM} != ${_tmp_sys}"
				echo "using SYSTEM = QUESTHD_STIM"
			fi

			_RIPPLE_SYSTEM="QUESTHD_STIM"
			;;
		"4400")
			if [[ "${_RIPPLE_SYSTEM}" != "TREK" ]] ; then
				echo "inconsistent RIPPLE SYSTEM detected."
				echo "${_RIPPLE_SYSTEM} != ${_tmp_sys}"
				echo "using SYSTEM = TREK"
			fi

			_RIPPLE_SYSTEM="TREK"
			;;
		"4500")
			if [[ "${_RIPPLE_SYSTEM}" != "EX_SUMMIT" ]] ; then
				echo "inconsistent RIPPLE SYSTEM detected."
				echo "${_RIPPLE_SYSTEM} != ${_tmp_sys}"
				echo "using SYSTEM = EX_SUMMIT"
			fi

			_RIPPLE_SYSTEM="EX_SUMMIT"
			;;
		*)
			echo "unable to detect system type"
			echo "sys-detect [${_RIPPLE_SYSTEM}]"
			echo "nomad-version [${_tmp_sys}]"
			echo "using SYSTEM = NOMAD"
			_RIPPLE_SYSTEM="NOMAD"
			;;
		esac
	fi

	echo "SYSTEM = ${_RIPPLE_SYSTEM}" > /etc/nipc.conf
	[[ "${OPT_TCP}" == "True" ]] && echo "TCP = true" >> /etc/nipc.conf
	echo "COB = False" >> /etc/nipc.conf
	echo "LOW_LATENCY_MODE = False" >> /etc/nipc.conf
	echo "LOW_LATENCY_SPIKES = False" >> /etc/nipc.conf
	echo "installed nipc.conf"
	echo "waiting for filesystem to sync"
	sync

	echo  "Installing ${pretty_name} services"
	udevadm control --reload-rules
	udevadm trigger
	systemctl enable /etc/systemd/system/rppl-nip.service
	systemctl daemon-reload

	echo "${pretty_name} programs installed"
	echo
}


install_runit() {
	local deb="./deb/runit_2.1.2-3_i386.deb"
	[[ -e "${deb}" ]] || { echo "runit not found."; return; }

	local name=$(dpkg-deb -I ${deb} | grep 'Package:' | awk '{print $2}')
	local vers=$(dpkg-deb -I ${deb} | grep 'Version:' | awk '{print $2}')

	if dpkg -s ${name} &> /dev/null ; then
		old_vers=$(dpkg-query -W -f'${Version}\n' ${name})
		if dpkg --compare-versions "${vers}" gt "${old_vers}" ; then
			echo "detected older version of runit, removing."
			dpkg --purge ${name}
		else
			echo "runit is most recent version"
			systemctl stop runit.service
			systemctl disable runit.service
			return
		fi
	fi

	echo "installing runit"
	DEBIAN_FRONTEND=noninteractive dpkg -i "${deb}"
	systemctl stop runit.service
	systemctl disable runit.service
}

enable_rsync() {
    echo "enabling rsync service"
    systemctl enable rsync
    if (( $? != 0)) ; then
	echo "Unable to activate rsync service"
	./bin/setled red
	exit 1
    fi
}


install_new_nomad_kernel() {
	local new_deb=$1

	echo "Installing new kernel : ${new_deb}"

	pushd . > /dev/null
	cd /usr/local/rppl
	DEBIAN_FRONTEND="noninteractive" dpkg --force-all -i ${new_deb}
	if (( $? != 0 )) ; then
		echo "Unable to install kernel: ${new_deb}"
		popd > /dev/null
		./bin/setled red
		exit 1
	fi
	popd > /dev/null

	RESTART="reboot"
}

check_nomad_kernel() {
	local cur new new_deb

	echo
	echo "Checking ${pretty_name} kernel"
	new_deb=$(ls ./deb/linux-image* \
		  | sort -r -V  \
		  | head -n 1 \
		  | xargs basename )
	new=$(echo "${new_deb}" | sed 's/linux-image-\([^_]*\)_.*$/\1/g')
	cur=$(uname -r)
	to_install=$(echo -e "${new}\n${cur}" | sort -r -V | head -n 1)

	if [[ "${cur}" != "${to_install}" ]] ; then
		install_new_nomad_kernel ${new_deb}
	else
		echo "kernel ${cur} is most recent."
	fi

	NEW_LINUX_KERNEL="${new}"
}


install_microprocessor_firmware() {
	local ver=$1
	echo " Need to install microprocessor firmware ${ver}"

	mkdir -p /lib/firmware/rppl
	rm -f /lib/firmware/rppl/nomad_mcu-*hex
	cp -d ./firmware/nomad_mcu-*hex /lib/firmware/rppl

	pushd . > /dev/null

	cd /lib/firmware/rppl

	if  [[ ! -e "nomad_mcu-${ver}.hex" ]] ; then
		echo "unable to find uc-firmware: ${ver}"
		popd > /dev/null
		return
	fi

	ln -fs nomad_mcu-${ver}.hex nomad_mcu.hex

	LOOP_MAX=5
	for (( i=0; i < LOOP_MAX; i++ )); do
		echo "trying to install nomad_mcu-${ver}.hex"
		openocd -fnomad-mcu.cfg -s /lib/firmware/rppl
		if [[ $? -eq 0 ]] ; then
			echo "     installed  nomad_mcu-${ver}.hex"
			echo
			break
		fi

		echo "XX install failed.  Trying again."
	done

	popd > /dev/null

	echo "microprocessor firmware ${ver} installed."
}

check_microprocessor_firmware() {
	local cur all new

	echo  "Checking on microprocesor firmware"

	cur=$(nomad-version -u)
	all=$(ls ./firmware/nomad_mcu-*hex \
              | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+')
	new=$(echo "${cur} ${all}" | tr ' ' '\n' | sort -ruV | head -n1)

	if [[ "${cur}" != "${new}" ]]; then
		install_microprocessor_firmware ${new}
	elif [[ ! -z "${OPT_FORCE}" ]] ; then
		echo "FORCED install"
		install_microprocessor_firmware ${new}
	else
		echo "microprocessor firmware ${cur} is most recent."
	fi

	NEW_MICROCONTROLLER_FW="${new}"
}

install_fpga_firmware() {
	local ver=$1
	echo " Need to install FPGA firmware ${ver}"

	mkdir -p /lib/firmware/rppl
	rm -f /lib/firmware/rppl/nomad_fpga*.bin
	rm -f /lib/firmware/rppl/nomad-*.svf

	cp -fd ./firmware/nomad_fpga*.bin /lib/firmware/rppl
	cp -f ./firmware/bscan_spi* /lib/firmware/rppl

	pushd . >/dev/null
	cd /lib/firmware/rppl

	if [[ ! -e  nomad_fpga-${ver}.bin ]] ; then
		echo "unable to find firmware  ${ver}"
		popd > /dev/null
		return
	fi

	ln -fs nomad_fpga-${ver}.bin nomad_fpga.bin

	(sleep 2; microcontroller --begin-flashing) &
	echo "Installing FPGA firmware"

	rmmod nipc
	openocd -fnomad-fpga.cfg -s /lib/firmware/rppl
	popd >/dev/null

	microcontroller --end-flashing
	echo "installed nomad_fpga-${ver}.bin"

	# this can eventually be restart as soon as we figure out how not to
	# keep running updates as soon as the isolated port powers up.
	RESTART="shutdown"
}

check_fpga_firmware() {
	local cur all new

	echo  "Checking on FPGA firmware"

	cur=$(nomad-version -f)
	all=$(ls ./firmware/nomad_fpga-*bin \
              | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+')
	new=$(echo "${cur} ${all}" | tr ' ' '\n' | sort -ruV | head -n1)

	if [[ "${cur}" != "${new}" ]]; then
		install_fpga_firmware ${new}
	elif [[ ! -z "${OPT_FORCED}" ]] ; then
		echo "FORCED install"
		install_fpga_firmware ${new}
	else
		echo "FPGA firmware ${cur} is most recent."
	fi

	NEW_FPGA_FW="${new}"
}

check_nomad_firmware() {
	echo
	echo "Verifying ${pretty_name} firmware"
	check_microprocessor_firmware
	echo
	check_fpga_firmware
	echo
}

delete_version_info() {
	rm -f /etc/rppl_version
}

write_version_info() {
	module_dir="/lib/modules/${NEW_LINUX_KERNEL}/kernel/drivers/rppl"
	cat <<-EOS > /etc/rppl_version
		kernel = ${NEW_LINUX_KERNEL}
		nipc_driver = $(modinfo -F version ${module_dir}/nipc.ko)
		nipc_firmware = ${NEW_FPGA_FW}
		microcontroller_firmware = ${NEW_MICROCONTROLLER_FW}
		nipexec = ${NIPEXEC}
		build_tag = ${BUILD_TAG}
		update = ${UPDATE_FILE}
	EOS
}


###############################################################################
#
#                            BEGIN SCRIPT HERE
#
###############################################################################

logfile=/var/log/nip-update.log
source ./build.info

LAST_UPDATE=$(grep -e '^update' /etc/rppl_version | sed 's/.*=\s*//g')
echo "LAST_UPDATE: ${LAST_UPDATE}"
echo "UPDATE_FILE: ${UPDATE_FILE}"

#output to log file
exec &> >(tee -a "${logfile}")

echo
echo "[$(date)] Beggining rppl ${pretty_name} update."
echo

add_nipc_user
add_ripple_user
delete_version_info
verify_running_on_nomad
remove_old_nomad_programs
install_new_nomad_programs
install_runit
# enable_rsync  -- off by default, for security
set_ripple_permissions
check_nomad_kernel
check_nomad_firmware
write_version_info

#for now force a shutdown on any nipexec install
RESTART="shutdown"

echo
echo "[$(date)] update completed successfully"
echo

if [[ "${RESTART}" == "shutdown" ]] ; then
	touch /SHUTDOWN
elif [[ "${RESTART}" == "reboot" ]] ; then
	touch /REBOOT
fi

sync
exit 0
