# Print a localized message
# USAGE: print_message $level $message $extra_values[…]
print_message() {
	local level
	# Valid levels are:
	# - error
	# - warning
	# - warning_once
	# - info
	# - info_once
	# Unknown levels will be handled similar to "info".
	level="$1"
	shift 1

	case "$level" in
		('error')
			print_message_error "$@"
		;;
		('warning')
			print_message_warning "$@"
		;;
		('warning_once')
			print_message_warning_once "$@"
		;;
		('info_once')
			print_message_info_once "$@"
		;;
		('info'|*)
			print_message_info "$@"
		;;
	esac
}

# Print a localized error message
# USAGE: print_message_error $message $extra_values[…]
print_message_error() (
	local message
	# The message is a format string, any included "%s" will be replaced by the values passed as extra arguments.
	# See printf(1) for details on the sequences that can be used in the format string.
	message="$1"
	shift 1

	## Since this is called from a subshell, this should not trigger unwanted output redirections.
	exec 1>&2
	local messages_language error_string
	messages_language=$(messages_language)
	case "$messages_language" in
		('fr')
			error_string='Erreur :'
		;;
		('en'|*)
			error_string='Error:'
		;;
	esac
	printf '\n\033[1;31m%s\033[0m\n' "$error_string"
	## Silence ShellCheck false-positive
	## Don't use variables in the printf format string. Use printf "..%s.." "$foo".
	# shellcheck disable=SC2059
	printf -- "$message" "$@"
)

# Print a localized warning message
# USAGE: print_message_warning $message $extra_values[…]
print_message_warning() {
	local message
	# The message is a format string, any included "%s" will be replaced by the values passed as extra arguments.
	# See printf(1) for details on the sequences that can be used in the format string.
	message="$1"
	shift 1

	local messages_language warning_string
	messages_language=$(messages_language)
	case "$messages_language" in
		('fr')
			warning_string='Avertissement :'
		;;
		('en'|*)
			warning_string='Warning:'
		;;
	esac
	printf '\n\033[1;33m%s\033[0m\n' "$warning_string"
	## Silence ShellCheck false-positive
	## Don't use variables in the printf format string. Use printf "..%s.." "$foo".
	# shellcheck disable=SC2059
	printf -- "$message" "$@"
}

# Print a localized warning message, only if it has not already been shown
# USAGE: print_message_warning_once $message $extra_values[…]
print_message_warning_once() {
	# Return early if this message has already been shown.
	if message_has_been_shown_already "$@"; then
		return 0
	fi

	print_message_warning "$@"

	# Prevent this message from being shown again.
	messages_already_shown_add "$@"
}

# Print a localized information message
# USAGE: print_message_info $message $extra_values[…]
print_message_info() {
	local message
	# The message is a format string, any included "%s" will be replaced by the values passed as extra arguments.
	# See printf(1) for details on the sequences that can be used in the format string.
	message="$1"
	shift 1

	## Silence ShellCheck false-positive
	## Don't use variables in the printf format string. Use printf "..%s.." "$foo".
	# shellcheck disable=SC2059
	printf -- "$message" "$@"
}

# Print a localized information message, only if it has not already been shown
# USAGE: print_message_info_once $message $extra_values[…]
print_message_info_once() {
	# Return early if this message has already been shown.
	if message_has_been_shown_already "$@"; then
		return 0
	fi

	print_message_info "$@"

	# Prevent this message from being shown again.
	messages_already_shown_add "$@"
}

# Compute a unique message indentifier from a message function name and its arguments
# USAGE: message_identifier $message $extra_values[…]
message_identifier() {
	local message_function
	message_function="$1"
	shift 1

	printf '%s' "$message_function"
	if [ $# -ge 1 ]; then
		printf ':%s' "$@"
	fi
}

# Print the path to a file listing messages already shown
# USAGE: messages_already_shown_file
# RETURN: the path to the file listing the messages,
#         or an empty string if such a path can not be computed yet
messages_already_shown_file() {
	# The list of shown messages can only be used when PLAYIT_WORKDIR is already set.
	if [ -z "${PLAYIT_WORKDIR:-}" ]; then
		return 0
	fi

	printf '%s/messages-shown' "$PLAYIT_WORKDIR"
}

# Add a message to the list of already shown ones.
# USAGE: messages_already_shown_add $message $extra_values[…]
messages_already_shown_add() {
	local messages_list
	messages_list=$(messages_already_shown_file)
	# The list of shown messages can only be used when PLAYIT_WORKDIR is already set.
	if [ -z "$messages_list" ]; then
		return 0
	fi

	local message_identifier
	message_identifier=$(message_identifier "$@")

	printf '%s\n' "$message_identifier" >> "$messages_list"
}

# Check if a message has already been shown.
# USAGE: messages_has_been_shown_already $message $extra_values[…]
# RETURN: 0 if the given message has already been shown,
#         1 if there is no messages list yet,
#         1 otherwise
message_has_been_shown_already() {
	local messages_list
	messages_list=$(messages_already_shown_file)
	# The list of shown messages can only be used when PLAYIT_WORKDIR is already set.
	if [ -z "$messages_list" ]; then
		return 1
	fi

	# Return early if there is no list of shown messages yet.
	if [ ! -e "$messages_list" ]; then
		return 1
	fi

	local message_identifier
	message_identifier=$(message_identifier "$@")

	grep --quiet --fixed-strings --line-regexp --regexp="$message_identifier" "$messages_list"
}

