# Fetch icons from the archive contents,
# convert them to PNG if they are not already in a supported format,
# include them in the given package.
#
# This function handles all icons for a given application.
#
# USAGE: icons_inclusion_single_application $package $application
icons_inclusion_single_application() {
	local package application
	package="$1"
	application="$2"

	local application_icons_list
	## application_icons_list relies on the context package being set, through a late call to application_exe.
	application_icons_list=$(
		set_current_package "$package"
		application_icons_list "$application"
	)
	# Throw an error if no icon was found for the given application.
	if [ -z "$application_icons_list" ]; then
		## Skip the error if an icons archives is supported, as a non-blocking warning has already been shown.
		if [ -n "${ARCHIVE_OPTIONAL_ICONS_NAME:-}" ]; then
			return 0
		fi
		error_no_icon_found "$application"
		return 1
	fi

	local icon
	for icon in $application_icons_list; do
		icons_inclusion_single_icon "$package" "$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_default icon_path
	content_path_default=$(content_path_default)
	icon_path=$(icon_path "$icon")

	printf '%s/gamedata/%s/%s' "$PLAYIT_WORKDIR" "$content_path_default" "$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 given package.
#
# This function handles a single icon.
#
# USAGE: icons_inclusion_single_icon $package $application $icon
icons_inclusion_single_icon() {
	local package application icon
	package="$1"
	application="$2"
	icon="$3"

	# Check for the existence of the icons source file
	local icon_path
	## TODO: icon_full_path relies on the context package being set,
	##       through a call to content_path_default.
	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"

	# Check if the icon is already in a supported format.
	# Directly include icons in a supported format,
	# otherwise convert them to PNG before inclusion.
	local icon_type
	icon_type=$(file_type "$icon_path")
	case "$icon_type" in
		( \
			'image/png' | \
			'image/svg+xml' | \
			'image/x-xpixmap' | \
			'image/x-xpmi' \
		)
			cp "$icon_path" "$icons_temporary_directory"
		;;
		( \
			'application/vnd.microsoft.portable-executable' | \
			'application/x-dosexec' | \
			'image/bmp' | \
			'image/vnd.microsoft.icon' | \
			'image/x-ms-bmp' \
		)
			icon_extract_png_from_file "$icon" "$icons_temporary_directory"
		;;
		(*)
			error_icon_unsupported_type "$icon_path" "$icon_type"
			return 1
		;;
	esac

	icons_include_from_directory "$package" "$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/vnd.microsoft.icon')
			icon_extract_png_from_ico "$icon" "$destination"
		;;
		( \
			'image/bmp' | \
			'image/x-ms-bmp' \
		)
			icon_convert_bmp_to_png "$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_default
	content_path_default=$(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_default}/${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

	# Check that at least one .ico file has been extracted, throw an error otherwise
	local ico_files_number
	ico_files_number=$(find "$destination" -name '*.ico' | wc --lines)
	if [ "$ico_files_number" -lt 1 ]; then
		error_no_ico_file_extracted "$icon"
		return 1
	fi
}

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

# Get icon files from the given directory and put them in the given package
# USAGE: icons_include_from_directory $package $application $directory
icons_include_from_directory() {
	local package application source_directory
	package="$1"
	application="$2"
	source_directory="$3"

	local package_path path_icons
	package_path=$(package_path "$package")
	path_icons=$(path_icons)

	local application_id
	application_id=$(
		set_current_package "$package"
		application_id "$application"
	)

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

		icon_resolution=$(icon_get_resolution "$source_file")
		destination_directory="${package_path}${path_icons}/${icon_resolution}/apps"
		destination_path="${destination_directory}/${application_id}.${source_file##*.}"
		mkdir --parents "$destination_directory"
		mv "$source_file" "$destination_path"
	done
}

# Return the resolution of the given image file.
# For bitmap images it returns its dimensions as "${width}x${height}",
# for vector images it returns "scalable".
# USAGE: icon_get_resolution $file
icon_get_resolution() {
	local image_file
	image_file="$1"

	local image_type image_resolution
	image_type=$(file_type "$image_file")
	case "$image_type" in
		( \
			'image/svg+xml' \
		)
			image_resolution='scalable'
		;;
		( \
			'image/png' | \
			'image/x-xpixmap' | \
			'image/x-xpmi' \
		)
			# `identify` should be available when handling bitmap images.
			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_string=$(identify "$image_file" | sed "s;^${image_file} ;;" | cut --delimiter=' ' --fields=2)
			image_resolution="${image_resolution_string%+0+0}"
		;;
		(*)
			error_icon_unsupported_type "$image_file" "$image_type"
			return 1
		;;
	esac

	printf '%s' "$image_resolution"
}

