#! /bin/sh

amp_mute() {
	# mute by bringing AVATA_MUTE pin low
	[ -e /sys/class/gpio/gpio505 ] || echo 505 > /sys/class/gpio/export
	echo out > /sys/class/gpio/gpio505/direction
	echo 0 > /sys/class/gpio/gpio505/value
}

amp_unmute() {
	# unmute by bringing AVATA_MUTE pin high
	echo 1 > /sys/class/gpio/gpio505/value
}

# load common functions first
. /usr/share/nsdk/settings-functions.sh

SCRIPTS_PATH=/usr/share/nsdk/nsdk-init.d/

case "$1" in
start)
	# echo V > /dev/watchdog
	# sfuflags -f boot_count -v 0
	# exit 0
	echo -n "Starting nSDK components"

	# sync the filesystem; esp. useful during 1st start to make sure all
	# package-configuration changes are correctly written to the flash
	sync

	# if proxy need to be enabled, uncomment the following line and
	# set propper values for proxyHost and proxyPort
	#export http_proxy=http://proxyHost:proxyPort/

	# use UTF-8 encoding for QFile
	export LC_CTYPE=C.UTF-8

	# panic on oops (which will reboot the device)
	sysctl -w kernel.panic_on_oops=1
	sysctl -w kernel.panic=5

	# update hwrevision file if necessary
	hwrevision.sh

	# Boost cpu speed to max available.
	echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

	# Set realtime limits
	if [ -f /proc/sys/kernel/sched_rt_runtime_us ]; then
		echo 80000 > /proc/sys/kernel/sched_rt_runtime_us
		echo 100000 > /proc/sys/kernel/sched_rt_period_us
	fi

	# If the autogrouping functionality of the scheduler is enabled
	# then the traditional meaning of nice(1) is only on a per-session
	# basis.  Autogrouping could lead to scheduling surprises, so
	# disable it.  See this link for more info:
	#
	# https://superuser.com/questions/805599/nice-has-no-effect-in-linux-unless-the-same-shell-is-used/1151279#1151279
	if [ -f /proc/sys/kernel/sched_autogroup_enabled ]; then
		echo WARNING: Kernel has SCHED_AUTOGROUP enabled, should be disabled!
		echo 0 > /proc/sys/kernel/sched_autogroup_enabled
	fi

	# if host requested to upgrade when StreamSDK was running, a flag is set
	# and StreamSDK is restarted; the upgrade has to start before we start
	# asking for firmware versions and model IDs
	#
	# this should NEVER trigger on a cold boot
	HOST_UPGRADE_REQUEST_FLAG="/hostUpgradeRequestFlag"
	if [ -f "$HOST_UPGRADE_REQUEST_FLAG" ]; then
		echo "MCU upgrade requested, starting now ..."

		# remove the flag
		rm $HOST_UPGRADE_REQUEST_FLAG

		# retrieve current model from the last reported model ID
		storedModel=$(fw_printconst lastReportedModel 2> /dev/null)
		model="${storedModel##lastReportedModel=}"

		# retrieve upgrade file
		hostUpgradeFile="/lib/firmware/"`cat /lib/firmware/versions.json | jq -r .$model.file 2>/dev/null | tr -d '[:space:]'`

		# start upgrade
		if [ -f $hostUpgradeFile ]; then
		    # disable the hardware watchdog, otherwise the module might be rebooted mid-upgrade
            echo V > /dev/watchdog
			hostlink_cli -T 600000 -C update_host_skip_start_message 4096 $hostUpgradeFile 2>&1 | tee /tmp/log/host_update
		else
			echo "ERROR: Wanted to start requested upgrade, but file doesn't exist: $hostUpgradeFile"
		fi
	fi

	# read the host firmware version from the MCU
	mcuVersion=`hostlink_cli -C get_state 0xF001 2>/dev/null | tr -d '[:space:]'`
	if [ -z "$mcuVersion" ]; then
		echo "WARNING! MCU failed to report a firmware version (response empty or no response)."
	else
		echo "Reported MCU firmware version: $mcuVersion"
		# store the reported firmware version for later retrieval
		fw_setconst mcuVersion $mcuVersion
	fi

	# read the device model ID from the MCU
	hostlinkResponse=$(hostlink_cli -C get_state 0xF300 | cut -d$'\n' -f2)
	echo "Requested device info over HostLink, response: $hostlinkResponse"
	model=""
	resp_1=$(echo "$hostlinkResponse" | cut -d$':' -f1)
	resp_2=$(echo "$hostlinkResponse" | cut -d$':' -f2)
	if [[ "$resp_1" = "model" ]] && [[ "$resp_2" != "unknown" ]]; then
		echo "Detected model: $resp_2"
		model=$resp_2

		# Store the model identifier in the const partition for fallback/host-update retrieval
		# NOTE: This is different value from 'model'; it really only represents the last model
		# ID we've received from the MCU, whereas 'model' might contain value from 'modelOverride',
		# or the last reported ID since the last time we've conducted the postinstall. This value
		# will always be stored when the model ID is reported. This allows the host-update step
		# above to always receive the accurate ID.
		fw_setconst lastReportedModel $model
	else
		echo "Not possible to parse model from HostLink response."
		model=""
	fi
	unset hostlinkResponse resp_1 resp_2

	# store the model ID into a tmpfile for debugging
	echo $model > /tmp/modelIdentifier

	# check if an override model is set (development purposes only!)
	modelOverride=$(fw_printconst modelOverride 2> /dev/null)
	modelOverride=${modelOverride##modelOverride=}
	if [ -n "$modelOverride" ]; then
		echo "Device model id override set to: $modelOverride"
		model=$modelOverride
	fi

	# if model identification failed, use the const partition as fallback
	if [ "x$model" == "x" ]; then
		storedModel=$(fw_printconst lastReportedModel 2> /dev/null)
		if [ -z "${storedModel##lastReportedModel=}" ]; then
			echo "!!! FATAL ERROR: unable to retrieve device model !!!"
			exit 1
		else
			model="${storedModel##lastReportedModel=}"
		fi
	fi

	PATH_SETUP_DONE_FLAG=/usr/share/nsdk/postinstall_done

	# Create link to brand-based webclient (ie arcam of jbl)
	# Do this on every start. That's easier for debugging
	brand=${model%%_*}
	if [[ $brand != "jbl" && $brand != "arc" ]]; then
		echo "ERROR: Cannot find brand 'arc' or 'jbl' in model string. Defaulting to 'jbl'"
		brand="jbl"
	fi
	echo "Brand is $brand"
	echo "Creating webclient link: /www/pages/webclient/ --> /www/pages/webclient_$brand/"
	ln -s -f -n "/www/pages/webclient_$brand" "/www/pages/webclient"

	# Remove SSH password if running an engineering build (after flashing or OTA)
	if [ ! -f $PATH_SETUP_DONE_FLAG ] && [ -f /usr/share/googleCast/harman_dev_key ]; then
		echo "This is an engineering build: removing SSH password"
		sed -i 's/-s//' /etc/default/dropbear; /etc/init.d/dropbear force-reload
	fi
	# Create links at the first time (after flashing or OTA)
	if [ ! -f $PATH_SETUP_DONE_FLAG ]; then
		echo "Creating link: modelName_default --> modelName in /settings-default/system/"
		ln -s -f modelName /settings-default/system/modelName_default

		echo "Moving custom Rygel XML files into place ..."
		for filepath in /usr/share/rygel/custom-xml/*.*
		do
			file=$(basename $filepath)
			ln -sf ../custom-xml/$file /usr/share/rygel/xml/$file
		done
	fi
	# Create links at the first time (after flashing or OTA or model change)
	storedModel=$(fw_printconst model 2> /dev/null)
	if [ -f $PATH_SETUP_DONE_FLAG ] && [ "x${storedModel##model=}" == "x$model" ]; then
		echo 'Not necessary to do postinstall.'
	else
		# If retrieving the model name was successful then the symbolic links are created accordingly
		if [ -n "$model" ]; then
			# Store the model identifier in the const partition for StreamSDK retrieval
			fw_setconst model $model

			# ALSA configuration
			modelSpecPaths="/etc/asound.conf"

			# UPnP icons
			modelSpecPaths="$modelSpecPaths /usr/share/rygel/icons/120x120/rygel.png"
			modelSpecPaths="$modelSpecPaths /usr/share/rygel/icons/120x120/rygel.jpg"
			modelSpecPaths="$modelSpecPaths /usr/share/rygel/icons/48x48/rygel.png"
			modelSpecPaths="$modelSpecPaths /usr/share/rygel/icons/48x48/rygel.jpg"

			# UPnP XML files
			modelSpecPaths="$modelSpecPaths /usr/share/rygel/xml/MediaRenderer2.xml"

			for path in $modelSpecPaths
			do
				specificPath="$path"_"$model"
				if [ -f $path ]; then		# deleting general config file if present
					echo "Removing $path"
					rm -f $path
				fi
				echo "Creating link: $path --> $specificPath"
				ln -s -f $specificPath $path #-f to overwrite existing links
			done

			# In addition to creating links, /etc/cast_audio.json shall be deleted so that it gets regenerated
			echo "Removing /etc/cast_audio.json"
			rm -f /etc/cast_audio.json

			# When upgrading from legacy codebase to rebase, the bootloader environment can load bad values
			# from the environment partition (including wrong kernel parameters), which kills the USB driver
			# on Mark Levinson and AVR devices, which try to initialize their USB controllers in slave mode
			# (which is incorrect). For this reason we make sure to erase and recreate the environment
			# partition as part of the post-install step.

			echo "Resetting and re-creating the environment (/dev/mtd6) partition"

			# Copy current environment values to a temporary backup file
			fw_printenv > /tmp/env_copy

			# Erase the environment partition
			flash_erase /dev/mtd6 0 0

			# Recreate the environment partition version number keys and values
			for i in `cat /tmp/env_copy | grep _vers`; do
				j=`echo $i | awk -F "=" '{print $1}'`; # key
				k=`echo $i | awk -F "=" '{print $2}'`; # value
				fw_setenv $j $k;
			done

			# Delete all unrelated MCU firmware files (retrieve current model from the last reported model ID)
			storedModel=$(fw_printconst lastReportedModel 2> /dev/null)
			deviceModel="${storedModel##lastReportedModel=}" nsdk-firmware-file-cleanup.sh

			# Sync Airable presets with the current endpoint
			deviceModel=$model nsdk-fix-airable-presets.sh

			# Create flag file to prevent these steps at the next startup
			echo "Creating flag file $PATH_SETUP_DONE_FLAG"
			touch $PATH_SETUP_DONE_FLAG

			# Reboot the AVATAR to ensure environment partition changes stick
			sync && reboot
			exit 0
		fi
	fi

	# device specific hostname
	nsdk-hostname.sh

	# create/mount the persistent storage partition
	nsdk-settings.sh

	# possibly migrate settings
	nsdk-settings-migrate.sh

	# Init /media/settings with conf file from nymea if it isn't there yet
	# e.g. fresh boot or factory reset
	if [ -d /etc/nymea/ -a ! -e /media/settings/nymea ]; then
		cp -r /etc/nymea/ /media/settings/
	fi

	# shorten fs write caching to about 6sec - default is 30sec which means settings
	# writes can be lost for this duration if power is cut after changing any value
	#
	# NOTE: ubifs adds 3-5 seconds on top of these kernel tweaks - so we can't go much
	#       lower this way. If you need shorter times then you'll need to mount settings
	#       partition in "sync" mode instead:
	#
	#           mount -o remount,rw,sync /media/settings
	#
	#       Note this is not recommended since it cases extra flash wear - esp. when
	#       settings partition gets many writes (full logs, media database, ..).
	#
	echo 100 > /proc/sys/vm/dirty_expire_centisecs
	echo 100 > /proc/sys/vm/dirty_writeback_centisecs


	mdnsd

	mkdir -p /tmp/storage

	mkdir -p /tmp/smt
	chmod 777 /tmp/smt

	# Start FullTimezoneView virtual fs
	if [ -x /usr/bin/fullTimezoneViewFs ] && ! grep -qs fullTimezoneViewFs /proc/mounts; then
		[ -d /tmp/zoneinfo ] || mkdir /tmp/zoneinfo
		grep -qs '/tmp/zoneinfo' /proc/mounts || mount --bind /usr/share/zoneinfo /tmp/zoneinfo
		mount --make-private /tmp/zoneinfo
		/usr/bin/fullTimezoneViewFs -o zoneInfoDir=/tmp/zoneinfo,zoneMapFile=/settings-default/timeManager/timezoneAreas,allow_other /usr/share/zoneinfo
	fi

	# Initialize alsa softvol mixer elements
	aplay -q -fdat < /dev/null 2> /dev/null

	# create google cast settings folders
	[ -f /usr/sbin/nsdk-googlecast.sh ] && nsdk-googlecast.sh

	# StreamConnect is no longer started here! It starts via DBus activation.
	# for details see commit "Streamconnect: Fix STREAMEIGHT-451: Start via DBus activation"

	# when using NFS for root mount DHCP doesn't work so need to setup DNS manually
	if grep -q 'root=/dev/nfs' /proc/cmdline; then
		echo 'nameserver 8.8.8.8' > /etc/resolv.conf
	fi

	# Destination for log files
	if [ "$(get_settings_value 'system/persistentLogs' | _jq '.value.bool_')" = "true" ]; then
		if [ ! -d "/media/settings/log" ]; then
			mkdir -p "/media/settings/log"
			chmod 777 "/media/settings/log"
		fi
		[ -h "/tmp/log" ] || ln -sf "/media/settings/log" "/tmp/log"
	else
		mkdir -p "/tmp/log"
		chmod 777 "/tmp/log"
	fi

	# Destination for temporary files used by Widevine
	mkdir -p /tmp/wv/oec
	chown -R nsdk:nsdk /tmp/wv &> /dev/null

	# nSDK
	cd /usr/share/nsdk
	export LD_LIBRARY_PATH=.:/usr/lib/gstreamer-1.0/
	export PATH=.:$PATH
	export GST_DEBUG=2,*rtpjitterbuffer*:1,*rtpsession*:1,*rtpbin*:1,*fec*:1,*sink*:1,*netclock*:1,adaptivedemux:1,queue:1,qtdemux:1,*hwcounter*:4
	# Uncomment to enable .dot GStreamer pipeline dumps
	#export GST_DEBUG_DUMP_DOT_DIR=/tmp/

	# check for host FW version. Update host if first start of device after update
	# if [ -f host_update.sh ]; then
	# 	./host_update.sh boot 2>&1 | tee /tmp/log/host_update
	# fi
	deviceModel="$model" hostCurrentVersion="$mcuVersion" modelOverride="$modelOverride" nsdk-avatarupgradestatus.sh

	# do various machine-specific audio-path configurations
	if [ -f /usr/bin/audio-config ]; then
		amp_mute
		audio-config init
		# audio-config input $(cat /usr/share/nsdk/input_source)
		amp_unmute
	fi

	# start features specific scripts
	[ -d "$SCRIPTS_PATH" ] && run-parts -a start "$SCRIPTS_PATH"

	# disable su for non root user
	chmod o-x /bin/su.shadow

	# change owner for files belonge to modules that was
	# running as root user and now are running as nsdk user
	chown -R nsdk:nsdk "/media/settings/rygel" &> /dev/null
	chown -R nsdk:nsdk "/media/settings/data-rw/musiclibrary" &> /dev/null
	chown -R nsdk:nsdk "/media/settings/data-rw/playlists" &> /dev/null
	chown -R nsdk:nsdk "/media/settings/nymea" &> /dev/null

	# create symlinks to log files to keep backward compatibility
	for i in bluez cast_shell crash_uploader host_update nSDK process_manager scwd system update_engine wpasupplicant nymead websocketd; do
		ln -s "/tmp/log/$i" "/tmp/log-$i" &>/dev/null;
		ln -s "/tmp/log/$i.0" "/tmp/log-$i.0" &>/dev/null;
	done

	# list of all required capabilities for nsdk binary
	setcap cap_net_bind_service+p ./nSDK

	# start websocketd and log its output
	./nsdk_watchdog --singleRun --rotateOnly --logfileName /tmp/log/websocketd --logfileSizeConf "default" \
		--app websocketd --port 50001 --binary nc localhost 50000 &

	./nsdk_watchdog --logfileName /tmp/log/nSDK --logfileSizeConf "nSDK" \
		--app ./nSDK --loggerConfig log.properties &

	echo "."
	;;

stop)
	amp_mute
	echo -n "Stopping nSDK components"
	for i in `seq 1 50`; do
		RC=0
		pkill -9 nsdk_watchdog && RC=1
		pkill -9 -f -x '\./nSDK.*' && RC=1
		pkill -9 scwd && RC=1
		pkill -9 MediaRendererApp && RC=1
		pkill ntpd && RC=1
		pkill -9 bluetoothd && RC=1
		pkill -9 mdnsd && RC=1
		pkill -9 sddpd && RC=1
		pkill -9 swupdate && RC=1
		pkill -9 nymead && RC=1
		pkill -9 websocketd && RC=1

		# cast processes:
		pkill -9 castControlApp && RC=1
		pkill -9 cast_cli && RC=1
		pkill -9 process_manager && RC=1
		pkill -9 crash_uploader && RC=1
		pkill -9 update_engine && RC=1
		pkill -9 cast_shell && RC=1
		pkill -9 iot_audio_captu && RC=1

		if [ $RC -eq 0 ]; then
			# no process were killed
			echo
			break
		else
			# process was killed
			echo -en ".";
			usleep 100000
		fi
	done

	# stop features specific scripts
	[ -d "$SCRIPTS_PATH" ] && run-parts -a stop "$SCRIPTS_PATH"

	if [ -f /usr/bin/audio-config ]; then
		audio-config deinit
	fi

	echo V > /dev/watchdog
	echo "."
	amp_unmute
	;;

restart)
	$0 stop
	sleep 2
	$0 start
	;;

*)
	echo "Usage: /etc/init.d/nsdk {start|stop|restart}"
	exit 1
esac

exit 0
