# Debian - Write the metadata for the listed packages
# USAGE: debian_packages_metadata $package[…]
debian_packages_metadata() {
	local package
	for package in "$@"; do
		debian_package_metadata_single "$package"
	done
}

# Debian - Write the metadata for the given package
# USAGE: debian_package_metadata_single $package
debian_package_metadata_single() {
	local package
	package="$1"

	# Create metadata directory, enforce correct permissions.
	local package_path control_directory
	package_path=$(package_path "$package")
	control_directory="${package_path}/DEBIAN"
	mkdir --parents "$control_directory"
	chmod 755 "$control_directory"

	# Write main metadata file (DEBIAN/control), enforce correct permissions.
	local control_file
	control_file="${control_directory}/control"
	debian_package_metadata_control "$package" > "$control_file"
	chmod 644 "$control_file"

	# Write postinst/prerm scripts, enforce correct permissions.
	local postinst_commands
	postinst_commands=$(debian_postinst_commands "$package")
	if [ -n "$postinst_commands" ]; then
		debian_script_postinst "$package" > "${control_directory}/postinst"
		chmod 755 "${control_directory}/postinst"
	fi
	local prerm_actions
	prerm_actions=$(package_prerm_actions "$package")
	if [ -n "$prerm_actions" ]; then
		debian_script_prerm "$package" > "${control_directory}/prerm"
		chmod 755 "${control_directory}/prerm"
	fi
}

# Print the content of the DEBIAN/control metadata file for the given package
# USAGE: debian_package_metadata_control $package
# RETURN: the contents of the DEBIAN/control file,
#         spanning over multiple lines
debian_package_metadata_control() {
	local package
	package="$1"

	local package_architecture package_depends package_description package_id package_maintainer package_provides package_size package_version
	package_architecture=$(package_architecture_string "$package")
	package_depends=$(package_debian_field_depends "$package")
	package_description=$(debian_field_description "$package")
	package_id=$(package_id "$package")
	package_maintainer=$(package_maintainer)
	package_provides=$(debian_field_provides "$package")
	package_size=$(debian_package_size "$package")
	package_version=$(package_version)

	cat <<- EOF
	Package: $package_id
	Version: $package_version
	Architecture: $package_architecture
	Multi-Arch: foreign
	Maintainer: $package_maintainer
	Installed-Size: $package_size
	Section: non-free/games
	EOF
	if [ -n "$package_provides" ]; then
		cat <<- EOF
		$package_provides
		EOF
	fi
	if [ -n "$package_depends" ]; then
		cat <<- EOF
		Depends: $package_depends
		EOF
	fi
	cat <<- EOF
	Description: $package_description
	EOF
}

# Debian - Print the necessary header for Debian control scripts
# USAGE: debian_script_header
# RETURN: the header for Debian control scripts,
#         spanning over multiple lines
debian_script_header() {
	cat <<- EOF
	#!/bin/sh
	set -o errexit

	EOF
}

# Debian - Print the necessary footer for Debian control scripts
# USAGE: debian_script_header
# RETURN: the footer for Debian control scripts,
#         spanning over multiple lines
debian_script_footer() {
	cat <<- EOF

	exit 0
	EOF
}

# Debian - Print the commands that should be run after the package installation
# USAGE: debian_postinst_commands $package
# RETURN: a list of commands that can span over several lines,
#         or an empty string if there is no command to run
debian_postinst_commands() {
	local package
	package="$1"

	# Include actions that should be run.
	package_postinst_actions "$package"

	# Include warnings that should be displayed.
	local warning_messages
	warning_messages=$(package_postinst_warnings "$package")
	if [ -n "$warning_messages" ]; then
		local warning_line
		while read -r warning_line; do
			printf 'printf "Warning: %%s\\n" "%s"\n' "$warning_line"
		done <<- EOL
		$(printf '%s' "$warning_messages")
		EOL
	fi
}

# Debian - Print the content of the DEBIAN/postinst script for the given package
# USAGE: debian_script_postinst $package
# RETURN: the contents of the DEBIAN/postinst file,
#         spanning over multiple lines
debian_script_postinst() {
	local package
	package="$1"

	debian_script_header
	debian_postinst_commands "$package"
	debian_script_footer
}

# Debian - Print the content of the DEBIAN/prerm script for the given package
# USAGE: debian_script_prerm $package
# RETURN: the contents of the DEBIAN/prerm file,
#         spanning over multiple lines
debian_script_prerm() {
	local package
	package="$1"

	debian_script_header
	package_prerm_actions "$package"
	debian_script_footer
}

# Debian - Build a list of packages
# USAGE: debian_packages_build $package[…]
debian_packages_build() {
	local package
	for package in "$@"; do
		debian_package_build_single "$package"
	done
}

# Debian - Build a single package
# USAGE: debian_package_build_single $package
debian_package_build_single() {
	local package
	package="$1"

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

	local option_output_dir package_name generated_package_path
	option_output_dir=$(option_value 'output-dir')
	package_name=$(package_name "$package")
	generated_package_path="${option_output_dir}/${package_name}"

	# Skip packages already existing,
	# unless called with --overwrite.
	local option_overwrite
	option_overwrite=$(option_value 'overwrite')
	if \
		[ "$option_overwrite" -eq 0 ] \
		&& [ -e "$generated_package_path" ]
	then
		information_package_already_exists "$package_name"
		return 0
	fi

	# Use old .deb format if the package is going over the size limit for the modern format
	local dpkg_options package_size
	package_size=$(debian_package_size "$package")
	if [ "$package_size" -gt 9700000 ]; then
		warning_debian_size_limit "$package"
		export PLAYIT_DEBIAN_OLD_DEB_FORMAT=1
		dpkg_options="${dpkg_options:-} --deb-format=0.939000"
	fi

	# Set compression setting
	local option_compression
	option_compression=$(option_value 'compression')
	case "$option_compression" in
		('none')
			dpkg_options="${dpkg_options:-} -Znone"
		;;
		('speed')
			dpkg_options="${dpkg_options:-} -Zgzip"
		;;
		('size')
			if [ "${PLAYIT_DEBIAN_OLD_DEB_FORMAT:-0}" -eq 1 ]; then
				## Old .deb format 0.939000 is not compatible with xz compression.
				dpkg_options="${dpkg_options:-} -Zgzip"
			else
				dpkg_options="${dpkg_options:-} -Zxz"
			fi
		;;
		('auto')
			if [ "${PLAYIT_DEBIAN_OLD_DEB_FORMAT:-0}" -eq 1 ]; then
				## Old .deb format 0.939000 is not compatible with xz compression.
				dpkg_options="${dpkg_options:-} -Zgzip"
			fi
		;;
	esac

	# Run the actual package generation, using dpkg-deb
	local TMPDIR package_generation_return_code
	information_package_building "$package_name"
	## We need to explicitly export TMPDIR, or dpkg-deb will not pick it up.
	export TMPDIR="$PLAYIT_WORKDIR"
	{
		debug_external_command "fakeroot -- dpkg-deb $dpkg_options --build \"$package_path\" \"$generated_package_path\" 1>/dev/null"
		fakeroot -- dpkg-deb ${dpkg_options:-} --build "$package_path" "$generated_package_path" 1>/dev/null
		package_generation_return_code=$?
	} || true
	if [ $package_generation_return_code -ne 0 ]; then
		error_package_generation_failed "$package_name"
		return 1
	fi
}

# Debian - Compute the package installed size
# USAGE: debian_package_size $package
# RETURN: the package contents size, in kilobytes
debian_package_size() {
	local package
	package="$1"

	# Compute the package size, in kilobytes.
	local package_path package_size
	package_path=$(package_path "$package")
	package_size=$(
		du --total --block-size=1K --summarize "$package_path" | \
			tail --lines=1 | \
			cut --fields=1
	)

	printf '%s' "$package_size"
}

# Debian - Print contents of "Depends" field
# USAGE: package_debian_field_depends $package
package_debian_field_depends() {
	local package
	package="$1"

	local dependencies_list first_item_displayed dependency_string
	dependencies_list=$(dependencies_debian_full_list "$package")
	first_item_displayed=0
	while read -r dependency_string; do
		if [ -z "$dependency_string" ]; then
			continue
		fi
		if [ "$first_item_displayed" -eq 0 ]; then
			printf '%s' "$dependency_string"
			first_item_displayed=1
		else
			printf ', %s' "$dependency_string"
		fi
	done <<- EOF
	$(printf '%s' "$dependencies_list")
	EOF
}

# Debian - Print contents of "Description" field
# USAGE: debian_field_description $package
debian_field_description() {
	local package
	package="$1"

	local game_name package_description script_version_string
	game_name=$(game_name)
	package_description=$(package_description "$package")
	script_version_string=$(script_version)

	printf '%s' "$game_name"
	if [ -n "$package_description" ]; then
		printf -- ' - %s' "$package_description"
	fi
	printf '\n ./play.it script version %s' "$script_version_string"
}

# Debian - Print the contents of the "Conflicts", "Provides" and "Replaces" fields
# USAGE: debian_field_provides $package
debian_field_provides() {
	local package
	package="$1"

	local package_provides
	package_provides=$(package_provides "$package")

	# Return early if there is no package name provided
	if [ -z "$package_provides" ]; then
		return 0
	fi

	local packages_list package_name
	packages_list=''
	while read -r package_name; do
		if [ -z "$packages_list" ]; then
			packages_list="$package_name"
		else
			packages_list="$packages_list, $package_name"
		fi
	done <<- EOL
	$(printf '%s' "$package_provides")
	EOL

	printf 'Conflicts: %s\n' "$packages_list"
	printf 'Provides: %s\n' "$packages_list"
	printf 'Replaces: %s\n' "$packages_list"
}

# Print the file name of the given package
# USAGE: package_name_debian $package
# RETURNS: the file name, as a string
package_name_debian() {
	local package
	package="$1"

	local package_id package_version package_architecture package_name
	package_id=$(package_id "$package")
	package_version=$(package_version)
	package_architecture=$(package_architecture_string "$package")
	package_name="${package_id}_${package_version}_${package_architecture}.deb"

	printf '%s' "$package_name"
}

# Get the path to the directory where the given package is prepared,
# relative to the directory where all packages are stored
# USAGE: package_path_debian $package
# RETURNS: relative path to a directory, as a string
package_path_debian() {
	local package
	package="$1"

	local package_name package_path
	package_name=$(package_name "$package")
	package_path="${package_name%.deb}"

	printf '%s' "$package_path"
}

# Print the architecture string of the given package, in the format expected by dpkg
# USAGE: debian_package_architecture_string $package
# RETURNS: the package architecture, as one of the following values:
#          - i386
#          - amd64
#          - all
debian_package_architecture_string() {
	local package
	package="$1"

	local package_architecture package_architecture_string
	package_architecture=$(package_architecture "$package")
	case "$package_architecture" in
		('32')
			package_architecture_string='i386'
		;;
		('64')
			package_architecture_string='amd64'
		;;
		('all')
			package_architecture_string='all'
		;;
	esac

	printf '%s' "$package_architecture_string"
}

