# Set the identifier of the current archive
# USAGE: set_current_archive $archive
set_current_archive() {
	local archive
	archive="$1"

	# Check that the identifier uses the expected ARCHIVE_BASE_xxx format.
	local regexp
	regexp='^ARCHIVE_BASE\(_[0-9A-Z]\+\)*_[0-9]\+$'
	if ! printf '%s' "$archive" | grep --quiet --regexp="$regexp"; then
		# Allow the old ARCHIVE_xxx format when targeting a compatibility level < 2.21.
		if ! compatibility_level_is_at_least '2.21'; then
			regexp='^ARCHIVE\(_[0-9A-Z]\+\)\+$'
			if ! printf '%s' "$archive" | grep --quiet --regexp="$regexp"; then
				error_current_archive_format_invalid "$archive"
				return 1
			fi
		else
			error_current_archive_format_invalid "$archive"
			return 1
		fi
	fi

	export PLAYIT_CONTEXT_ARCHIVE="$archive"
}

# Set the identifier of the current package
# USAGE: set_current_package $package
set_current_package() {
	local package
	package="$1"

	# Check that the identifier uses the expected PKG_xxx format.
	local regexp
	regexp='^PKG\(_[0-9A-Z]\+\)\+$'
	if ! printf '%s' "$package" | grep --quiet --regexp="$regexp"; then
		error_current_package_format_invalid "$package"
		return 1
	fi

	# Check that the identifier is included in the list of packages to build.
	if ! package_is_included_in_packages_list "$package"; then
		error_current_package_not_in_list "$package"
		return 1
	fi

	export PLAYIT_CONTEXT_PACKAGE="$package"
}

# Print the identifier of the current archive.
# USAGE: current_archive
# RETURNS: the current archive identifier,
#          or an empty string if no archive is set
current_archive() {
	# To ensure backwards-compatibility, the legacy variable should have a higher priority than the modern one.
	# Otherwise the ability to set the context using $ARCHIVE from game scripts would be lost as soon as the library calls set_current_archive.
	local archive
	archive="${ARCHIVE:-}"
	if \
		[ -n "$archive" ] && \
		compatibility_level_is_at_least '2.27'
	then
		warning_context_legacy_archive
	fi

	if [ -z "$archive" ]; then
		archive="${PLAYIT_CONTEXT_ARCHIVE:-}"
	fi

	printf '%s' "$archive"
}

# Print the identifier of the current package.
# USAGE: current_package
# RETURN: the current package identifier
current_package() {
	# To ensure backwards-compatibility, the legacy variable should have a higher priority than the modern one.
	# Otherwise the ability to set the context using $PKG from game scripts would be lost as soon as the library calls set_current_package.
	local package
	package="${PKG:-}"
	if \
		[ -n "$package" ] && \
		compatibility_level_is_at_least '2.27'
	then
		warning_context_legacy_package
	fi

	if [ -z "$package" ]; then
		package="${PLAYIT_CONTEXT_PACKAGE:-}"
	fi

	# If no package context is explicitly set, set it to the first package in the list of packages to build.
	if [ -z "$package" ]; then
		local packages_list
		packages_list=$(packages_list)
		package=$(printf '%s' "$packages_list" | head --lines=1)
		set_current_package "$package"
	fi

	printf '%s' "$package"
}

# Print the suffix of the identifier of the current archive.
# USAGE: current_archive_suffix
# RETURN: the current archive identifier suffix including the leading underscore,
#         or an empty string if no archive is set
current_archive_suffix() {
	if ! compatibility_level_is_at_least '2.21'; then
		current_archive_suffix_legacy
		return 0
	fi

	local archive
	archive=$(current_archive)

	printf '%s' "${archive#ARCHIVE_BASE}"
}

# Print the suffix of the identifier of the current package.
# USAGE: current_package_suffix
# RETURN: the current package identifier suffix including the leading underscore
current_package_suffix() {
	local package
	package=$(current_package)

	printf '%s' "${package#PKG}"
}

# Print the name of the variable containing the context-specific value of the given variable
# Context priority order is the following one:
# - archive-specific
# - package-specific
# - default
# - empty
# USAGE: context_name $variable_name
# RETURN: the name of the variable containing the context-specific value,
#         or an empty string
context_name() {
	local variable_name
	variable_name="$1"

	local current_archive_suffix current_package_suffix
	current_archive_suffix=$(current_archive_suffix)
	current_package_suffix=$(current_package_suffix)

	# Try to find an archive-specific value for the given variable.
	local context_name_archive
	if [ -n "$current_archive_suffix" ]; then
		context_name_archive=$(context_name_archive "$variable_name")
		if [ -n "$context_name_archive" ]; then
			printf '%s' "$context_name_archive"
			return 0
		fi
	fi

	# Try to find a package-specific value for the given variable.
	local context_name_package
	if [ -n "$current_package_suffix" ] ; then
		context_name_package=$(context_name_package "$variable_name")
		if [ -n "$context_name_package" ]; then
			printf '%s' "$context_name_package"
			return 0
		fi
	fi

	# Check if the base variable value is set.
	if ! variable_is_empty "$variable_name"; then
		printf '%s' "$variable_name"
		return 0
	fi

	# If no value has been found for the given variable, an empty string is returned.
}

# Print the name of the variable containing the archive-specific value of the given variable
# USAGE: context_name_archive $variable_name
# RETURN: the name of the variable containing the archive-specific value,
#         or an empty string
context_name_archive() {
	local variable_name
	variable_name="$1"

	local current_archive_suffix
	current_archive_suffix=$(current_archive_suffix)
	# Return early if no archive context is set
	if [ -z "$current_archive_suffix" ]; then
		return 0
	fi

	local current_archive_name
	while [ -n "$current_archive_suffix" ]; do
		current_archive_name="${variable_name}${current_archive_suffix}"
		if ! variable_is_empty "$current_archive_name"; then
			printf '%s' "$current_archive_name"
			return 0
		fi
		current_archive_suffix="${current_archive_suffix%_*}"
	done

	# If no value has been found for the given variable, an empty string is returned.
}

# Print the name of the variable containing the package-specific value of the given variable
# USAGE: context_name_package $variable_name
# RETURN: the name of the variable containing the package-specific value,
#         or an empty string
context_name_package() {
	local variable_name
	variable_name="$1"

	local current_package_suffix
	current_package_suffix=$(current_package_suffix)
	# Return early if no package context is set
	if [ -z "$current_package_suffix" ]; then
		return 0
	fi

	local current_package_name
	while [ -n "$current_package_suffix" ]; do
		current_package_name="${variable_name}${current_package_suffix}"
		if ! variable_is_empty "$current_package_name"; then
			printf '%s' "$current_package_name"
			return 0
		fi
		current_package_suffix="${current_package_suffix%_*}"
	done

	# If no value has been found for the given variable, an empty string is returned.
}

# Print the context-sensitive value for the given variable
# Context priority order is the following one:
# - archive-specific
# - package-specific
# - default
# - empty
# USAGE: context_value $variable_name
# RETURN: the context-sensitive value of the given variable,
#         or an empty string
context_value() {
	local variable_name
	variable_name="$1"

	local context_name
	context_name=$(context_name "$variable_name")
	# Return early if this variable has no set value.
	if [ -z "$context_name" ]; then
		return 0
	fi

	get_value "$context_name"
}

