class_name MainRegion
extends HBoxContainer

signal selected_section_changed
signal sections_reordered

# Store certain scenes here to avoid cyclic reference errors. When wanting to
# instance the scene use `get_window_type()`
# Use 2 arrays to store the scenes since Dictionary exports don't support
# PackedScene type hints
export(Array, PackedScene) var scenes: Array
export(Array, String) var scene_names: Array
export(PackedScene) var SectionButton_scene: PackedScene = preload("res://scenes/sections_list/section_button/section_button.tscn")

# Section names as keys and their PackedScenes as values
var _sections: Dictionary = {}
# Name of the currently selected section
var _selected_section: String = ""
onready var _sections_node: ScrollContainer = find_node("Sections")
# Child nodes that shouldn't be removed
onready var _constant_nodes: Array = [_sections_node]


func _ready() -> void:
	_sections_node.connect("item_dropped", self, "_on_Sections_item_dropped")


func init(sections: Dictionary, sections_order: Array) -> void:
	""" Adds all the sections to the region, in order """
	_sections = sections
	# Add all the sections to the scene
	for section_name in sections.keys():
		if not (section_name is String):
			var msg: String = ("Key in `sections` is not a String: %s" 
					% str(section_name))
			push_error(msg)
			continue
		add_section(section_name)
	
	# Put the sections in order
	for position in range(len(sections_order)):
		if not (sections_order[position] in sections):
			var msg: String = "Value in `sections_order` must also be a key in"
			msg += "`sections`: %s" % sections_order[position]
			push_warning(msg)
			continue
		set_section_position(sections_order[position], position)
	
	sections_order = get_sections_order()
	if len(sections_order) > 0:
		set_selected_section(sections_order[0])


func add_section(section_name: String) -> void:
	""" Creates the nodes for the section in the sections list """
	if _get_section_nodes(section_name)[0]:
		push_warning("Section already exists: %s" % section_name)
		return
	
	var button: SectionButton = SectionButton_scene.instance()
	button.connect("pressed", self, "_on_SectionButton_pressed", [button])
	button.set_name(section_name)
	button.set_text(section_name)
	_sections_node.add_list_item(button)


func set_section_position(section_name: String, section_position: int) -> bool:
	"""
	Changes the order of the section in the control that shows all the 
	sections. 0 is at the top
	
	Returns:
		`true` if the section's position was successfully updated (may not be 
		exactly to `section_position`), `false` otherwise
	"""
	var button: SectionButton = _get_section_nodes(section_name)[0]
	if button != null:
		_sections_node.move_list_item(button, int(max(section_position, 0)))
		return true
	return false


func get_sections_order() -> PoolStringArray:
	""" Returns the names of the sections in their current order """
	var positions: PoolStringArray = PoolStringArray()
	for section in _sections_node.get_list_items():
		positions.append(section.get_name())
	return positions


func set_window(window: Control) -> void:
	"""
	Deselects the selected section and removes its content if applicable, and
	adds the window to the scene
	"""
	deselect_selected_section()
	remove_current_window()
	add_child(window)


func add_window_type(window_type: String, scene_path: String) -> void:
	if get_window_type(window_type) == null:
		scene_names.append(window_type)
		scenes.append(load(scene_path))
	else:
		push_error("Window type '%s' already exists" % window_type)


func get_window_type(window_type: String) -> PackedScene:
	"""
	Returns:
		The PackedScene in `scenes` that is at the same index as `window_type`
		is in `scene_names`
	"""
	var idx: int = scene_names.find(window_type)
	if idx > -1 and len(scenes) > idx:
		return scenes[idx]
	return null


func set_selected_section(section_name: String) -> void:
	"""
	Highlights the button for the section in the section's list, updates the
	text in the current tab and adds the section's content to the scene
	"""
	if _selected_section == section_name:
		return
	
	if _sections.get(section_name):
		var content: Control = _sections.get(section_name).instance()
		content.set_name(section_name)
		set_window(content)
	
	var section_label: Button = _get_section_nodes(section_name)[0]
	if section_label != null:
		section_label.set_active(true)
	_selected_section = section_name
	emit_signal("selected_section_changed", section_name)


func deselect_selected_section() -> void:
	"""
	Deselects the button for the section in the sections list and removes the
	section's content from the scene
	"""
	var old_selection: Array = _get_section_nodes(_selected_section)
	if old_selection[0] != null:
		old_selection[0].set_active(false)
	_selected_section = ""


func remove_current_window() -> void:
	var window: Node = get_child(get_child_count() - 1)
	if not window in _constant_nodes:
		remove_child(window)
		window.queue_free()


func _get_section_nodes(section_name: String) -> Array:
	var section_label: SectionButton = null
	var section_content: Control = get_node_or_null(section_name)
	
	var sections: Array = _sections_node.get_list_items()
	for section in sections:
		if section.get_name() == section_name:
			section_label = section
			break
	
	return [section_label, section_content]


func _on_SectionButton_pressed(button: SectionButton) -> void:
	var section_name: String = button.get_name()
	set_selected_section(section_name)


func _on_Sections_item_dropped() -> void:
	emit_signal("sections_reordered", self)
