#!/bin/bash
################################################################################
# Auto install/update deCONZ for Raspberry Pi (stable and beta channel).
#  - This script is usually copied to /tmp and executed from there.
#  - Dont call this script directly use deCONZ-update.sh from deCONZ package instead.
################################################################################
APP=deconz
VERSION_ALPHA=2.05.69
VERSION_BETA=2.05.69
VERSION_STABLE=2.05.67
FW_AVR_VERSION=0x26330500
FW_R21_VERSION=0x264a0700
FW_R21_VERSION_NEED_UPDATE=0x26420700

# auto configure system
MAINUSER=$(getent passwd 1000 | cut -d: -f1)
DECONZ_CONF_DIR="/home/$MAINUSER/.local/share"

# extract channel from this script filename
CHANNEL=$(basename $(echo "$0" | cut -d'-' -f3) .sh)

CONFIG_INI=""
ZLLDB=""
OS_ID=$(cat /etc/os-release | sed -n 's/^ID=\(.*\)/\1/p')
#OS_VERSION=$(cat /etc/os-release | sed -n 's/^VERSION="[0-9]\s(\(.*\))"/\1/p')
WGETVERSION=$(dpkg -s wget | grep -e "^Version:" | cut -d' ' -f2)
CURVERSION=$(dpkg -s deconz | grep -e "^Version:" | cut -d' ' -f2)
RPIREV=$(cat /proc/cpuinfo | grep Revision | cut -d':' -f2 | xargs)
USERAGENT="User-Agent: Wget/${WGETVERSION} (GNU/Linux) deCONZ/${CURVERSION} ${OS_ID}/${OS_VERSION_NR}"
USER1=$(getent passwd 1000 | cut -f1 -d:)
OTAUDIR="/home/${USER1}/otau"
WD_SCRIPT="test-deconz.sh"
SUDO="sudo"
UPDATE_SERVICE=0
DECONZ_PID=$(pidof deCONZ)
DEV=""
URL="phoscon.de/repos/apt/deconz/deconz_repo/pool/main/d/deconz"

DOCKER=0

if [ "$OS_ID" == "ubuntu" ]; then
	OS_VERSION=`cat /etc/os-release | grep '^VERSION_CODENAME=' | cut -d '=' -f 2`
	ARCH="amd64"
	# not supported yet
	exit 1
elif [ "$OS_ID" == "raspbian" ]; then
	OS_VERSION=$(cat /etc/os-release | sed -n 's/^VERSION="[0-9]\s(\(.*\))"/\1/p')
	OS_VERSION_NR=$(cat /etc/os-release | grep VERSION_ID | cut -d'=' -f2 | xargs)
	ARCH="armhf"
else
	echo "unknown operation system $OS_ID"
	exit 1
fi

if [[ "$CHANNEL" = "beta" ]]; then
	VERSION="$VERSION_BETA-${OS_ID}-${OS_VERSION}-${CHANNEL}"
elif [[ "$CHANNEL" = "alpha" ]]; then
	#VERSION="$VERSION_ALPHA-${OS_ID}-${OS_VERSION}-${CHANNEL}"
	VERSION="$VERSION_ALPHA-${OS_ID}-jessie-${CHANNEL}"
elif [[ "$CHANNEL" = "stable" ]]; then
	VERSION="$VERSION_STABLE-${OS_ID}-${OS_VERSION}-${CHANNEL}"
else
	echo "unknown update channel $CHANNEL"
	exit 1
fi

# phoscon.de/repos/apt/deconz/deconz_repo/pool/main/d/deconz/deconz_2.05.64-raspbian-jessie-alpha_armhf.deb
APPFILE="deconz_${VERSION}_${ARCH}.deb"

if [[ $UID -eq 0 ]]; then
	echo "don't use sudo"
	SUDO=""
else
	echo "use sudo"
fi

cat /proc/1/cgroup | grep docker > /dev/null

if [ $? -eq 0 ]; then
	DOCKER=1
	# fallback when running as root; e.g. in a docker container
	if [ -d "/root/.local/share/dresden-elektronik" ]; then
		DECONZ_CONF_DIR="/root/.local/share"
	fi
fi

drs=("data/dresden-elektronik/deCONZ/config.ini" "dresden-elektronik/deCONZ/config.ini" "deCONZ/config.ini")
for i in "${drs[@]}"; do
	if [ -f "${DECONZ_CONF_DIR}/$i" ]; then
		CONFIG_INI="${DECONZ_CONF_DIR}/$i"
		break
	fi
done

if [ ! -f "$CONFIG_INI" ]; then
	# might have been deleted
	CONFIG_INI=""
fi

if [[ -n "$CONFIG_INI" ]]; then
	# disable html5 appcache
	sed -i "/appcache=true/c appcache=false" $CONFIG_INI
fi

# check which device deCONZ is connected to
if [[ -z $DEV ]] && [[ -n $DECONZ_PID ]]; then
	for i in "/dev/serial0" "/dev/ttyS0" "/dev/ttyUSB0" "/dev/ttyUSB1" "/dev/ttyAMA0" "/dev/ttyACM0" "/dev/ttyACM1"; do

		$SUDO ls -l /proc/$DECONZ_PID/fd | grep $i > /dev/null
		if [ $? -eq 0 ]; then
			DEV=$i
			break
		fi
	done
fi

function backupDatabase() {

	local TIMEOUT=10

	while [[ $TIMEOUT -gt 0 ]]; do
		pidof deCONZ > /dev/null
		if [ $? -eq 1 ]; then
			break
		fi

		sleep 1
		TIMEOUT=$((TIMEOUT - 1))
	done

	if [[ -z "$ZLLDB" ]]; then
		# look for latest config in specific order
		drs=("data/dresden-elektronik/deCONZ/zll.db" "dresden-elektronik/deCONZ/zll.db" "deCONZ/zll.db")
		for i in "${drs[@]}"; do
			if [ -f "${DECONZ_CONF_DIR}/$i" ]; then
				ZLLDB="${DECONZ_CONF_DIR}/$i"
				echo "use database file $ZLLDB"
				break
			fi
		done
	fi

	if [ ! -f "$ZLLDB" ]; then
		# might have been deleted
		ZLLDB=""
	fi

	if [[ -n $ZLLDB && -f "$ZLLDB" ]]; then
		cp "${ZLLDB}" "${ZLLDB}.bak.${CURVERSION}"
	fi
}

function updateFirmware() {
	if [[ $DOCKER -eq 1 ]]; then
		return
	fi

	## don't update when deCONZ is running
	pidof deCONZ > /dev/null
	if [ $? -eq 0 ]; then
		return
	fi

	if [[ -n "$ZLLDB" ]]; then
		sqlite3 $ZLLDB "select * from zbconf" | grep $FW_AVR_VERSION > /dev/null
		# check if latest version is (or was) already installed
		if [ $? -eq 0 ]; then
			return
		fi
	fi

	if [[ -z "$DEV" ]]; then
		return
	elif [[ -z "$ZLLDB" ]]; then
		return
	elif [[ "$DEV" =~ .*ttyAMA.* ]] || [[ "$DEV" =~ .*serial0 ]] || [[ "$DEV" =~ .*ttyS0 ]]; then
		# RaspBee
		# check if latest version is (or was) already installed
		sqlite3 $ZLLDB "select * from zbconf" | grep $FW_AVR_VERSION > /dev/null
		if [ $? -eq 0 ]; then
			return
		fi
		$SUDO GCFFlasher_internal -f "/usr/share/deCONZ/firmware/deCONZ_Rpi_${FW_AVR_VERSION}.bin.GCF"
		$SUDO GCFFlasher_internal -r
	elif [[ "$DEV" =~ .*ttyUSB.* ]]; then
		# ConBee
		# check if latest version is (or was) already installed
		sqlite3 $ZLLDB "select * from zbconf" | grep $FW_AVR_VERSION > /dev/null
		if [ $? -eq 0 ]; then
			return
		fi
		$SUDO GCFFlasher_internal -d "$DEV" -f "/usr/share/deCONZ/firmware/deCONZ_Rpi_${FW_AVR_VERSION}.bin.GCF"
		$SUDO GCFFlasher_internal -d "$DEV" -r
	elif [[ "$DEV" =~ .*ttyACM0.* ]]; then
		# ConBee II
		# check if latest version is (or was) already installed
		sqlite3 $ZLLDB "select * from zbconf" | grep $FW_R21_VERSION_NEED_UPDATE > /dev/null
		# TODO use bc to compare firmware versions
		if [ $? -ne 0 ]; then # assume newer firmware installed
			return
		fi
		$SUDO GCFFlasher_internal -d "$DEV" -f "/usr/share/deCONZ/firmware/deCONZ_ConBeeII_${FW_R21_VERSION}.bin.GCF"
	fi
}

# function that is called when the script exits
function finish {
    # remove running script
    $SUDO rm -f $0
}

#whenver the script exits call the function "finish"
trap finish EXIT

PROXY=${http_proxy:-}
if [[ ! -z "$PROXY" ]]; then
    PROXY="http_proxy=${PROXY}"
fi

systemctl -q is-active deconz-update
if [ $? -eq 0 ]; then
	echo "installing via deconz-update.service. UID=$UID"
	UPDATE_SERVICE=1
fi

echo "download $APPFILE in $CHANNEL channel"

# check if deCONZ is running and quit if so
#if [ "$(pidof deCONZ)" ] && [ $? -eq 1 ]; then
#	echo "deCONZ is running, please close before proceed with update"
#	exit 1
#fi

# stop watchdog if deCONZ test script is installed
if [ -e "/etc/watchdog.d/${WD_SCRIPT}" ]; then
	systemctl status watchdog.service > /dev/null
	if [ $? -eq 0 ]; then
		echo "stop watchdog while update deCONZ"
		$SUDO systemctl stop watchdog.service > /dev/null
	fi

	# no more needed
	rm -f "/etc/watchdog.d/${WD_SCRIPT}"
fi

if [ "$OS_ID" = "raspbian" ]; then
	USERAGENT="User-Agent: Wget/${WGETVERSION} (linux-gnueabihf) deCONZ/${CURVERSION} rpirev/${RPIREV} ${OS_ID}/${OS_VERSION_NR}"
fi

if [ "$OS_ID" = "raspbian" ] && [ "$OS_VERSION" = "wheezie" ]; then
	exit 1
fi

if [ "$OS_ID" = "raspbian" ] && [ "$OS_VERSION" = "jessie" ] && [ "$CHANNEL" = "stable" ]; then
	# on Raspbian Jessie RaspBee can co exist with bluetooth
	#egrep -q -e "^enable_uart=1" /boot/config.txt
	#if [ $? -eq 1 ]; then
	#	sudo sed -i s/^enable_uart=.*//g /boot/config.txt
	#	sudo sh -c 'echo "enable_uart=1" >> /boot/config.txt'
	#fi

	#egrep -q -e "console=serial0" /boot/cmdline.txt
	#if [ $? -eq 0 ]; then
	#	sudo sed -i s/console=serial0,115200//g /boot/cmdline.txt
	#fi

	egrep -q -e "^dtoverlay=pi3-miniuart-bt-overlay" /boot/config.txt
	if [ $? -eq 1 ]; then
		$SUDO sed -i s/^dtoverlay=pi3-disable-bt.*//g /boot/config.txt
		$SUDO sh -c 'echo "dtoverlay=pi3-miniuart-bt-overlay" >> /boot/config.txt'
	fi
fi

# check if otau dir exists
if [ ! -d "$OTAUDIR" ]; then
	echo creating otau directory
	mkdir -p ${OTAUDIR}
fi

# remove 'old' deCONZ package if exist
if [ -e "${APPFILE}" ]; then
	rm -f ${APPFILE}
fi

# check for deCONZ
dpkg --compare-versions ${CURVERSION} eq ${VERSION}
if [ $? -ne 0 ]; then

	$SUDO apt-get update -y

	if [ $? -ne 0 ]; then
		#exit 1
		echo "error during apt-get update. rc: $?"
	fi

	# download deCONZ package
	wget --user-agent="${USERAGENT}" ${URL}/${APPFILE}

	if [ $? -ne 0 ]; then
		# todo check signature
		echo "failed to download script return code: $?"
		exit 1
	fi

	# install deCONZ
	$SUDO dpkg -i ${APPFILE}

	if [ $? -ne 0 ]; then
		echo $?
	fi

	# install dependencies
	$SUDO apt-get -y install -f

	if [ $? -ne 0 ]; then
		exit 1
	fi

	$SUDO apt-get install -y ca-certificates

	# cleanup
	if [ -e "${APPFILE}" ]; then
		rm -f ${APPFILE}
	fi

fi

# sync filesystem
sync

$SUDO systemctl daemon-reload

if [[ $DOCKER -eq 1 ]]; then
	backupDatabase
	exit 0
fi

# running from old deCONZ-autostart.sh
if [[ $UID -ne 0 ]]; then
	$SUDO systemctl start deconz-gui

	# remove control
	sleep 10
	killall deCONZ-autostart.sh
else
	# deconz-update.service is in charge
	#
	dpkg --compare-versions ${CURVERSION} lt 2.04.94
	if [ $? -eq 0 ]; then
		# versions up to 2.4.93
		echo "restart to complete, since installed update script version $CURVERSION is to old"
		backupDatabase
		reboot
	fi

	# (1) systemd/headless
	systemctl -q is-active deconz
	if [ $? -eq 0 ]; then
		systemctl stop deconz
		backupDatabase
		systemctl start deconz
		exit 0
	fi

	# (2) systemd/gui
	systemctl -q is-active deconz-gui
	if [ $? -eq 0 ]; then
		systemctl stop deconz-gui
		backupDatabase
		updateFirmware
		systemctl start deconz-gui
		exit 0
	fi

	killall deCONZ

	# (3) plain in graphical environment
	systemctl -q is-active lightdm
	if [ $? -eq 0 ]; then
		backupDatabase
		updateFirmware
		systemctl start deconz-gui
		exit 0
	fi

	# (4) plain as headless
	systemctl start deconz
	exit 0
fi


# reboot so that all is written properly to the sd-card
# and new deCONZ-autostart.sh will be started after bootup
if [ "$CHANNEL" = "stable" ] && [ -e "/home/pi/.config/autostart/deCONZ.desktop" ]; then
	$SUDO reboot
fi

exit 0
