# 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=$1

	# Set the prefix type for the current application (deprecated).
	local prefix_type
	prefix_type=$(context_value "${application}_PREFIX_TYPE")
	# Application-prefix type is deprecated, because it conflicts with implicit application list.
	# APP_MAIN_PREFIX_TYPE would be matched as the type of an "APP_MAIN_PREFIX" application,
	# including it in the default list of applications.
	if \
		compatibility_level_is_at_least '2.35' &&
		[ -n "$prefix_type" ]
	then
		warning_deprecated_variable "${application}_PREFIX_TYPE" 'APPLICATIONS_PREFIX_TYPE'
	fi

	# Set the 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)
		## TODO: A default value could be set for Unreal Engine 4 games.
		##       Based on that default value, the fallback wrestool options for these games might need updating.
		case "$game_engine" in
			('gamemaker')
				application_exe=$(application_exe_gamemaker)
			;;
			('unity3d')
				application_exe=$(unity3d_application_exe_default "$application")
			;;
			('visionaire')
				application_exe=$(visionaire_application_exe)
			;;
		esac
	fi

	printf '%s' "$application_exe"
}

# Print the full path to the application binary.
# An empty string is printed if the binary could not be found, without throwing an error.
# USAGE: application_exe_path $application_exe
application_exe_path() {
	local 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.
	local path_archive_contents application_exe_path
	path_archive_contents=$(path_archive_contents)
	application_exe_path="${path_archive_contents}/${application_exe}"
	if [ -f "$application_exe_path" ]; then
		printf '%s' "$application_exe_path"
		return 0
	fi
}

# 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"
}

# Check if the given category is valid according to
# https://specifications.freedesktop.org/menu-spec/1.0/category-registry.html
# USAGE: is_valid_category $category
## TODO: This should be handled in src/30_lauchers/10_desktop.sh
## TODO: Only the main category should be checked, additional categories should be allowed.
is_valid_category() {
	local category
	category="$1"

	case "$category" in
		'AudioVideo') ;;
		'Audio') ;;
		'Video') ;;
		'Development') ;;
		'Education') ;;
		'Game') ;;
		'Graphics') ;;
		'Network') ;;
		'Office') ;;
		'Settings') ;;
		'System') ;;
		'Utility') ;;
		*) return 1 ;;
	esac
	return 0
}

# Print the menu category that should be used for the given application.
# USAGE: application_category $application
## TODO: This should be reduced to only print a category (with a fallback),
##       checking its validity should be done in src/30_lauchers/10_desktop.sh
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

	# Check the category against XDG specification.
	if ! is_valid_category "$application_category"; then
		warning_application_category_unspecified "$application" "$application_category"
	fi

	printf '%s' "$application_category"
}

# Print the pre-run actions for the given application.
# USAGE: application_prerun $application
application_prerun() {
	local application
	application="$1"

	# Print explicit pre-run actions.
	context_value "${application}_PRERUN"

	# Print engine-specific common actions.
	local game_engine
	game_engine=$(game_engine)
	case "$game_engine" in
		('gamemaker')
			application_prerun_gamemaker
		;;
		('unity3d')
			## TODO: This should be moved to a dedicated function.
			## Use a dedicated log file for the current game session.
			cat <<- EOF
			mkdir --parents logs
			EOF
		;;
	esac

	# Include LD_PRELOAD hack in pre-run actions.
	local ld_preload_source
	ld_preload_source=$(ld_preload_source)
	if [ -n "$ld_preload_source" ]; then
		# Set the path to the packaged .so library
		## TODO: This is used in several places, and should probably by handled by a dedicated function.
		local path_libraries path_binary
		path_libraries=$(path_libraries)
		path_binary="${path_libraries}/preload-hack.so"
		cat <<- EOF
		export LD_PRELOAD="\${LD_PRELOAD}:${path_binary}"
		EOF
	fi

	# Ensure the pre-run actions always end with a line break.
	printf '\n'
}

# Print the post-run actions for the given application.
# USAGE: application_postrun $application
application_postrun() {
	local application
	application="$1"

	context_value "${application}_POSTRUN"

	# Ensure the post-run actions always end with a line break.
	printf '\n'
}

# 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"
}

