@tool
class_name DialogicSettingEvent
extends DialogicEvent

## Event that allows changing a specific setting.


### Settings

enum Modes {SET, RESET, RESET_ALL}
enum SettingValueType {
	STRING,
	NUMBER,
	VARIABLE,
	EXPRESSION
}

## The name of the setting to save to.
var name := ""
var _value_type := 0 :
	get:
		return _value_type
	set(_value):
		_value_type = _value
		if not _suppress_default_value:
			match _value_type:
				SettingValueType.STRING, SettingValueType.VARIABLE, SettingValueType.EXPRESSION:
					value = ""
				SettingValueType.NUMBER:
					value = 0
			ui_update_needed.emit()

var value: Variant = ""

var mode := Modes.SET

## Used to suppress _value_type from overwriting value with a default value when the type changes
## This is only used when initializing the event_variable.
var _suppress_default_value: bool = false

################################################################################
## 						INITIALIZE
################################################################################

func _execute() -> void:
	if mode == Modes.RESET or mode == Modes.RESET_ALL:
		if !name.is_empty() and mode != Modes.RESET_ALL:
			dialogic.Settings.reset_setting(name)
		else:
			dialogic.Settings.reset_all()
	else:
		match _value_type:
			SettingValueType.STRING:
				dialogic.Settings.set(name, value)
			SettingValueType.NUMBER:
				dialogic.Settings.set(name, float(value))
			SettingValueType.VARIABLE:
				if dialogic.has_subsystem('VAR'):
					dialogic.Settings.set(name, dialogic.VAR.get_variable('{'+value+'}'))
			SettingValueType.EXPRESSION:
				if dialogic.has_subsystem('VAR'):
					dialogic.Settings.set(name, dialogic.VAR.get_variable(value))
	finish()


################################################################################
## 						INITIALIZE
################################################################################

func _init() -> void:
	event_name = "Setting"
	set_default_color('Color9')
	event_category = "Helpers"
	event_sorting_index = 2


func _get_icon() -> Resource:
	return load(self.get_script().get_path().get_base_dir().path_join('icon.svg'))


################################################################################
## 						SAVING/LOADING
################################################################################

func to_text() -> String:
	var string := "setting "
	if mode != Modes.SET:
		string += "reset "

	if !name.is_empty() and mode != Modes.RESET_ALL:
		string += '"' + name + '"'

	if mode == Modes.SET:
		string += " = "
		value = str(value)
		match _value_type:
			SettingValueType.STRING: # String
				string += '"'+value.replace('"', '\\"')+'"'
			SettingValueType.NUMBER,SettingValueType.EXPRESSION: # Float or Expression
				string += str(value)
			SettingValueType.VARIABLE: # Variable
				string += '{'+value+'}'

	return string


func from_text(string:String) -> void:
	var reg := RegEx.new()
	reg.compile('setting (?<reset>reset)? *("(?<name>[^=+\\-*\\/]*)")?( *= *(?<value>.*))?')
	var result := reg.search(string)
	if !result:
		return

	if result.get_string('reset'):
		mode = Modes.RESET

	name = result.get_string('name').strip_edges()

	if name.is_empty() and mode == Modes.RESET:
		mode = Modes.RESET_ALL

	if result.get_string('value'):
		_suppress_default_value = true
		value = result.get_string('value').strip_edges()
		if value.begins_with('"') and value.ends_with('"') and value.count('"')-value.count('\\"') == 2:
			value = result.get_string('value').strip_edges().replace('"', '')
			_value_type = SettingValueType.STRING
		elif value.begins_with('{') and value.ends_with('}') and value.count('{') == 1:
			value = result.get_string('value').strip_edges().trim_suffix('}').trim_prefix('{')
			_value_type = SettingValueType.VARIABLE
		else:
			value = result.get_string('value').strip_edges()
			if value.is_valid_float():
				_value_type = SettingValueType.NUMBER
			else:
				_value_type = SettingValueType.EXPRESSION
		_suppress_default_value = false


func is_valid_event(string:String) -> bool:
	return string.begins_with('setting')


################################################################################
## 						EDITOR REPRESENTATION
################################################################################

func build_event_editor() -> void:
	add_header_edit('mode', ValueType.FIXED_OPTIONS, {
		'options': [{
				'label': 'Set',
				'value': Modes.SET,
				'icon': load("res://addons/dialogic/Editor/Images/Dropdown/default.svg")
			},{
				'label': 'Reset',
				'value': Modes.RESET,
				'icon': load("res://addons/dialogic/Editor/Images/Dropdown/update.svg")
			},{
				'label': 'Reset All',
				'value': Modes.RESET_ALL,
				'icon': load("res://addons/dialogic/Editor/Images/Dropdown/update.svg")
			},
			]})

	add_header_edit('name', ValueType.DYNAMIC_OPTIONS, {'placeholder':'Type setting', 'suggestions_func':get_settings_suggestions}, 'mode != Modes.RESET_ALL')
	add_header_edit('_value_type', ValueType.FIXED_OPTIONS, {'left_text':'to',
		'options': [
			{
				'label': 'String',
				'icon': ["String", "EditorIcons"],
				'value': SettingValueType.STRING
			},{
				'label': 'Number',
				'icon': ["float", "EditorIcons"],
				'value': SettingValueType.NUMBER
			},{
				'label': 'Variable',
				'icon': ["ClassList", "EditorIcons"],
				'value': SettingValueType.VARIABLE
			},{
				'label': 'Expression',
				'icon': ["Variant", "EditorIcons"],
				'value': SettingValueType.EXPRESSION
			}],
		'symbol_only':true},
		'!name.is_empty() and mode == Modes.SET')
	add_header_edit('value', ValueType.SINGLELINE_TEXT, {}, '!name.is_empty() and (_value_type == SettingValueType.STRING or _value_type == SettingValueType.EXPRESSION) and mode == Modes.SET')
	add_header_edit('value', ValueType.NUMBER, {}, '!name.is_empty()  and _value_type == SettingValueType.NUMBER and mode == Modes.SET')
	add_header_edit('value', ValueType.DYNAMIC_OPTIONS,
			{'suggestions_func' : get_value_suggestions, 'placeholder':'Select Variable'},
			'!name.is_empty() and _value_type == SettingValueType.VARIABLE and mode == Modes.SET')


func get_settings_suggestions(filter:String) -> Dictionary:
	var suggestions := {filter:{'value':filter, 'editor_icon':["GDScriptInternal", "EditorIcons"]}}

	for prop in ProjectSettings.get_property_list():
		if prop.name.begins_with('dialogic/settings/'):
			suggestions[prop.name.trim_prefix('dialogic/settings/')] = {'value':prop.name.trim_prefix('dialogic/settings/'), 'editor_icon':["GDScript", "EditorIcons"]}
	return suggestions


func get_value_suggestions(_filter:String) -> Dictionary:
	var suggestions := {}

	var vars: Dictionary = ProjectSettings.get_setting('dialogic/variables', {})
	for var_path in DialogicUtil.list_variables(vars):
		suggestions[var_path] = {'value':var_path, 'editor_icon':["ClassList", "EditorIcons"]}
	return suggestions



####################### CODE COMPLETION ########################################
################################################################################

func _get_code_completion(CodeCompletionHelper:Node, TextNode:TextEdit, line:String, _word:String, symbol:String) -> void:
	if symbol == " " and !"reset" in line and !'=' in line and !'"' in line:
		TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, "reset", "reset ", event_color.lerp(TextNode.syntax_highlighter.normal_color, 0.5), TextNode.get_theme_icon("RotateLeft", "EditorIcons"))
		TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, "reset all", "reset \n", event_color.lerp(TextNode.syntax_highlighter.normal_color, 0.5), TextNode.get_theme_icon("ToolRotate", "EditorIcons"))

	if (symbol == " " or symbol == '"') and !"=" in line and CodeCompletionHelper.get_line_untill_caret(line).count('"') != 2:
		for i in get_settings_suggestions(''):
			if i.is_empty():
				continue
			if symbol == '"':
				TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, i, i, event_color.lerp(TextNode.syntax_highlighter.normal_color, 0.5), TextNode.get_theme_icon("GDScript", "EditorIcons"), '"')
			else:
				TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, i, '"'+i, event_color.lerp(TextNode.syntax_highlighter.normal_color, 0.5), TextNode.get_theme_icon("GDScript", "EditorIcons"), '"')


func _get_start_code_completion(_CodeCompletionHelper:Node, TextNode:TextEdit) -> void:
	TextNode.add_code_completion_option(CodeEdit.KIND_PLAIN_TEXT, 'setting', 'setting ', event_color)

#################### SYNTAX HIGHLIGHTING #######################################
################################################################################

func _get_syntax_highlighting(Highlighter:SyntaxHighlighter, dict:Dictionary, line:String) -> Dictionary:
	dict[line.find('setting')] = {"color":event_color}
	dict[line.find('setting')+7] = {"color":Highlighter.normal_color}
	dict = Highlighter.color_word(dict, event_color, line, 'reset')
	dict = Highlighter.color_region(dict, Highlighter.string_color, line, '"', '"')
	dict = Highlighter.color_region(dict, Highlighter.variable_color, line, '{', '}')
	return dict
