# Arch Linux - Write the metadata for the listed packages
# USAGE: archlinux_packages_metadata $package[…]
archlinux_packages_metadata() {
	local package
	for package in "$@"; do
		archlinux_package_metadata_single "$package"
	done
}

# Arch Linux - Write the metadata for the given package
# USAGE: archlinux_package_metadata_single $package
archlinux_package_metadata_single() {
	local package
	package="$1"

	local package_path target
	package_path=$(package_path "$package")
	target="${package_path}/.PKGINFO"
	mkdir --parents "$(dirname "$target")"

	local \
		archlinux_field_pkgname \
		archlinux_field_pkgver \
		archlinux_field_packager \
		archlinux_field_builddate \
		archlinux_field_size \
		archlinux_field_arch \
		archlinux_field_pkgdesc \
		archlinux_field_depend \
		archlinux_field_provides
	archlinux_field_pkgname=$(archlinux_field_pkgname "$package")
	archlinux_field_pkgver=$(archlinux_field_pkgver "$package")
	archlinux_field_packager=$(archlinux_field_packager "$package")
	archlinux_field_builddate=$(archlinux_field_builddate "$package")
	archlinux_field_size=$(archlinux_field_size "$package")
	archlinux_field_arch=$(archlinux_field_arch "$package")
	archlinux_field_pkgdesc=$(archlinux_field_pkgdesc "$package")
	archlinux_field_depend=$(archlinux_field_depend "$package")
	archlinux_field_provides=$(archlinux_field_provides "$package")

	cat > "$target" <<- EOF
	# Generated by ./play.it $PLAYIT_LIBRARY_VERSION
	pkgname = $archlinux_field_pkgname
	pkgver = $archlinux_field_pkgver
	packager = $archlinux_field_packager
	builddate = $archlinux_field_builddate
	size = $archlinux_field_size
	arch = $archlinux_field_arch
	pkgdesc = $archlinux_field_pkgdesc
	EOF
	if [ -n "$archlinux_field_depend" ]; then
		local field_depend_single
		while read -r field_depend_single; do
			cat >> "$target" <<- EOF
			depend = $field_depend_single
			EOF
		done <<- EOL
		$(printf '%s' "$archlinux_field_depend")
		EOL
	fi
	if [ -n "$archlinux_field_provides" ]; then
		local field_provides_single
		while read -r field_provides_single; do
			cat >> "$target" <<- EOF
			conflict = $field_provides_single
			provides = $field_provides_single
			EOF
		done <<- EOL
		$(printf '%s' "$archlinux_field_provides")
		EOL
	fi

	# Write the .INSTALL metadata file
	local install_contents
	install_contents=$(archlinux_script_install "$package")
	if [ -n "$install_contents" ]; then
		printf '%s' "$install_contents" > "${package_path}/.INSTALL"
	fi

	# Creates .MTREE
	local option_mtree
	option_mtree=$(option_value 'mtree')
	if [ "$option_mtree" -eq 1 ]; then
		package_archlinux_create_mtree "$package"
	fi
}

# Arch Linux - Build a list of packages
# USAGE: archlinux_packages_build $package[…]
archlinux_packages_build() {
	local package
	for package in "$@"; do
		archlinux_package_build_single "$package"
	done
}

# Arch Linux - Build a single package
# USAGE: archlinux_package_build_single $package
archlinux_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")
	## The path to the generated package must be an absolute path,
	## because we do not run the tar call from the current directory.
	generated_package_path=$(realpath "${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

	# Set basic tar options.
	local tar_version tar_options
	tar_version=$(tar --version | head --lines 1)
	case "$tar_version" in
		(*'GNU tar'*)
			tar_options='--create --group=root --owner=root'
		;;
		(*'libarchive'*)
			tar_options='--create --gname=root --uname=root'
		;;
		(*)
			error_unknown_tar_implementation
			return 1
		;;
	esac

	# Set compression setting
	local option_compression tar_compress_program
	option_compression=$(option_value 'compression')
	case "$option_compression" in
		('none')
			tar_compress_program=''
		;;
		('speed')
			tar_compress_program='zstd --fast=1'
		;;
		('size')
			tar_compress_program='zstd -19'
		;;
	esac

	# Run the actual package generation, using tar
	local package_contents
	package_contents='.PKGINFO *'
	if [ -e "${package_path}/.INSTALL" ]; then
		package_contents=".INSTALL $package_contents"
	fi
	if [ -e "${package_path}/.MTREE" ]; then
		package_contents=".MTREE $package_contents"
	fi
	information_package_building "$package_name"
	## TODO: env --chdir could be used instead of cd in a subshell.
	if ! (
		cd "$package_path"
		if [ -n "$tar_compress_program" ]; then
			tar $tar_options --use-compress-program="$tar_compress_program" --file "$generated_package_path" $package_contents
		else
			tar $tar_options --file "$generated_package_path" $package_contents
		fi
	)
	then
		error_package_generation_failed "$package_name"
		return 1
	fi
}

# creates .MTREE in package
# USAGE: package_archlinux_create_mtree $pkg_path
# RETURNS: nothing
package_archlinux_create_mtree() {
	local package
	package="$1"

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

	info_package_mtree_computation "$package"
	## TODO: env --chdir could be used instead of cd in a subshell.
	(
		cd "$package_path"
		# shellcheck disable=SC2094
		env --ignore-environment find . -print0 |
			env --ignore-environment bsdtar \
			--create \
			--file - \
			--files-from - \
			--format=mtree \
			--no-recursion \
			--null \
			--options='!all,use-set,type,uid,gid,mode,time,size,md5,sha256,link' \
			--exclude .MTREE \
			|
			env --ignore-environment gzip \
			--force \
			--no-name \
			--to-stdout \
			> .MTREE
	)
}

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

	local package_id package_version package_architecture package_name
	package_id=$(package_id "$package")
	package_version=$(package_version)
	package_architecture=$(archlinux_field_arch "$package")
	package_name="${package_id}_${package_version}_${package_architecture}.pkg.tar"

	local option_compression
	option_compression=$(option_value 'compression')
	case $option_compression in
		('speed')
			package_name="${package_name}.zst"
		;;
		('size')
			package_name="${package_name}.zst"
		;;
	esac

	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_archlinux $package
# RETURNS: relative path to a directory, as a string
package_path_archlinux() {
	local package
	package="$1"

	local package_name package_path
	package_name=$(package_name "$package")
	package_path="${package_name%.pkg.tar*}"

	printf '%s' "$package_path"
}

# Tweak the given package id to follow Arch Linux standards
# USAGE: archlinux_package_id $package_id
# RETURNS: the package id, as a non-empty string
archlinux_package_id() {
	local package_id
	package_id="$1"

	# Prepend "lib32-" to the ID of 32-bit packages.
	local package_architecture
	package_architecture=$(package_architecture "$package")
	case "$package_architecture" in
		('32')
			package_id="lib32-${package_id}"
		;;
	esac

	printf '%s' "$package_id"
}

