# Print a list of directories to scan for game scripts
# Each path is printed on its own line.
# USAGE: games_list_sources
games_list_sources() {
	# If an explicit path has been set, limit the search to this path
	local option_collection_path
	option_collection_path=$(option_value 'collection-path')
	if [ -n "$option_collection_path" ]; then
		printf '%s' "$option_collection_path"
		return 0
	fi

	# Include the current user game scripts collections
	local user_collections_basedir
	user_collections_basedir="${XDG_DATA_HOME:=$HOME/.local/share}/play.it/collections"
	if [ -d "$user_collections_basedir" ]; then
		find "$user_collections_basedir" -mindepth 1 -maxdepth 1 -type d | sort
	fi
	# Include the system-provided game scripts collections
	local system_prefix system_collections_basedir
	for system_prefix in \
		'/usr/local/share/games' \
		'/usr/local/share' \
		'/usr/share/games' \
		'/usr/share'
	do
		system_collections_basedir="${system_prefix}/play.it/collections"
		if [ -d "$system_collections_basedir" ]; then
			find "$system_collections_basedir" -mindepth 1 -maxdepth 1 -type d | sort
		fi
	done

	# Look for game scripts in the legacy "games" paths
	## These have a lower priority than the "collections" paths.
	user_collections_basedir="${XDG_DATA_HOME:=$HOME/.local/share}/play.it/games"
	if [ -d "$user_collections_basedir" ]; then
		find "$user_collections_basedir" -mindepth 1 -maxdepth 1 -type d | sort
	fi
	for system_prefix in \
		'/usr/local/share/games' \
		'/usr/local/share' \
		'/usr/share/games' \
		'/usr/share'
	do
		system_collections_basedir="${system_prefix}/play.it/games"
		if [ -d "$system_collections_basedir" ]; then
			find "$system_collections_basedir" -mindepth 1 -maxdepth 1 -type d | sort
		fi
	done
}

# List all available game scripts
# USAGE: games_list_scripts_all
# RETURN: a list of available game scripts,
#         separated by line breaks
games_list_scripts_all() {
	local games_sources
	games_sources=$(games_list_sources)

	# Throw an error if no source of game scripts is found
	if [ -z "$games_sources" ]; then
		error_no_collection
		return 1
	fi

	while read -r games_collection; do
		find "$games_collection" -name play-\*.sh | sort
	done <<- EOF
	$(printf '%s' "$games_sources")
	EOF
}

# List the game scripts providing support for the given archive name
# USAGE: games_find_scripts_for_archive $archive_name
# RETURN: a list of game scripts,
#         separated by line breaks
games_find_scripts_for_archive() {
	local archive_name
	archive_name="$1"

	# games_list_scripts_all is called on its own first, so its error code is not hidden by the pipe
	local scripts_list
	scripts_list=$(games_list_scripts_all)
	# grep error status in case of no game script found is ignored
	printf '%s' "$scripts_list" | xargs --no-run-if-empty grep \
		--files-with-matches \
		--regexp="^ARCHIVE_[0-9A-Z_]\\+=['\"]${archive_name}['\"]" || true
}

# Print the path to the first game script with support with the given archive name
# USAGE: games_find_script_for_archive $archive_name
# RETURN: the path to a single game script
games_find_script_for_archive() {
	local archive_name
	archive_name="$1"

	local scripts_list
	scripts_list=$(games_find_scripts_for_archive "$archive_name")

	# Throw an error if no game script is found for the given archive
	if [ -z "$scripts_list" ]; then
		error_no_script_found_for_archive "$archive_name"
		## Remove the empty working directory
		rmdir "$PLAYIT_WORKDIR"
		return 1
	fi

	# If multiple scripts have been found with support for a given archive name,
	# run some extra tests to find the correct one
	if [ "$(printf '%s' "$scripts_list" | wc --lines)" -gt 1 ]; then
		local hash_reference archive_identifiers archive_identifier archive_hash
		while read -r script; do
			# Parse the archive identifiers from the game script
			# Multiple identifiers can be found if several archives of the given name are supported by the current script
			archive_identifiers=$(sed --silent --regexp-extended "s/^(ARCHIVE_BASE(_[A-Z0-9]+)*_[0-9]+)_NAME=['\"]?${archive_name}['\"]?$/\\1/p" "$script")
			# If no identifier is found, try the legacy variable without the "_NAME" suffix
			if [ -z "$archive_identifiers" ]; then
				archive_identifiers=$(sed --silent --regexp-extended "s/^(ARCHIVE_BASE(_[A-Z0-9]+)*_[0-9]+)=['\"]?${archive_name}['\"]?$/\\1/p" "$script")
			fi
			for archive_identifier in $archive_identifiers; do
				# Parse the archive hash from the game script
				## FIXME: Fix hash parsing for archives with multiple valid hashes.
				archive_hash=$(sed --silent --regexp-extended "s/^${archive_identifier}_MD5=['\"]?([0-9a-f]+)['\"]?$/\\1/p" "$script")
				# If this is the first archive of the list, set its hash as the reference
				if [ -z "${hash_reference:-}" ]; then
					hash_reference="$archive_hash"
				fi
				# If the hash is distinct from the reference, we need to run a hash comparison to find the correct script
				if [ "$archive_hash" != "$hash_reference" ]; then
					game_find_script_by_hash "$scripts_list"
					return 0
				fi
			done
		done <<- EOL
		$(printf '%s' "$scripts_list")
		EOL
	fi

	printf '%s' "$scripts_list" | head --lines=1
}

# Discriminate between multiple game scripts using the archive hash
# USAGE: game_find_script_by_hash $scripts_list
# RETURN: the path to a single game script
game_find_script_by_hash() {
	# The list of scripts that should be parsed, separated by line breaks
	local scripts_list
	scripts_list="$1"

	# Compute the hash of the current archive
	local archive_name archive_hash
	archive_name=$(archive_name 'SOURCE_ARCHIVE')
	archive_hash=$(archive_hash_md5_computed "$archive_name")

	local regexp
	regexp="^ARCHIVE_BASE(_[A-Z0-9]+)*_[0-9]+_MD5=['\"]?${archive_hash}['\"]?$"
	printf '%s' "$scripts_list" | xargs grep \
		--files-with-matches \
		--extended-regexp --regexp="$regexp" |
		head --lines=1
}

# Print the version of the current game script
# USAGE: script_version
# RETURN: the script version string,
#         throw an error if it is not set,
#         throw an error if it does not follow the expected format
script_version() {
	local version_string
	version_string="${script_version:-}"

	# Throw an error if the script version is not set
	if [ -z "$version_string" ]; then
		error_missing_variable 'script_version'
		return 1
	fi

	# Throw an error if the version string does not use the expected format
	local regexp
	regexp='^[0-9]\{8\}\.[0-9]\+$'
	if ! printf '%s' "$version_string" | grep --quiet --regexp="$regexp"; then
		error_invalid_version_string "$version_string"
		return 1
	fi

	printf '%s' "$version_string"
}

