# 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.
# Warning: The context package must be set when calling this function, so it is passed to the content_path_default call.
#          Package-specific CONTENT_PATH_DEFAULT is uncommon, but is used at least for Divinity: Original Sin 2.
# USAGE: icon_full_path $icon
icon_full_path() {
	local icon=$1

	local path_archive_contents icon_path
	path_archive_contents=$(path_archive_contents)
	icon_path=$(icon_path "$icon")
	printf '%s/%s' "$path_archive_contents" "$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=$1 \
		application=$2 \
		icon=$3

	# Check for the existence of the icon source file.
	local icon_path
	icon_path=$(
		set_current_package "$package"
		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=$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 path_archive_contents inner_icon_file TMP_INNER_ICON
	path_archive_contents=$(path_archive_contents)
	for inner_icon_file in "$destination"/*.ico; do
		inner_icon_file_name=$(basename "$inner_icon_file")
		inner_icon_file_temporary_path="${path_archive_contents}/${inner_icon_file_name}"
		mv "$inner_icon_file" "$inner_icon_file_temporary_path"
		# shellcheck disable=SC2034
		TMP_INNER_ICON="$inner_icon_file_name"
		icon_extract_png_from_ico 'TMP_INNER_ICON' "$destination"
		rm "$inner_icon_file_temporary_path"
	done
}

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

