#!/bin/bash
#
# Copyright (c) 2021 by Thomas A. Early N7TAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#!/bin/bash

CharCount () {
	local haystack=$1
	local test="\${haystack//[^$2]}"
	eval local result=$test
	return ${#result}
}

RemoveDupes () {
	local -n s=$1
	local i j
	for (( i=0; i<${#s}-1; i++)); do
		for (( j=$i+1; j<${#s}; j++)); do
			if [[ ${s:$i:1} != "." ]]; then
				if [[ ${s:$i:1} == ${s:$j:1} ]]; then
					local l=$(($j + 1))
					s="${s:0:$j}.${s:$l}"
				fi
			fi
		done
	done
	s=${s//.}
}

CheckModules () {
	# only A through Z
	modules=${1//[^A-Z]}
	if (( ${#modules} < 1 )); then
		unset modules
		clear
		echo "ERROR: You must specify at least one module, A to Z!"
		echo
		read -p "<Enter> to continue: " ans
		return
	fi

	RemoveDupes modules
	tcmodules=${modules:0:1}
}

CheckTranscodedModules () {
	local tc=${1//[^A-Z]}
	local tcorig=$tc
	if (( ${#tc} < 1 )); then
		tcmodules=${modules:0:1}
		clear
		echo "ERROR: You must specify at least one module!"
		echo "If you aren't using a transcoder, set the transcoder"
		echo "address value to the default 'none'!"
		echo
		read -p "<Enter> to continue: " ans
		return
	fi

	RemoveDupes tc

	local m=$modules_d
	if [ ! -z ${modules+x} ]; then
		m=$modules
	fi

	local i
	for ((i=0; i<${#tc}; i++)); do
		CharCount $m ${tc:$i:1}
		local count=$?
		if (( $count < 1 )); then
			local j=$((i+1))
			tc="${tc:0:$i}.${tc:$j}"
		fi
	done
	tc=${tc//.}

	if (( ${#tc} < 1 )); then
		echo "ERROR: Module(s), '$tcorig', are not in the configure modules, '$m'!"
		echo
		read -p "<Enter> to continue: " ans
		tcmodules=${modules:0:1}
		return
	fi
	tcmodules=$tc
}

SetBooleanValue ()
{
	local dvname
	local cv
	if [ -z $2 ]; then
		if [ -z ${!1+x} ]; then
			if [[ "$1" == module_[abc]_* ]]; then
				echo matches
				dvname=${1//_[abc]_/_x_}
			else
				echo does not match
				dvname=${1}_d
			fi
			cv=${!dvname}
		else
			cv=${!1}
		fi
		if [[ $cv == [tT]* ]]; then
			eval ${1}=false
		else
			eval ${1}=true
		fi
	elif [[ "$2" == [tT]* ]]; then
		eval ${1}=true
	else
		eval ${1}=false
	fi
}

EvaluateVar ()
{
	if [ -z ${!1+x} ]; then
		if [ -z "${!2}" ]; then
			echo "'' <DEFAULT>"
		else
			echo "${!2} <DEFAULT>"
		fi
	else
		if [ -z "${!1}" ]; then
			echo "''"
		else
			echo "${!1}"
		fi
	fi
}

WriteMemFile ()
{
	local file
	file="$rcfg"
	echo "# created on `date`"                                  > $file
	[ -z ${callsign+x}    ] || echo    "callsign='$callsign'"  >> $file
	[ -z ${modules+x}     ] || echo     "modules='$modules'"   >> $file
	[ -z ${ip4addr+x}     ] || echo     "ip4addr='$ip4addr'"   >> $file
	[ -z ${ip6addr+x}     ] || echo     "ip6addr='$ip6addr'"   >> $file
	[ -z ${tcaddress+x}   ] || echo   "tcaddress='$tcaddress'" >> $file
	[ -z ${tcmodules+x}   ] || echo   "tcmodules='$tcmodules'" >> $file
	[ -z ${ysfautolink+x} ] || echo "ysfautolink=$ysfautolink" >> $file
	[ -z ${ysfmodule+x}   ] || echo   "ysfmodule='$ysfmodule'" >> $file
	[ -z ${ysflocaldb+x}  ] || echo  "ysflocaldb=$ysflocaldb"  >> $file
	[ -z ${ysfdbname+x}   ] || echo   "ysfdbname='$ysfdbname'" >> $file
	[ -z ${ysfdbuser+x}   ] || echo   "ysfdbuser='$ysfdbuser'" >> $file
	[ -z ${ysfdbpw+x}     ] || echo     "ysfdbpw='$ysfdbpw'"   >> $file
	[ -z ${g3support+x}   ] || echo   "g3support=$g3support"   >> $file
	[ -z ${dbsupport+x}   ] || echo   "dbsupport=$dbsupport"   >> $file
}

WriteSRCHFile ()
{
	local file m
	file="$srch"
	echo "// Created on `date`" > $file
	echo "#define CALLSIGN \"${callsign}\"" >> $file
	if [[ "$callsign" == XRF* ]]; then
		echo "#define NO_XLX" >> $file
	fi
	if [ -z ${modules+x} ]; then
		echo "#define ACTIVE_MODULES \"${modules_d}\"" >> $file
	else
		echo "#define ACTIVE_MODULES \"${modules}\"" >> $file
	fi
	if [ ! -z ${ip4addr+x} ]; then
		echo "#define LISTEN_IPV4 \"${ip4addr}\"" >> $file
	fi
	if [ ! -z ${ip6addr+x} ]; then
		echo "#define LISTEN_IPV6 \"${ip6addr}\"" >> $file
	fi
	if [ -z ${ysfautolink+x} ]; then
		echo "#define YSF_AUTOLINK_ENABLE ${ysfautolink_d}" >> $file
	else
		echo "#define YSF_AUTOLINK_ENABLE ${ysfautolink}" >> $file
	fi
	if [ -z ${ysfmodule+x} ]; then
		echo "#define YSF_AUTOLINK_MODULE '${ysfmodule_d}'" >> $file
	else
		echo "#define YSF_AUTOLINK_MODULE '${ysfmodule}'" >> $file
	fi
	if [[ "$ysflocaldb" == true ]]; then
		echo '#define YSF_DB_SUPPORT true' >> $file
		echo "#define YSF_DB_NAME \"$ysfdbname\"" >> $file
		echo "#define YSF_DB_USER \"$ysfdbuser\"" >> $file
		echo "#define YSF_DB_PASSWORD \"$ysfdbpw\"" >> $file
	else
		echo '#define YSF_DB_SUPPORT false' >> $file
	fi
	if [ ! -z ${tcaddress+x} ]; then
		echo "#define TRANSCODER_IP \"${tcaddress}\"" >> $file
		echo "#define TRANSCODED_MODULES \"${tcmodules}\"" >> $file
	fi
	if [ -z ${g3support+x} ]; then
		m=${g3support_d}
	else
		m=${g3support}
	fi
	if [[ "$m" != true ]]; then
		echo "#define NO_G3" >> $file
	fi
	if [ -n ${dbsupport+x} ]; then
		if [ "$dbsupport" == true ]; then
			echo "#define DEBUG" >> $file
		fi
	fi
}

WriteSRCMKFile ()
{
	local file
	file="$srcm"
	echo "# Created on `date`" > $file
	[ -z ${ip4addr+x} ] || echo "ipv4 = $ip4addr" >> $file
	[ -z ${ip6addr+x} ] || echo "ipv6 = $ip6addr" >> $file
	[ -z ${tcaddress+x} ] || echo "tc_ip = $tcaddress" >> $file
	if [ -z ${g3support+x} ]; then
		echo "use_g3 = $g3support_d" >> $file
	else
		echo "use_g3 = $g3support" >> $file
	fi
	if [ -z ${dbsupport+x} ]; then
		echo "debug = $dbsupport_d" >> $file
	else
		echo "debug = $dbsupport" >> $file
	fi
	if [ -z ${ysflocaldb+x} ]; then
		echo "ysf_db = $ysflocaldb_d" >> $file
	else
		echo "ysf_db = $ysflocaldb" >> $file
	fi
}

WriteTranscoderHFile ()
{
	local file
	file="$tcdh"
	echo "// Created on `date`" > $file
	if [ -n ${tcaddress+x} ] && [[ "$tcaddress" != "local" ]]; then
		echo "#define TRANSCODER_IP \"${tcaddress}\"" >> $file
	fi
	if [ -n ${tcmodules+x} ]; then
		echo "#define TRANSCODED_MODULES \"${tcmodules}\"" >> $file
	fi
	if [ -n ${dbsupport+x} ]; then
		if [ "$dbsupport" == true ]; then
			echo "#define DEBUG" >> $file
		fi
	fi
}

WriteTranscoderMKFile ()
{
	local file
	file="$tcdm"
	echo "# created on `date`" > $file
	if [ -z ${dbsupport+x} ]; then
		echo "debug = $dbsupport_d" >> $file
	else
		echo "debug = $dbsupport" >> $file
	fi
}

WriteCfgPhpFile ()
{
	cat << EOF > $ysfs
<?php
define('DB_SERVER', 'localhost');
define('DB_USERNAME', '${ysfdbuser}');
define('DB_PASSWORD', '${ysfdbpw}');
define('DB_NAME', '${ysfdbname}');
// Attempt to connect to MySQL database
\$link = mysqli_connect(DB_SERVER, DB_USERNAME, DB_PASSWORD, DB_NAME);
// Check connection
if (\$link === false) { die("ERROR: Could not connect. " . mysqli_connect_error()); }
?>
EOF
}

WriteDBCreateFile ()
{
	cat << EOF > $dbcr
CREATE DATABASE IF NOT EXISTS ${ysfdbname};
USE ${ysfdbname};
CREATE TABLE IF NOT EXISTS ysfnodes (
	callsign VARCHAR(7) PRIMARY KEY,
	password VARCHAR(255) NOT NULL,
	txfreq INT NOT NULL DEFAULT 446500000,
	rxfreq INT NOT NULL DEFAULT 446500000,
	created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE USER IF NOT EXISTS '${ysfdbuser}'@'localhost' IDENTIFIED BY '${ysfdbpw}';
GRANT ALL PRIVILEGES ON $ysfdbname . ysfnodes TO '${ysfdbuser}'@'localhost';
FLUSH PRIVILEGES;
EOF
}

WriteCFGFiles ()
{
	WriteMemFile
	WriteSRCHFile
	WriteSRCMKFile
	if [ -z ${tcaddress+x} ]; then
		rm -f $tcdh $tcdm
	else
		WriteTranscoderHFile
		WriteTranscoderMKFile
	fi
	if [[ "$ysflocaldb" == true ]]; then
		WriteCfgPhpFile
		WriteDBCreateFile
	else
		rm -f $ysfs $dbcr
	fi
}

ListCFGFiles ()
{
	echo "===========${rcfg}============="
	cat $rcfg
	echo "===========${srch}============="
	cat $srch
	echo "===========${srcm}============="
	cat $srcm
	if [ ! -z ${tcaddress+x} ]; then
		echo "===========${tcdh}============="
		cat $tcdh
		echo "===========${tcdm}============="
		cat $tcdm
	fi
	if [[ "$ysflocaldb" ==  true ]]; then
		echo "===========${ysfs}============="
		cat $ysfs
		echo "===========${dbcr}============="
		cat $dbcr
	fi
}

# Execution starts here!
# file locations
rcfg='reflector.cfg'
srch='reflector/configure.h'
srcm='reflector/configure.mk'
tcdh='../tcd/configure.h'
tcdm='../tcd/configure.mk'
ysfs='wiresx/configure.php'
dbcr='configure.sql'
urfserv='/etc/systemd/system/urfd.service'
# default values
callsign_d='CHNGME'
modules_d='ABCF'
ip4addr_d='none'
ip6addr_d='none'
tcaddress_d='none'
ysfautolink_d=false
ysfmodule_d='D'
g3support_d=false
dbsupport_d=false
ysflocaldb_d=false
ysfdbname_d=''
ysfdbuser_d=''
ysfdbpw_d=''

# expert mode
if [[ "$1" == ex* ]]; then
	expertmode="expertMode"
fi

if [ -e reflector.cfg ]; then
	source reflector.cfg
else
	echo 'No configuration file found...'
	sleep 1
fi

if [ -z ${expertmode+x} ]; then
	if [ -e $urfserv ]; then
		echo -n "You cannot change the configuration right now beacuse there is an "
		if [ -e $urfserv ]; then
			echo "URFD server running."
		fi;
		echo "===========${rcfg}============="
		cat $rcfg
		echo
		echo "Please use radmin to uninstall the running server before attempting to modify the configuration."
		exit 1
	fi
fi

key='x'
# main loop
while [[ "$key" != q* ]]
do
	clear
	echo
	echo "        Reflector Configuration, Version #220119"
	echo
	echo    "     ******* REFLECTOR ********"
	echo -n "cs : Reflector Callsign     = "; EvaluateVar callsign{,_d}
	echo -n "am : Active Modules         = "; EvaluateVar modules{,_d}
	echo -n "g3 : Icom G3 Support        = "; EvaluateVar g3support{,_d}
	echo    "     ******* ADDRESSES ********"
	echo -n "i4 : IPv4 Listen Address    = "; EvaluateVar ip4addr{,_d}
	echo -n "i6 : IPv6 Listen Address    = "; EvaluateVar ip6addr{,_d}
	echo    "     ******* TRANSCODER ********"
	echo    "     The only TC address supported is 'local' or the default 'none'"
	echo -n "tc : Transcoder Address     = "; EvaluateVar tcaddress{,_d}
	if [ ! -z ${tcaddress+x} ]; then
		echo -n "tm : Transcoder Modules     = "; EvaluateVar tcmodules{,_d}
	fi
	echo    "     ******* SYSTEM FUSION ********"
	echo -n "ye : YSF Autolink Enable    = "; EvaluateVar ysfautolink{,_d}
	if [ ! -z ${ysfautolink+x} ]; then
		if [[ "$ysfautolink" == true ]]; then
			echo -n "ym : YSF Autolink Module    = "; EvaluateVar ysfmodule{,_d}
		fi
	fi
	echo -n "yl : YSF Local Database     = "; EvaluateVar ysflocaldb{,_d}
	if [[ "$ysflocaldb" == true ]]; then
		echo -n "yd : YSF Database Name      = "; EvaluateVar ysfdbname{,_d}
		echo -n "yu : YSF Database User      = "; EvaluateVar ysfdbuser{,_d}
		echo -n "yp : YSF Database Password  = "; EvaluateVar ysfdbpw{,_d}
	fi
	echo    "     ******* DEBUGGING ********"
	echo -n "db : Debugging Support      = "; EvaluateVar dbsupport{,_d}
	echo
	if [[ "$callsign" == URF* ]]; then
		echo    "w  : Write configuration files (overwrites any existing files) and quit"
	fi
	echo    "q  : Quit without saving"
	echo    "u  : Unset the value of <key> (revert to the default value)."
	echo
	read -p "Please input <key> <value> - omit value to toggle a true/false : " key value garbage

	if   [[ "$key" == cs*  && ${value^^} == URF* ]]; then
		callsign="${value^^}"
		callsign="${callsign:0:6}"
		unset tcaddress tcmodules ysf{autolink,module,localdb,dbname,dbuser,dbpw}
	elif [[ "$key" == am* ]]; then CheckModules "${value^^}"
	elif [[ "$key" == i4* ]]; then ip4addr="$value"
	elif [[ "$key" == i6* ]]; then ip6addr="$value"
	elif [[ "$key" == tc* ]]; then tcaddress="local"
	elif [[ "$key" == tm* ]]; then CheckTranscodedModules "${value^^}"
	elif [[ "$key" == ye* ]]; then SetBooleanValue ysfautolink "$value"
	elif [[ "$key" == ym* ]]; then
		ysfmodule="${value^^}"
		ysfmodule="${ysfmodule:0:1}"
	elif [[ "$key" == g3* ]]; then SetBooleanValue g3support "$value"
	elif [[ "$key" == db* ]]; then SetBooleanValue dbsupport "$value"
	elif [[ "$key" == yl* ]]; then SetBooleanValue ysflocaldb "$value"
	elif [[ "$key" == yd* ]]; then ysfdbname="$value"
	elif [[ "$key" == yu* ]]; then ysfdbuser="$value"
	elif [[ "$key" == yp* ]]; then ysfdbpw="$value"
	elif [[ "$key" == w* ]]; then
		WriteCFGFiles
		ListCFGFiles
		exit 0
	elif [[ "$key" == u* ]]; then
		if   [[ "$value" == cs* ]]; then unset callsign
		elif [[ "$value" == am* ]]; then unset modules
		elif [[ "$value" == i4* ]]; then unset ip4addr
		elif [[ "$value" == i6* ]]; then unset ip6addr
		elif [[ "$value" == tc* ]]; then unset tcaddress
		elif [[ "$value" == tm* ]]; then tcmodules=${modules:0:1}
		elif [[ "$value" == ye* ]]; then unset ysfautolink ysfmodule
		elif [[ "$value" == ym* ]]; then unset ysfmodule
		elif [[ "$value" == g3* ]]; then unset g3support
		elif [[ "$value" == db* ]]; then unset dbsupport
		elif [[ "$value" == yl* ]]; then unset ysflocaldb ysfdbname ysfdbuser ysfdbpw
		elif [[ "$value" == yd* ]]; then unset ysfdbname
		elif [[ "$value" == yu* ]]; then unset ysfdbuser
		elif [[ "$value" == yp* ]]; then unset ysfdbpw
		fi
	fi
done
exit 0
