# Fetch icon from the archive contents,
# convert it to PNG if it is not already in a supported format,
# include it in the current package.
#
# This function is the one that should be called from game scripts,
# it can take several applications as its arguments,
# and default to handle all applications if none are explicitely given.
#
# USAGE: icons_inclusion $application[…]
icons_inclusion() {
	# Do nothing if icons inclusion has been disabled
	local option_icons
	option_icons=$(option_value 'icons')
	if [ "$option_icons" -eq 0 ]; then
		return 0
	fi

	# A late requirements check is run here,
	# in case it was skipped earlier because of an empty icons list.
	# This can happen if both the application type and icon are implicit,
	# like with WINE games where the icons source is the game binary.
	# Failing here is not ideal because the archive contents extraction already happened,
	# but at least the failure is explicit instead of silent.
	requirements_check_icons

	# If no applications are explicitely listed,
	# try to fetch the icons for all applications.
	if [ "$#" -eq 0 ]; then
		applications_list=$(applications_list)
		# If icons_inclusion has been called with no argument,
		# the applications list should not be empty.
		if [ -z "$applications_list" ]; then
			error_applications_list_empty
			return 1
		fi
		icons_inclusion $applications_list
		return 0
	fi

	local application
	for application in "$@"; do
		assert_not_empty 'application' 'icons_inclusion'
		icons_inclusion_single_application "$application"
	done
}

# Fetch icon from the archive contents,
# convert it to PNG if it is not already in a supported format,
# include it in the current package.
#
# This function handles all icons for a given application.
#
# USAGE: icons_inclusion_single_application $application
icons_inclusion_single_application() {
	local application
	application="$1"
	assert_not_empty 'application' 'icons_inclusion_single_application'

	local application_icons_list
	application_icons_list=$(application_icons_list "$application")
	# Return early if the current application has no associated icon
	if [ -z "$application_icons_list" ]; then
		return 0
	fi

	local icon
	for icon in $application_icons_list; do
		icons_inclusion_single_icon "$application" "$icon"
	done
}

# Compute the full path to the icon source file
# USAGE: icon_full_path $icon
# RETURN: the full path to the file that provides icons,
#         as an absolute path
icon_full_path() {
	local icon
	icon="$1"

	local content_path icon_path
	content_path=$(content_path_default)
	icon_path=$(icon_path "$icon")

	printf '%s/gamedata/%s/%s' "$PLAYIT_WORKDIR" "$content_path" "$icon_path"
}

# Fetch icon from the archive contents,
# convert it to PNG if it is not already in a supported format,
# include it in the current package.
#
# This function handles a single icon.
#
# USAGE: icons_inclusion_single_icon $application $icon
icons_inclusion_single_icon() {
	local application icon
	application="$1"
	icon="$2"

	# Check for the existence of the icons source file
	local icon_path
	icon_path=$(icon_full_path "$icon")
	if [ ! -f "$icon_path" ]; then
		error_icon_file_not_found "$icon_path"
		return 1
	fi

	icons_temporary_directory="${PLAYIT_WORKDIR}/icons"
	mkdir --parents "$icons_temporary_directory"
	icon_extract_png_from_file "$icon" "$icons_temporary_directory"
	icons_include_from_directory "$application" "$icons_temporary_directory"
	rmdir "$icons_temporary_directory"
}

# Convert the given file into .png icons
# USAGE: icon_extract_png_from_file $icon $destination
icon_extract_png_from_file() {
	local icon destination
	icon="$1"
	destination="$2"

	local icon_file icon_type
	icon_file=$(icon_full_path "$icon")
	icon_type=$(file_type "$icon_file")
	case "$icon_type" in
		( \
			'application/vnd.microsoft.portable-executable' | \
			'application/x-dosexec' \
		)
			icon_extract_png_from_exe "$icon" "$destination"
		;;
		('image/png')
			icon_copy_png "$icon" "$destination"
		;;
		('image/vnd.microsoft.icon')
			icon_extract_png_from_ico "$icon" "$destination"
		;;
		( \
			'image/bmp' | \
			'image/x-ms-bmp' \
		)
			icon_convert_bmp_to_png "$icon" "$destination"
		;;
		( \
			'image/x-xpixmap' | \
			'image/x-xpmi' \
		)
			icon_copy_xpm "$icon" "$destination"
		;;
		(*)
			error_icon_unsupported_type "$icon_file" "$icon_type"
			return 1
		;;
	esac
}

# Extract .png file(s) from the given .exe file
# USAGE: icon_extract_png_from_exe $icon $destination
icon_extract_png_from_exe() {
	local icon destination
	icon="$1"
	destination="$2"

	# Extract the .ico file(s) for the given .exe file
	icon_extract_ico_from_exe "$icon" "$destination"

	# Extract the .png file(s) from each previously extracted .ico file
	local inner_icon_file content_path
	content_path=$(content_path_default)
	for inner_icon_file in "$destination"/*.ico; do
		(
			inner_icon_file_name=$(basename "$inner_icon_file")
			inner_icon_file_temporary_path="${PLAYIT_WORKDIR}/gamedata/${content_path}/${inner_icon_file_name}"
			mv "$inner_icon_file" "$inner_icon_file_temporary_path"
			export TMP_INNER_ICON="$inner_icon_file_name"
			icon_extract_png_from_ico 'TMP_INNER_ICON' "$destination"
			rm "$inner_icon_file_temporary_path"
		)
	done
}

# Extract .ico file(s) from the given .exe file
# USAGE: icon_extract_ico_from_exe $icon $destination
icon_extract_ico_from_exe() {
	local icon destination
	icon="$1"
	destination="$2"

	local icon_file wrestool_options
	icon_file=$(icon_full_path "$icon")
	wrestool_options=$(icon_wrestool_options "$icon")
	## Silence ShellCheck false-positive
	## Double quote to prevent globbing and word splitting.
	# shellcheck disable=SC2086
	wrestool $wrestool_options --extract --output="$destination" "$icon_file" 2>/dev/null
}

# Convert the given .bmp file to .png
# USAGE: icon_convert_bmp_to_png $icon $destination
icon_convert_bmp_to_png() {
	local icon destination
	icon="$1"
	destination="$2"

	icon_convert_to_png "$icon" "$destination"
}

# Extract .png file(s) from the given .ico file
# USAGE: icon_extract_png_from_ico $icon $destination
icon_extract_png_from_ico() {
	local icon destination
	icon="$1"
	destination="$2"

	icon_convert_to_png "$icon" "$destination"
}

# Convert multiple icon formats supported by ImageMagick to .png
# USAGE: icon_convert_to_png $icon $destination
icon_convert_to_png() {
	local icon destination
	icon="$1"
	destination="$2"

	local icon_file file_name
	icon_file=$(icon_full_path "$icon")
	file_name=$(basename "$icon_file")
	convert "$icon_file" "${destination}/${file_name%.*}.png"
}

# Copy the given .png file to the given directory
# USAGE: icon_copy_png $icon $destination
icon_copy_png() {
	local icon destination
	icon="$1"
	destination="$2"

	local icon_file
	icon_file=$(icon_full_path "$icon")
	cp "$icon_file" "$destination"
}

# Copy the given .xpm file to the given directory
# USAGE: icon_copy_xpm $icon $destination
icon_copy_xpm() {
	local icon destination
	icon="$1"
	destination="$2"

	local icon_file
	icon_file=$(icon_full_path "$icon")
	cp "$icon_file" "$destination"
}

# Get icon files from the given directory and put them in the current package
# USAGE: icons_include_from_directory $app $directory
# RETURNS: nothing
# SIDE EFFECT: take the icons from the given directory, move them to standard paths into the current package
icons_include_from_directory() {
	# Get the application id
	local application application_id
	application="$1"
	application_id=$(application_id "$application")

	# Get the icons from the given source directory,
	# then move them to the current package
	local source_directory source_file destination_name destination_directory destination_file path_icons
	source_directory="$2"
	path_icons=$(path_icons)
	for source_file in \
		"$source_directory"/*.png \
		"$source_directory"/*.xpm
	do
		# Skip the current pattern if it matched no file
		if [ ! -e "$source_file" ]; then
			continue
		fi

		# Compute icon file name
		destination_name="${application_id}.${source_file##*.}"

		# Compute icon path
		local package package_path icon_resolution
		package=$(current_package)
		package_path=$(package_path "$package")
		icon_resolution=$(icon_get_resolution "$source_file")
		destination_directory="${package_path}${path_icons}/${icon_resolution}/apps"

		# Move current icon file to its destination
		destination_file="${destination_directory}/${destination_name}"
		mkdir --parents "$destination_directory"
		mv "$source_file" "$destination_file"
	done
}

# Return the resolution of the given image file
# USAGE: icon_get_resolution $file
# RETURNS: image resolution, using the format ${width}x${height}
icon_get_resolution() {
	local image_file
	image_file="$1"

	# `identify` should be available when this function is called.
	# Exits with an explicit error if it is missing
	if ! command -v 'identify' >/dev/null 2>&1; then
		error_unavailable_command 'icon_get_resolution' 'identify'
		return 1
	fi

	local image_resolution_string image_resolution
	image_resolution_string=$(identify "$image_file" | sed "s;^${image_file} ;;" | cut --delimiter=' ' --fields=2)
	image_resolution="${image_resolution_string%+0+0}"

	printf '%s' "$image_resolution"
	return 0
}

