#!/usr/bin/env bash

firstport=9010
[ "$DEBUG" ] || DEBUG=no

BASEDIR=$(dirname $(dirname $(realpath "$0")))
. $BASEDIR/libexec/os-helpers || exit 1

[ -z "$uuidgen" ] && end 1 "this script requires uuid generator, run sudo apt install uuid to install one"
which bc >/dev/null || end $? "this script requires bc, run sudo apt install bc to install it"
debug "EtcRoot $EtcRoot"
debug "OpenSimExe $OpenSimExe"
debug "BinDirectory $BinDirectory"

[ "$3" ] && BinDirArg=$3
[ "$2" ] && gridnick=$1 && shift
[ "$1" ] && SimName=$1 && shift

ls $EtcRoot/robust.d/*.ini 2>/dev/null | while read ini; do
	gridnick=$(basename $ini .ini | sed "s/ //g")
	for file in "$ini" "$EtcRoot/grids/$gridnick/Robust.HG.ini" "$EtcRoot/grids/$gridnick/Robust.ini" "$(realpath "$ini")"; do
		[ -e "$file" -a -e "$(dirname "$file")/OpenSim.ini" ] && ini="$file" && break
		# log testing "$(dirname "$file")/OpenSim.ini"
	done
	echo "$gridnick $ini" >>$TMP.grids
done
ls $EtcRoot/*.OpenSim.ini 2>/dev/null | while read ini; do
	nick=$(basename $ini .OpenSim.ini)
	grep -q "^$nick[[:blank:]]" $TMP.grids 2>/dev/null && continue
	echo "$nick $ini" >>$TMP.grids
done

[ -f $TMP.grids ] && defaultGrid=$(head -1 $TMP.grids | cut -d " " -f 1)
[ -f $TMP.grids ] && echo "Known grids:"
cat $TMP.grids | sed "s:^:  :"
debug default grid $defaultGrid
[ ! "$gridnick" ] && gridnick="$defaultGrid"

readvar gridnick

RobustConfig=$(grep "^$gridnick " $TMP.grids | cut -d " " -f 2)
if [ ! "$RobustConfig" ]; then
	end 1 "No robust config found, manual setup not implemented"
fi
[ -f "$RobustConfig" ] || end 1 RobustConfig $RobustConfig not found

grep -q "\[GridInfoService\]" $RobustConfig
if [ $? -eq 0 ]; then
	debug "robust type ini file"
	crudget $RobustConfig Const || crudget $RobustConfig const
	crudget $RobustConfig Launch || crudget $RobustConfig launch
	# BinDir=$bindir
	crudget $RobustConfig GridInfoService || crudget $RobustConfig gridinfoservice
else
	debug "simulator type ini file"
	crudget $RobustConfig Const || crudget $RobustConfig const
	# gridname=$gridname
	curl -s $baseurl:$publicport/get_grid_info >$TMP.gridinfo
	which xmlstarlet >/dev/null &&
		gridnick=$(xmlstarlet sel -t -m /gridinfo -v gridnick -nl <$TMP.gridinfo)
fi
gridslug=$(echo "$gridnick" | tr [:upper:] [:lower:])

PrivatePort=${privateport:-${PrivatePort}}
PrivatePort=${PrivatePort:-8002}
firstport=$((($PrivatePort / 10 + 1) * 10))

debug grid name $gridname
debug grid nick $gridnick
debug gridslug $gridslug

readvar SimName

[ ! "$SimName" ] && end 1
simslug=$(echo "${gridnick}_$SimName" | tr [:upper:] [:lower:] | sed "s/[^[:alnum:]_]//g")
debug simslug $simslug

debug "list of core opensim directories"
# find "$CORE" -name OpenSim.exe | xargs dirname | grep "bin$" > $TMP.list
ls $BASEDIR/lib/opensim*/bin/OpenSim.exe \
	$BASEDIR/core/opensim*/bin/OpenSim.exe \
	$BinDirectory/bin/OpenSim.exe 2>/dev/null | sed "s:/OpenSim.exe$::" | sort >$TMP.list

grep -v "/opensim-[0-9\.]*/" $TMP.list >$TMP.osdirs
grep "/opensim-[0-9\.]*/" $TMP.list >>$TMP.osdirs
defaultOSDir=$(tail -1 $TMP.osdirs)
debug default CoreDirectory $defaultOSDir
echo "Found OpenSimulator distributions:"
cat $TMP.osdirs | sed "s:^:  :"
BinDir=${bindir:-${BinDir}}
BinDir=${BinDirArg:-${BinDir}}

[ ! "$BinDir" ] && BinDir=$defaultOSDir

readvar BinDir
[ -d "$BinDir" ] || end $? "$BinDir directory does not exist"
[ -f "$BinDir/OpenSim.exe" ] || end $? "$BinDir not an OpenSim bin directory"
EtcRoot=${etcdirectory:-${EtcRoot}}
[ "$EtcRoot" = "" ] && EtcRoot="$(dirname "$RobustConfig")"
debug EtcRoot $EtcRoot

[ -f "$EtcRoot/OpenSim.ini" ] &&
	debug "Using $EtcRoot/OpenSim.ini" ||
	end 1 "Configuration not found, use newgrid.sh to build $EtcRoot/ ($etcdirectory)"
cleanupIni "$EtcRoot/OpenSim.ini" >$TMP.OpenSim.ini

simConfigDir="$EtcRoot/sims/$simslug"
simConfig="$EtcRoot/sims/$simslug.ini"
ls $simConfig 2>/dev/null &&
	{
		log 1 "There is already a config for $simslug"
		if yesno "Proceed and replace the config?"; then
			debug "using $simConfig"
			# cleanupIni $simConfig > $TMP.ini || end $?
			# crudmerge $TMP.ini $simConfig || end $?
		else
			end 1 "current $simslug config left untouched"
		fi
	} || debug Creating new $simConfig

crudget $TMP.OpenSim.ini Const 2>/dev/null || crudget $TMP.OpenSim.ini const 2>/dev/null || end $? "could not get Const section from $EtcRoot/OpenSim.ini"

cat <<EOF >$TMP.launch
;; Generated by $0 $(date)

;; Parameters used by opensim-debian/bin/opensim script.
;; You can safely delete Launch section if you use another launching process
[Launch]
  SimName = "$SimName"
  simslug = "$simslug"
  BinDir = "$BinDir"
  Executable = "OpenSim.exe"
  LogConfig = "$simConfigDir/log.config"
;; End of Launch section

EOF

if [ -f $simConfig ]; then
	cleanupIni $simConfig >$TMP.ini || end $? "error while cleaning up $simConfig"
	# crudmerge $TMP.ini $TMP.launch || end $? "error while merging launch section"
	#
	# cp $TMP.saved.ini $EtcRoot/tmp.saved.ini
	# crudmerge $TMP.ini $TMP.saved.ini || end $? "error while merging $simConfig"
	# cp $TMP.ini $EtcRoot/tmp.ini
else
	cleanupIni $TMP.launch >$TMP.ini || end $?
	# cleanupIni $EtcRoot/OpenSim.ini >> $TMP.ini || end $?
fi

crudget $TMP.ini Network 2>/dev/null || crudget $TMP.ini network 2>/dev/null || end $? could not read $TMP.ini Network section

[ "$http_listener_port" ] || http_listener_port=$("$BASEDIR/bin/opensim" next port $firstport)
readvar http_listener_port
crudini --set $TMP.ini Network http_listener_port "$http_listener_port"
debug "getting db settings"
# inigrep Include_ $TMP.ini

crudget $TMP.ini DatabaseService 2>/dev/null || end $?
if [ "$ConnectionString" ]; then
	db_name=$(echo "$ConnectionString;" | sed "s/.*Database=//" | cut -d ';' -f 1)
	[ ! "$db_name" -o "$db_name" = "opensim" ] && db_name="${gridslug}_${simslug}"
else
	crudget $RobustConfig DatabaseService || end $? get DatabaseService failed
	db_name="${simslug}"
fi
db_host=$(echo "$ConnectionString;" | sed "s/.*Data Source=//" | cut -d ';' -f 1)
[ ! "$db_host" ] && db_host=localhost
db_user=$(echo "$ConnectionString;" | sed "s/.*User ID=//" | cut -d ';' -f 1)
[ ! "$db_user" ] && db_user=opensim
db_pass=$(echo "$ConnectionString;" | sed "s/.*Password=//" | cut -d ';' -f 1)
[ "$db_pass" = "****" ] && db_pass=
[ ! "$db_pass" ] && db_pass=$(randomPassword) && echo "Generated random password $db_pass"
readvar db_host db_name db_user db_pass

testDatabaseConnection $db_host $db_name $db_user "$db_pass" ||
	end $?

ConnectionString="Data Source=$db_host;Database=$db_name;User ID=$db_user;Password=$db_pass;Old Guids=true;"
crudini --set $TMP.ini DatabaseService StorageProvider "OpenSim.Data.MySQL.dll"
crudini --set $TMP.ini DatabaseService ConnectionString "\"$ConnectionString\""

remote_enabled=$(crudget $TMP.OpenSim.ini RemoteAdmin enabled)
if [ "$remote_enabled" = "true" ]; then
	# crudini --set $TMP.ini RemoteAdmin enabled true
	crudini --set $TMP.ini RemoteAdmin port $("$BASEDIR/bin/opensim" next port $((http_listener_port + 1)))
fi

crudini --set $TMP.ini Includes Include-Common "$EtcRoot/OpenSim.ini"

[ -f "$EtcRoot/Vivox.ini" ] &&
	crudini --set $TMP.ini Includes Include-Voice "$EtcRoot/Vivox.ini"

# crudini --del $TMP.ini Architecture
# crudini --set $TMP.ini Architecture Include_Architecture '"${Const|BinDirectory}/config-include/GridHypergrid.ini"'
CacheRoot=${cachedirectory:-${CacheRoot}}
eval CacheRoot=$(echo $CacheRoot | sed "s/{[a-Z]*|\([a-z]*\)}/{\\1}/i")
DataRoot=${datadirectory:-${DataRoot}}
eval DataRoot=$(echo $DataRoot | sed "s/{[a-Z]*|\([a-z]*\)}/{\\1}/i")
simConfigDir=${simconfigdir:-${simConfigDir}}
eval simConfigDir=$(echo $simConfigDir | sed "s/{[a-Z]*|\([a-z]*\)}/{\\1}/i")
debug CacheRoot $CacheRoot
debug DataRoot $DataRoot
debug simConfigDir $simConfigDir
for folder in \
	"$(dirname "$CacheRoot")" \
	"$(dirname "$DataRoot")" \
	"$(dirname "$simConfigDir")" \
	"$CacheRoot" \
	"$DataRoot" \
	"$simConfigDir" \
	"$simConfigDir/regions"; do
	[ -e "$folder" ] && continue
	mkdir "$folder" && debug created folder $folder || end $? could not create $folder
done

cleanupIni4Prod $TMP.ini &&
	cp $TMP.ini "$simConfig" &&
	ln -frs "$simConfig" "$EtcRoot/opensim.d/$simslug.ini"

ls $simConfigDir/regions/*.ini 2>/dev/null
if [ $? -ne 0 ]; then
	if yesno -y "Create first region?"; then

		RegionName=$SimName
		readvar RegionName
		[ "$RegionName" = "" ] && log $? RegionName must be provided, using $SimName && RegionName=$SimName

		RegionUUID=$($uuidgen)
		readvar RegionUUID

		Location=$("$BASEDIR/bin/opensim" next location $gridnick)
		readvar Location
		checklocation=$("$BASEDIR/bin/opensim" next location $gridnick $Location)
		[ "$checklocation" != "$Location" ] && log $? "Invalid location, using $checklocation" && Location=$checklocation

		InternalPort=$("$BASEDIR/bin/opensim" next port $((http_listener_port + 2)))
		readvar InternalPort
		checkInternalPort=$("$BASEDIR/bin/opensim" next port $InternalPort)
		[ $checkInternalPort != "$InternalPort" ] && log $? "Invalid InternalPort, using $checkInternalPort" && InternalPort=$checkInternalPort

		cat <<EOF >$simConfigDir/regions/$RegionName.ini
;; Generated by $PGM $(date)
[$RegionName]
RegionUUID = $RegionUUID
Location = $Location
SizeX = 256
SizeY = 256
SizeZ = 256
InternalAddress = 0.0.0.0
InternalPort = $InternalPort
ResolveAddress = False
ExternalHostName = SYSTEMIP
MaptileStaticUUID = 00000000-0000-0000-0000-000000000000
EOF
	fi
fi
if yesno -y "(re)start $SimName ($simslug)?"; then
	opensim restart $simslug
	end $?
fi

end $?
