#!/bin/bash

# Provides functions to query and validate values for serverconfig.xml

#################################
## Definition of options

serverconfig_ServerPort_QueryName() {
	echo "Base Port"
}
serverconfig_ServerPort_Type() {
	echo "number"
}
serverconfig_ServerPort_Default() {
	echo "25000"
}
serverconfig_ServerPort_Range() {
	echo "1024-65533"
}
serverconfig_ServerPort_Validate() {
	local I=${INSTANCE:-!}
	if [ $(checkGamePortUsed "$1" "$I") -eq 0 ]; then
		echo "1"
	else
		echo "0"
	fi
}
serverconfig_ServerPort_ErrorMessage() {
	echo "Illegal port number or port already in use by another instance."
}



serverconfig_ServerIsPublic_QueryName() {
	echo "Public server"
}
serverconfig_ServerIsPublic_Type() {
	echo "boolean"
}
serverconfig_ServerIsPublic_Default() {
	echo "true"
}
serverconfig_ServerIsPublic_ErrorMessage() {
	echo "Not a valid boolean given (true/false or yes/no or y/n)."
}



serverconfig_ServerName_QueryName() {
	echo "Server name"
}
serverconfig_ServerName_Type() {
	echo "string"
}
serverconfig_ServerName_Validate() {
	if [ ! -z "$1" ]; then
		echo "1"
	else
		echo "0"
	fi
}
serverconfig_ServerName_ErrorMessage() {
	echo "Server name cannot be empty."
}



serverconfig_ServerPassword_QueryName() {
	echo "Server password"
}
serverconfig_ServerPassword_Type() {
	echo "string"
}



serverconfig_ServerMaxPlayerCount_QueryName() {
	echo "Max players"
}
serverconfig_ServerMaxPlayerCount_Type() {
	echo "number"
}
serverconfig_ServerMaxPlayerCount_Default() {
	echo "4"
}
serverconfig_ServerMaxPlayerCount_Range() {
	echo "1-64"
}



serverconfig_GameWorld_QueryName() {
	echo "World name"
}
serverconfig_GameWorld_Type() {
	echo "enum"
}
serverconfig_GameWorld_Default() {
	echo "1"
}
serverconfig_GameWorld_Values() {
	config_allowed_values=("Navezgane" "MP Wasteland Horde" "MP Wasteland Skirmish" "MP Wasteland War")
}



serverconfig_GameName_QueryName() {
	echo "Game name"
}
serverconfig_GameName_Type() {
	echo "string"
}
serverconfig_GameName_Validate() {
	if [ ! -z "$1" ]; then
		echo "1"
	else
		echo "0"
	fi
}
serverconfig_GameName_ErrorMessage() {
	echo "Game name cannot be empty."
}



serverconfig_GameDifficulty_QueryName() {
	echo "Difficulty"
}
serverconfig_GameDifficulty_Type() {
	echo "number"
}
serverconfig_GameDifficulty_Default() {
	echo "2"
}
serverconfig_GameDifficulty_Range() {
	echo "0-4"
}
serverconfig_GameDifficulty_Values() {
	config_allowed_values=("Very easy" "Easy" "Medium" "Hard" "Very hard")
}



serverconfig_GameMode_QueryName() {
	echo "Game mode"
}
serverconfig_GameMode_Type() {
	echo "enum"
}
serverconfig_GameMode_Default() {
	echo "1"
}
serverconfig_GameMode_Values() {
	config_allowed_values=("GameModeSurvivalMP" "GameModeSurvivalSP")
}



serverconfig_ZombiesRun_QueryName() {
	echo "Zombies run"
}
serverconfig_ZombiesRun_Type() {
	echo "number"
}
serverconfig_ZombiesRun_Default() {
	echo "0"
}
serverconfig_ZombiesRun_Range() {
	echo "0-2"
}
serverconfig_ZombiesRun_Values() {
	config_allowed_values=("Default day/night walk/run" "Never run" "Always run")
}



serverconfig_ShowAllPlayersOnMap_QueryName() {
	echo "Show all players on map"
}
serverconfig_ShowAllPlayersOnMap_Type() {
	echo "boolean"
}
serverconfig_ShowAllPlayersOnMap_Default() {
	echo "true"
}
serverconfig_ShowAllPlayersOnMap_ErrorMessage() {
	echo "Not a valid boolean given (true/false or yes/no or y/n)."
}



serverconfig_BuildCreate_QueryName() {
	echo "Item spawn menu"
}
serverconfig_BuildCreate_Type() {
	echo "boolean"
}
serverconfig_BuildCreate_Default() {
	echo "true"
}
serverconfig_BuildCreate_ErrorMessage() {
	echo "Not a valid boolean given (true/false or yes/no or y/n)."
}



serverconfig_DayNightLength_QueryName() {
	echo "Length of one day"
}
serverconfig_DayNightLength_Type() {
	echo "number"
}
serverconfig_DayNightLength_Default() {
	echo "45"
}



serverconfig_FriendlyFire_QueryName() {
	echo "Friendly fire"
}
serverconfig_FriendlyFire_Type() {
	echo "boolean"
}
serverconfig_FriendlyFire_Default() {
	echo "false"
}
serverconfig_FriendlyFire_ErrorMessage() {
	echo "Not a valid boolean given (true/false or yes/no or y/n)."
}



serverconfig_DayCount_QueryName() {
	echo "Day Count (Horde)"
}
serverconfig_DayCount_Type() {
	echo "number"
}
serverconfig_DayCount_Default() {
	echo "3"
}



serverconfig_FragLimit_QueryName() {
	echo "Frag limit (DM)"
}
serverconfig_FragLimit_Type() {
	echo "number"
}
serverconfig_FragLimit_Default() {
	echo "5"
}



serverconfig_MatchLength_QueryName() {
	echo "Match length (DM)"
}
serverconfig_MatchLength_Type() {
	echo "number"
}
serverconfig_MatchLength_Default() {
	echo "15"
}



serverconfig_RebuildMap_QueryName() {
	echo "Rebuild map on round restart"
}
serverconfig_RebuildMap_Type() {
	echo "boolean"
}
serverconfig_RebuildMap_Default() {
	echo "false"
}
serverconfig_RebuildMap_ErrorMessage() {
	echo "Not a valid boolean given (true/false or yes/no or y/n)."
}



serverconfig_ControlPanelEnabled_QueryName() {
	echo "Enable control panel"
}
serverconfig_ControlPanelEnabled_Type() {
	echo "boolean"
}
serverconfig_ControlPanelEnabled_Default() {
	echo "false"
}
serverconfig_ControlPanelEnabled_ErrorMessage() {
	echo "Not a valid boolean given (true/false or yes/no or y/n)."
}



serverconfig_ControlPanelPort_QueryName() {
	echo "Control panel port"
}
serverconfig_ControlPanelPort_Type() {
	echo "number"
}
serverconfig_ControlPanelPort_Default() {
	echo "8080"
}
serverconfig_ControlPanelPort_Range() {
	echo "1024-65535"
}
serverconfig_ControlPanelPort_Validate() {
	local I=${INSTANCE:-!}
	if [ $(checkTCPPortUsed "$1" "$I") -eq 0 ]; then
		echo "1"
	else
		echo "0"
	fi
}
serverconfig_ControlPanelPort_ErrorMessage() {
	echo "Illegal port number or port already in use by another instance."
}



serverconfig_ControlPanelPassword_QueryName() {
	echo "Control panel password"
}
serverconfig_ControlPanelPassword_Type() {
	echo "string"
}



serverconfig_TelnetPort_QueryName() {
	echo "Telnet port"
}
serverconfig_TelnetPort_Type() {
	echo "number"
}
serverconfig_TelnetPort_Default() {
	echo "8081"
}
serverconfig_TelnetPort_Range() {
	echo "1024-65535"
}
serverconfig_TelnetPort_Validate() {
	local I=${INSTANCE:-!}
	if [ $(checkTCPPortUsed "$1" "$I") -eq 0 ]; then
		echo "1"
	else
		echo "0"
	fi
}
serverconfig_TelnetPort_ErrorMessage() {
	echo "Illegal port number or port already in use by another instance."
}



serverconfig_TelnetPassword_QueryName() {
	echo "Telnet password"
}
serverconfig_TelnetPassword_Type() {
	echo "string"
}



serverconfig_DisableNAT_QueryName() {
	echo "Disable NAT"
}
serverconfig_DisableNAT_Type() {
	echo "boolean"
}
serverconfig_DisableNAT_Default() {
	echo "true"
}
serverconfig_DisableNAT_ErrorMessage() {
	echo "Not a valid boolean given (true/false or yes/no or y/n)."
}




serverconfig_DropOnDeath_QueryName() {
	echo "Drop on Death"
}
serverconfig_DropOnDeath_Type() {
	echo "number"
}
serverconfig_DropOnDeath_Default() {
	echo "0"
}
serverconfig_DropOnDeath_Range() {
	echo "0-3"
}
serverconfig_DropOnDeath_Values() {
	config_allowed_values=("Everything" "Toolbelt only" "Backpack only" "Delete all")
}


serverconfig_DropOnQuit_QueryName() {
	echo "Drop on Quit"
}
serverconfig_DropOnQuit_Type() {
	echo "number"
}
serverconfig_DropOnQuit_Default() {
	echo "0"
}
serverconfig_DropOnQuit_Range() {
	echo "0-3"
}
serverconfig_DropOnQuit_Values() {
	config_allowed_values=("Nothing" "Everything" "Toolbelt only" "Backpack only")
}




serverconfig_CraftTimer_QueryName() {
	echo "Craft speed"
}
serverconfig_CraftTimer_Type() {
	echo "number"
}
serverconfig_CraftTimer_Default() {
	echo "1"
}
serverconfig_CraftTimer_Range() {
	echo "0-2"
}
serverconfig_CraftTimer_Values() {
	config_allowed_values=("Instant" "Normal" "Double")
}


serverconfig_LootTimer_QueryName() {
	echo "Loot open speed"
}
serverconfig_LootTimer_Type() {
	echo "number"
}
serverconfig_LootTimer_Default() {
	echo "1"
}
serverconfig_LootTimer_Range() {
	echo "0-2"
}
serverconfig_LootTimer_Values() {
	config_allowed_values=("Instant" "Normal" "Double")
}




serverconfig_PlayerDamageGiven_QueryName() {
	echo "Damage Player->Zombies"
}
serverconfig_PlayerDamageGiven_Type() {
	echo "number"
}
serverconfig_PlayerDamageGiven_Default() {
	echo "2"
}
serverconfig_PlayerDamageGiven_Range() {
	echo "0-4"
}
serverconfig_PlayerDamageGiven_Values() {
	config_allowed_values=("50%" "75%" "100%" "150%" "200%")
}


serverconfig_PlayerDamageRecieved_QueryName() {
	echo "Damage Zombies->Player"
}
serverconfig_PlayerDamageRecieved_Type() {
	echo "number"
}
serverconfig_PlayerDamageRecieved_Default() {
	echo "2"
}
serverconfig_PlayerDamageRecieved_Range() {
	echo "0-4"
}
serverconfig_PlayerDamageRecieved_Values() {
	config_allowed_values=("50%" "75%" "100%" "150%" "200%")
}


serverconfig_EnemySenseMemory_QueryName() {
	echo "Sense memory (seconds)"
}
serverconfig_EnemySenseMemory_Type() {
	echo "number"
}
serverconfig_EnemySenseMemory_Default() {
	echo "60"
}


serverconfig_EnemySpawnMode_QueryName() {
	echo "Spawn mode"
}
serverconfig_EnemySpawnMode_Type() {
	echo "number"
}
serverconfig_EnemySpawnMode_Default() {
	echo "3"
}
serverconfig_EnemySpawnMode_Range() {
	echo "0-5"
}
serverconfig_EnemySpawnMode_Values() {
	config_allowed_values=("Disabled" "50%" "75%" "100%" "125%" "150%")
}


serverconfig_EnemyDifficulty_QueryName() {
	echo "Enemy difficulty"
}
serverconfig_EnemyDifficulty_Type() {
	echo "number"
}
serverconfig_EnemyDifficulty_Default() {
	echo "0"
}
serverconfig_EnemyDifficulty_Range() {
	echo "0-1"
}
serverconfig_EnemyDifficulty_Values() {
	config_allowed_values=("Normal" "Feral")
}




serverconfig_NightPercentage_QueryName() {
	echo "Night percentage"
}
serverconfig_NightPercentage_Type() {
	echo "number"
}
serverconfig_NightPercentage_Default() {
	echo "35"
}
serverconfig_NightPercentage_Range() {
	echo "10-90"
}



serverconfig_BlockDurabilityModifier_QueryName() {
	echo "Block durability (%)"
}
serverconfig_BlockDurabilityModifier_Type() {
	echo "number"
}
serverconfig_BlockDurabilityModifier_Default() {
	echo "100"
}




serverconfig_LootAbundance_QueryName() {
	echo "Loot abundance (%)"
}
serverconfig_LootAbundance_Type() {
	echo "number"
}
serverconfig_LootAbundance_Default() {
	echo "100"
}


serverconfig_LootRespawnDays_QueryName() {
	echo "Loot respawn delay (days)"
}
serverconfig_LootRespawnDays_Type() {
	echo "number"
}
serverconfig_LootRespawnDays_Default() {
	echo "7"
}




serverconfig_LandClaimSize_QueryName() {
	echo "Land claim size"
}
serverconfig_LandClaimSize_Type() {
	echo "number"
}
serverconfig_LandClaimSize_Default() {
	echo "7"
}


serverconfig_LandClaimDeadZone_QueryName() {
	echo "Minimum keystone distance"
}
serverconfig_LandClaimDeadZone_Type() {
	echo "number"
}
serverconfig_LandClaimDeadZone_Default() {
	echo "30"
}


serverconfig_LandClaimExpiryTime_QueryName() {
	echo "Claim expiry time (days)"
}
serverconfig_LandClaimExpiryTime_Type() {
	echo "number"
}
serverconfig_LandClaimExpiryTime_Default() {
	echo "3"
}


serverconfig_LandClaimDecayMode_QueryName() {
	echo "Claim decay mode"
}
serverconfig_LandClaimDecayMode_Type() {
	echo "number"
}
serverconfig_LandClaimDecayMode_Default() {
	echo "0"
}
serverconfig_LandClaimDecayMode_Range() {
	echo "0-2"
}
serverconfig_LandClaimDecayMode_Values() {
	config_allowed_values=("Linear" "Exponential" "Full protection")
}


serverconfig_LandClaimOnlineDurabilityModifier_QueryName() {
	echo "Claim durability modifier - online"
}
serverconfig_LandClaimOnlineDurabilityModifier_Type() {
	echo "number"
}
serverconfig_LandClaimOnlineDurabilityModifier_Default() {
	echo "4"
}


serverconfig_LandClaimOfflineDurabilityModifier_QueryName() {
	echo "Claim durability modifier - offline"
}
serverconfig_LandClaimOfflineDurabilityModifier_Type() {
	echo "number"
}
serverconfig_LandClaimOfflineDurabilityModifier_Default() {
	echo "4"
}




serverconfig_AirDropFrequency_QueryName() {
	echo "Airdrop delay (hours)"
}
serverconfig_AirDropFrequency_Type() {
	echo "number"
}
serverconfig_AirDropFrequency_Default() {
	echo "24"
}


serverconfig_MaxSpawnedZombies_QueryName() {
	echo "Maximum number of concurrent zombies"
}
serverconfig_MaxSpawnedZombies_Type() {
	echo "number"
}
serverconfig_MaxSpawnedZombies_Default() {
	echo "60"
}


serverconfig_VACEnabled_QueryName() {
	echo "Enable Valve Anti Cheat"
}
serverconfig_VACEnabled_Type() {
	echo "boolean"
}
serverconfig_VACEnabled_Default() {
	echo "true"
}
serverconfig_VACEnabled_ErrorMessage() {
	echo "Not a valid boolean given (true/false or yes/no or y/n)."
}




#################################
## Edit option functions

configEditServer() {
	local CV
	
	echo "Server"
	echo "--------------------------------"
	for CV in \
			ServerName ServerPassword ServerIsPublic ServerPort ServerMaxPlayerCount \
			DisableNAT VACEnabled MaxSpawnedZombies \
			; do
		$1 $CV
	done
	echo
}

configEditRemoteControl() {
	local CV
	
	echo "Remote control"
	echo "--------------------------------"
	for CV in \
			ControlPanelEnabled ControlPanelPort ControlPanelPassword \
			TelnetPort TelnetPassword \
			; do
		if [ "$CV" = "TelnetPort" ]; then
			echo
			echo "NOTE: Telnet will always be enabled for management purposes!"
			echo "Make sure you block external access to this port or set no password"
			echo "so the server will only listen on the loopback interface!"
			echo
		fi
		$1 $CV
	done
	echo
}

configEditGameType() {
	local CV
	
	echo "Game type"
	echo "--------------------------------"
	for CV in \
			GameName GameWorld GameMode \
			; do
		$1 $CV
	done
	echo
}

configEditGameTypeSpecific() {
	local CV
	
	echo "Options for specific game types"
	echo "--------------------------------"
	for CV in \
			DayCount FragLimit MatchLength RebuildMap \
			; do
		$1 $CV
	done
	echo
}

configEditGeneric() {
	local CV
	
	echo "Generic options"
	echo "--------------------------------"
	for CV in \
			ShowAllPlayersOnMap FriendlyFire BuildCreate \
			BlockDurabilityModifier \
			; do
		$1 $CV
	done
	echo
}

configEditDropLoot() {
	local CV
	
	echo "Drop and Loot"
	echo "--------------------------------"
	for CV in \
			DropOnDeath DropOnQuit \
			LootAbundance LootRespawnDays AirDropFrequency \
			; do
		$1 $CV
	done
	echo
}

configEditTimes() {
	local CV
	
	echo "Times / Durations"
	echo "--------------------------------"
	for CV in \
			CraftTimer LootTimer \
			DayNightLength NightPercentage \
			; do
		$1 $CV
	done
	echo
}

configEditDifficulty() {
	local CV
	
	echo "Difficulty"
	echo "--------------------------------"
	for CV in \
			GameDifficulty ZombiesRun \
			PlayerDamageGiven PlayerDamageRecieved EnemySenseMemory EnemySpawnMode EnemyDifficulty \
			; do
		$1 $CV
	done
	echo
}

configEditLandClaim() {
	local CV
	
	echo "Land claim options"
	echo "--------------------------------"
	for CV in \
			LandClaimSize LandClaimDeadZone LandClaimExpiryTime LandClaimDecayMode \
			LandClaimOnlineDurabilityModifier LandClaimOfflineDurabilityModifier \
			; do
		$1 $CV
	done
	echo
}

configEditAll() {
	configEditServer "$1"
	configEditRemoteControl "$1"
	configEditGameType "$1"
	configEditGameTypeSpecific "$1"
	configEditGeneric "$1"
	configEditDropLoot "$1"
	configEditTimes "$1"
	configEditDifficulty "$1"
	configEditLandClaim "$1"
}





#################################
## Generic worker functions


# List all defined config editing parts
# Returns:
#   List of config funcs
listConfigEditFuncs() {
	local CV
	for CV in $(declare -F | cut -d\  -f3 | grep "^configEdit.*$"); do
		CV=${CV#configEdit}
		printf "%s " "$CV"
	done
}


# List all defined config options
# Returns:
#   List of defined config options
listConfigValues() {
	local CV
	for CV in $(declare -F | cut -d\  -f3 | grep "^serverconfig_.*_Type$"); do
		CV=${CV#serverconfig_}
		CV=${CV%_Type}
		printf "%s " "$CV"
	done
}


# Validate the given value for the given option
# Params:
#   1: Option name
#   2: Value
# Returns:
#   0/1: invalid/valid
isValidOptionValue() {
	local TYPE=$(serverconfig_$1_Type)
	local RANGE=""

	if [ "$TYPE" = "enum" ]; then
		TYPE="number"
		serverconfig_$1_Values
		RANGE=1-${#config_allowed_values[@]}
	else
		if [ "$(type -t serverconfig_$1_Range)" = "function" ]; then
			RANGE=$(serverconfig_$1_Range)
		fi
	fi

	case "$TYPE" in
		number)
			if [ $(isANumber "$2") -eq 0 ]; then
				echo "0"
				return
			fi
			if [ ! -z "$RANGE" ]; then
				local MIN=$(cut -d- -f1 <<< "$RANGE")
				local MAX=$(cut -d- -f2 <<< "$RANGE")
				if [ $2 -lt $MIN -o $2 -gt $MAX ]; then
					echo "0"
					return
				fi
			fi
			;;
		boolean)
			if [ $(isABool "$2") -eq 0 ]; then
				echo "0"
				return
			fi
			;;
		string)
			;;
	esac
	

	if [ "$(type -t serverconfig_$1_Validate)" = "function" ]; then
		if [ $(serverconfig_$1_Validate "$2") -eq 0 ]; then
			echo "0"
			return
		fi
	fi
	
	echo "1"
}

# Query for the value of a single config option
# Will be stored in $configCurrent_$1
# Params:
#   1: Option name
configQueryValue() {
	local TYPE=$(serverconfig_$1_Type)
	local NAME=""
	local RANGE=""
	local DEFAULT=""
	local currentValName=configCurrent_$1

	if [ "$(type -t serverconfig_$1_Values)" = "function" ]; then
		echo "$(serverconfig_$1_QueryName), options:"
		serverconfig_$1_Values
		NAME="Select option"
		if [ "$TYPE" = "enum" ]; then
			local OPTOFFSET=1
		else
			local OPTOFFSET=0
		fi
		for (( i=$OPTOFFSET; i < ${#config_allowed_values[@]}+$OPTOFFSET; i++ )); do
			printf "  %2d: %s\n" $i "${config_allowed_values[$i-$OPTOFFSET]}"
		done
	else
		NAME=$(serverconfig_$1_QueryName)
	fi

	if [ "$TYPE" = "enum" ]; then
		RANGE=1-${#config_allowed_values[@]}
		if [ ! -z "${!currentValName}" ]; then
			for (( i=1; i < ${#config_allowed_values[@]}+1; i++ )); do
				if [ "${!currentValName}" = "${config_allowed_values[$i-1]}" ]; then
					DEFAULT=$i
				fi
			done
			export $currentValName=
		fi
	else
		if [ "$(type -t serverconfig_$1_Range)" = "function" ]; then
			RANGE=$(serverconfig_$1_Range)
		fi
	fi

	if [ -z "$DEFAULT" ]; then
		if [ ! -z "${!currentValName}" ]; then
			DEFAULT=${!currentValName}
		else
			if [ "$(type -t serverconfig_$1_Default)" = "function" ]; then
				DEFAULT=$(serverconfig_$1_Default)
			fi
		fi
	fi

	local prompt=$(printf "%s" "$NAME")
	if [ ! -z "$RANGE" ]; then
		prompt=$(printf "%s (%s)" "$prompt" "$RANGE")
	fi
	if [ ! -z "$DEFAULT" ]; then
		prompt=$(printf "%s [%s]" "$prompt" "$DEFAULT")
	fi
	prompt=$(printf "%s:" "$prompt")
	prompt=$(printf "%-*s " 40 "$prompt")

	while : ; do
		read -p "$prompt" $currentValName
		export $currentValName="${!currentValName:-$DEFAULT}"
		if [ $(isValidOptionValue "$1" "${!currentValName}") -eq 0 ]; then
			if [ "$(type -t serverconfig_$1_ErrorMessage)" = "function" ]; then
				serverconfig_$1_ErrorMessage "${!currentValName}"
			fi
		fi
		[ $(isValidOptionValue "$1" "${!currentValName}") -eq 1 ] && break
	done
	
	if [ "$TYPE" = "boolean" ]; then
		if [ $(getBool ${!currentValName}) -eq 1 ]; then
			export $currentValName="true"
		else
			export $currentValName="false"
		fi
	fi
	if [ "$TYPE" = "enum" ]; then
		export $currentValName="${config_allowed_values[$currentValName-1]}"
	fi
	echo
}

# Set parameters for current instance that have forced values:
#  - TelnetEnabled must be set so that management scripts can work
#  - AdminFileName is made to point to the local instance admins.xml
#  - SaveGameFolder is made to point to the instance folder
# Params:
#   1: Instance name
configSetAutoParameters() {
	configCurrent_TelnetEnabled=true
	configCurrent_AdminFileName=admins.xml
	configCurrent_SaveGameFolder="$(getInstancePath "$1")"
}


# Print defined config value
# Params:
#   1: Config option
printConfigValue() {
	local currentValName=configCurrent_$1
	printf "%-25s = %s\n" "$(serverconfig_$1_QueryName)" "${!currentValName}"
}

# Query for an instance name (will be saved in $INSTANCE)
readInstanceName() {
	until [ $(isValidInstanceName "$INSTANCE") -eq 1 ]; do
		read -p "Instance name: " INSTANCE
		if [ $(isValidInstanceName "$INSTANCE") -eq 0 ]; then
			echo "Invalid instance name, may only contain:"
			echo " - letters (A-Z / a-z)"
			echo " - digits (0-9)"
			echo " - underscores (_)"
			echo " - hyphens (-)"
		fi
	done
}

# Undefine the current config values
unsetAllConfigValues() {
	local CV
	for CV in $(listConfigValues); do
		local currentValName=configCurrent_$CV
		export $currentValName=
	done
}

# Load all config values from the config.xml of the given instance
# Params:
#   1: Instance name
loadCurrentConfigValues() {
	local CV
	for CV in $(listConfigValues); do
		local currentValName=configCurrent_$CV
		local cfile=$(getInstancePath "$1")/config.xml
		local XPATH="/ServerSettings/property[@name='$CV']/@value"
		local VAL=$($XMLSTARLET sel -t -v "$XPATH" $cfile)
		if [ ! -z "$VAL" ]; then
			export $currentValName="$VAL"
		fi
	done
}

# Save all config values to the config.xml of the given instance
# Params:
#   1: Instance name
saveCurrentConfigValues() {
	local CV
	for CV in $(listConfigValues) TelnetEnabled AdminFileName SaveGameFolder; do
		local currentValName=configCurrent_$CV
		local val="${!currentValName}"
		local cfile=$(getInstancePath "$1")/config.xml

		XPATHBASE="/ServerSettings/property[@name='$CV']"

		if [ -z $($XMLSTARLET sel -t -v "$XPATHBASE/@name" $cfile) ]; then
			$XMLSTARLET ed -L \
				-s "/ServerSettings" -t elem -n "property" -v "" \
				-i "/ServerSettings/property[not(@name)]" -t attr -n "name" -v "$CV" \
				-i "$XPATHBASE" -t attr -n "value" -v "$val" \
				$cfile
		else
			$XMLSTARLET ed -L \
				-u "$XPATHBASE/@value" -v "$val" \
				$cfile
		fi
	done
}

# Check if the config template exists
# Returns:
#   0/1: no/yes
configTemplateExists() {
	if [ -f $SDTD_BASE/templates/config.xml ]; then
		echo 1
	else
		echo 0
	fi
}

# Get a single value from a serverconfig
# Params:
#   1: Instance name
#   2: Property name
# Returns:
#   Property value
getConfigValue() {
	local CONF=$(getInstancePath $1)/config.xml
	$XMLSTARLET sel -t -v "/ServerSettings/property[@name='$2']/@value" $CONF
}

# Update a single value in a serverconfig
# Params:
#   1: Instance name
#   2: Property name
#   3: New value
setConfigValue() {
	local CONF=$(getInstancePath $1)/config.xml
	$XMLSTARLET ed -L -u "/ServerSettings/property[@name='$2']/@value" -v "$3" $CONF
}

