extends DialogicSubsystem

## Subsystem that handles glossaries.

## List of glossary resources that are used.
var glossaries := []
## If false, no parsing will be done.
var enabled := true

## Any key in this dictionary will overwrite the color for any item with that name.
var color_overrides := {}

const SETTING_DEFAULT_COLOR := 'dialogic/glossary/default_color'


#region STATE
####################################################################################################

func clear_game_state(_clear_flag := DialogicGameHandler.ClearFlags.FULL_CLEAR) -> void:
	glossaries = []

	for path: String in ProjectSettings.get_setting('dialogic/glossary/glossary_files', []):
		add_glossary(path)

#endregion


#region MAIN METHODS
####################################################################################################

func parse_glossary(text: String) -> String:
	if not enabled:
		return text

	var def_case_sensitive: bool = ProjectSettings.get_setting('dialogic/glossary/default_case_sensitive', true)
	var def_color: Color = ProjectSettings.get_setting(SETTING_DEFAULT_COLOR, Color.POWDER_BLUE)
	var regex := RegEx.new()

	for glossary: DialogicGlossary in glossaries:

		if !glossary.enabled:
			continue

		for entry_value: Variant in glossary.entries.values():

			if not entry_value is Dictionary:
				continue

			var entry: Dictionary = entry_value
			var entry_key: String = entry.get(DialogicGlossary.NAME_PROPERTY, "")

			# Older versions of the glossary resource do not have a property
			# for their name, we must skip these.
			# They can be updated by opening the resource in the glossary
			# editor.
			if entry_key.is_empty():
				continue

			if not entry.get('enabled', true):
				continue

			var regex_options := glossary.get_set_regex_option(entry_key)

			if regex_options.is_empty():
				continue

			var pattern: String = '(?<=\\W|^)(?<!\\\\)(?<word>' + regex_options + ')(?!])(?=\\W|$)'

			if entry.get('case_sensitive', def_case_sensitive):
				regex.compile(pattern)

			else:
				regex.compile('(?i)'+pattern)

			var color: String = entry.get('color', def_color).to_html()

			if entry_key in color_overrides:
				color = color_overrides[entry_key].to_html()

			text = regex.sub(text,
				'[url=' + entry_key + ']' +
				'[color=' + color + ']${word}[/color]' +
				'[/url]',
				true
				)

	return text


func add_glossary(path:String) -> void:
	if ResourceLoader.exists(path):
		var resource: DialogicGlossary = load(path)

		if resource is DialogicGlossary:
			glossaries.append(resource)
	else:
		printerr('[Dialogic] The glossary file "' + path + '" is missing. Make sure it exists.')


## Iterates over all glossaries and returns the first one that matches the
## [param entry_key].
##
## Runtime complexity:
## O(n), where n is the number of glossaries.
func find_glossary(entry_key: String) -> DialogicGlossary:
	for glossary: DialogicGlossary in glossaries:

		if glossary.entries.has(entry_key):
			return glossary

	return null


## Returns the first match for a given entry key.
## If translation is available and enabled, it will be translated
func get_entry(entry_key: String) -> Dictionary:
	var glossary: DialogicGlossary = dialogic.Glossary.find_glossary(entry_key)

	var result := {
		"title": "",
		"text": "",
		"extra": "",
		"color": Color.WHITE,
		}

	if glossary == null:
		return {}

	var is_translation_enabled: bool = ProjectSettings.get_setting('dialogic/translation/enabled', false)

	var entry := glossary.get_entry(entry_key)

	if entry.is_empty():
		return {}

	result.color = entry.get("color")
	if result.color == null:
		result.color = ProjectSettings.get_setting(SETTING_DEFAULT_COLOR, Color.POWDER_BLUE)

	if is_translation_enabled and not glossary._translation_id.is_empty():
		var translation_key: String = glossary._translation_keys.get(entry_key)
		var last_slash := translation_key.rfind('/')

		if last_slash == -1:
			return {}

		var tr_base := translation_key.substr(0, last_slash)

		result.title = translate(tr_base, "title", entry)
		result.text = translate(tr_base, "text", entry)
		result.extra = translate(tr_base, "extra", entry)
	else:
		result.title = entry.get("title", "")
		result.text = entry.get("text", "")
		result.extra = entry.get("extra", "")

	## PARSE TEXTS FOR VARIABLES
	result.title = dialogic.VAR.parse_variables(result.title)
	result.text = dialogic.VAR.parse_variables(result.text)
	result.extra = dialogic.VAR.parse_variables(result.extra)

	return result



## Tries to translate the property with the given
func translate(tr_base: String, property: StringName, fallback_entry: Dictionary) -> String:
	var tr_key := tr_base.path_join(property)
	var tr_value := tr(tr_key)

	if tr_key == tr_value:
		tr_value = fallback_entry.get(property, "")

	return tr_value
