# List the application identifiers for the current game or expansion
# USAGE: applications_list
# RETURN: a list of application identifiers, one per line,
#         or an empty string if there is no application (common case for expansions)
applications_list() {
	# Fetch the explicit list if it is set
	local applications_list
	applications_list=$(context_value 'APPLICATIONS_LIST')

	# Parse the environment to compute an applications list from it
	if [ -z "$applications_list" ]; then
		local sed_expression
		# The following expression matches:
		# - APP_xxx_EXE
		# - APP_xxx_SCUMMID
		# - APP_xxx_TYPE
		# and the suffixed variants of these variables.
		sed_expression='s/^\(APP_[0-9A-Z]\+\)_\(EXE\|SCUMMID\|TYPE\)\(_[0-9A-Z]\+\)*=.*/\1/p'
		applications_list=$(set | sed --silent --expression="$sed_expression")
	fi

	# Fall back on the default applications list for the current game engine
	if [ -z "$applications_list" ]; then
		local game_engine
		game_engine=$(game_engine)
		case "$game_engine" in
			('unity3d')
				# Unity3D games are expected to provide a single application
				applications_list='APP_MAIN'
			;;
			('visionaire')
				applications_list=$(visionaire_applications_list)
			;;
		esac
	fi

	printf '%s\n' $applications_list | list_clean
}

# Print the type of prefix to use for the given application.
# If no type is explicitely set from the game script, it defaults to "symlinks".
# The supported prefix types are:
# - "symlinks", the default, generate our usual symbolic links farm
# - "none", no prefix is generated, the game is run from the read-only system directory
# USAGE: application_prefix_type $application
# RETURN: the prefix type keyword, from the supported values
application_prefix_type() {
	# Prefix types:
	# - "symlinks", the default, generate our usual symbolic links farm
	# - "none", no prefix is generated, the game is run from the read-only system directory

	local application
	application="$1"

	# Set the prefix type for the current application.
	local prefix_type
	prefix_type=$(context_value "${application}_PREFIX_TYPE")

	# Fall back on the default prefix type for the current game.
	if [ -z "$prefix_type" ]; then
		prefix_type=$(context_value 'APPLICATIONS_PREFIX_TYPE')
	fi

	# Fall back on the default prefix type for the current application type.
	if [ -z "$prefix_type" ]; then
		local application_type
		application_type=$(application_type "$application")
		case "$application_type" in
			('renpy')
				prefix_type='none'
			;;
			('scummvm')
				prefix_type='none'
			;;
			(*)
				prefix_type='symlinks'
			;;
		esac
	fi

	# Check that a supported prefix type has been set.
	case "$prefix_type" in
		('symlinks'|'none')
			## This is a supported type, no error to throw.
		;;
		(*)
			error_unknown_prefix_type "$prefix_type"
			return 1
		;;
	esac

	printf '%s' "$prefix_type"
}

# print the id of the given application
# USAGE: application_id $application
# RETURN: the application id, limited to the characters set [-_0-9a-z]
#         the id can not start nor end with a character from the set [-_]
application_id() {
	local application
	application="$1"

	# Get the application type from its identifier
	# Fall back on the game id if no value is set
	local application_id
	application_id=$(context_value "${application}_ID")
	if [ -z "$application_id" ]; then
		application_id=$(game_id)
	fi

	# Check that the id fits the format restrictions
	if ! printf '%s' "$application_id" |
		grep --quiet --regexp='^[0-9a-z][-_0-9a-z]\+[0-9a-z]$'
	then
		error_application_id_invalid "$application" "$application_id"
		return 1
	fi

	printf '%s' "$application_id"
}

# Print the name of the binary targeted by the given application
# USAGE: application_exe $application
# RETURN: the binary file name,
#         or an empty string is none is set
application_exe() {
	local application
	application="$1"

	local application_exe
	application_exe=$(context_value "${application}_EXE")

	# If no binary is explicitly set, fall back on the default value for the current game engine.
	if [ -z "$application_exe" ]; then
		local game_engine
		game_engine=$(game_engine)
		case "$game_engine" in
			('unity3d')
				application_exe=$(unity3d_application_exe_default "$application")
			;;
			('visionaire')
				application_exe=$(visionaire_application_exe)
			;;
		esac
	fi

	printf '%s' "$application_exe"
}

# Print the path to the application binary, with single quotes escaped,
# for inclusion in a single quote delimited variable declaration.
# USAGE: application_exe_escaped $application
application_exe_escaped() {
	local application
	application="$1"

	local application_exe
	application_exe=$(application_exe "$application")

	# If the file name includes single quotes, replace each one with: '\''
	printf '%s' "$application_exe" | sed "s/'/'\\\''/g"
}

# Print the full path to the application binary
# An error is thrown if the binary file could not be found anywhere
# USAGE: application_exe_path $application_exe
application_exe_path() {
	local application_exe
	application_exe="$1"

	# Look for the application binary in the current package.
	local package package_path path_game_data application_exe_path
	package=$(current_package)
	package_path=$(package_path "$package")
	path_game_data=$(path_game_data)
	application_exe_path="${package_path}${path_game_data}/${application_exe}"
	if [ -f "$application_exe_path" ]; then
		printf '%s' "$application_exe_path"
		return 0
	fi

	# Look for the application binary in all packages.
	local packages_list
	packages_list=$(packages_list)
	for package in $packages_list; do
		package_path=$(package_path "$package")
		path_game_data=$(
			set_current_package "$package"
			path_game_data
		)
		application_exe_path="${package_path}${path_game_data}/${application_exe}"
		if [ -f "$application_exe_path" ]; then
			printf '%s' "$application_exe_path"
			return 0
		fi
	done

	# Look for the application binary in the temporary path for archive content.
	## Reaching this step with CONTENT_PATH_DEFAULT unset triggers an error.
	local content_path_default
	content_path_default=$(content_path_default)
	if [ -n "$content_path_default" ]; then
		local application_exe_path
		application_exe_path="${PLAYIT_WORKDIR}/gamedata/${content_path_default}/${application_exe}"
		if [ -f "$application_exe_path" ]; then
			printf '%s' "$application_exe_path"
			return 0
		fi
	fi

	# Throw an error if the binary file could not be found anywhere
	error_application_exe_path_not_found "$application_exe"
	return 1
}

# print the name of the given application, for display in menus
# USAGE: application_name $application
# RETURN: the pretty version of the application name
application_name() {
	local application
	application="$1"

	# Get the application name from its identifier
	# Fall back on the game name if no value is set
	local application_name
	application_name=$(context_value "${application}_NAME")
	if [ -z "$application_name" ]; then
		application_name=$(game_name)
	fi

	printf '%s' "$application_name"
}

# print the category of the given application, for sorting in menus with categories support
# USAGE: application_category $application
# RETURN: the application XDG menu category
application_category() {
	local application
	application="$1"

	# Get the application category from its identifier
	local application_category
	application_category=$(get_value "${application}_CAT")
	## If no category is explicitely set, fall back on "Game"
	if [ -z "$application_category" ]; then
		application_category='Game'
	fi

	# TODO - We could check that the category is part of the 1.0 XDG spec:
	# https://specifications.freedesktop.org/menu-spec/menu-spec-1.0.html#category-registry

	printf '%s' "$application_category"
}

# Print the pre-run actions for the given application.
# USAGE: application_prerun $application
# RETURN: the pre-run actions, can span over multiple lines,
#         or an empty string if there are none
application_prerun() {
	local application
	application="$1"

	local application_prerun
	application_prerun=$(context_value "${application}_PRERUN")

	# Run engine specific actions
	local game_engine
	game_engine=$(game_engine)
	case "$game_engine" in
		('unity3d')
			## Use a dedicated log file for the current game session.
			application_prerun="$application_prerun
			mkdir --parents logs"
		;;
	esac

	# If LD_PRELOAD hacks are provided in the current package, include them in the pre-run actions.
	local package hacks_list
	package=$(current_package)
	hacks_list=$(hacks_included_in_package "$package")
	if [ -n "$hacks_list" ]; then
		local hack hack_prerun
		for hack in $hacks_list; do
			hack_prerun=$(hack_application_prerun "$hack")
			application_prerun="$application_prerun
$hack_prerun"
		done
	fi

	# Ensure the pre-run actions string always end with a line break.
	printf '%s\n' "$application_prerun"
}

# Print the post-run actions for the given application.
# USAGE: application_postrun $application
# RETURN: the post-run actions, can span over multiple lines,
#         or an empty string if there are none
application_postrun() {
	local application
	application="$1"

	local application_postrun
	application_postrun=$(context_value "${application}_POSTRUN")

	# Ensure the post-run actions string always end with a line break.
	printf '%s\n' "$application_postrun"
}

# print the options string for the given application
# USAGE: application_options $application
# RETURN: the options string on a single line,
#         or an empty string if no options are set
application_options() {
	# Get the application options string from its identifier
	local application application_options
	application="$1"
	application_options=$(context_value "${application}_OPTIONS")

	# Add engine specific options
	local game_engine
	game_engine=$(game_engine)
	case "$game_engine" in
		('unity3d')
			## Use a dedicated log file for the current game session.
			## The quotes are not truly required, but they make ShellCheck happy.
			application_options="$application_options -logFile \"./logs/\$(date +%F-%R).log\""
		;;
	esac

	# Check that the options string does not span multiple lines
	local line_breaks_number
	line_breaks_number=$(printf '%s' "$application_options" | wc --lines)
	if [ "$line_breaks_number" -gt 0 ]; then
		error_variable_multiline "${application}_OPTIONS"
		return 1
	fi

	printf '%s' "$application_options"
}

