extends MarginContainer

# Max number of characters in a tab title
const TAB_TITLE_MAX_LENGTH = 20

export(Dictionary) var sections: Dictionary = {
	"Home": load("res://src/scenes/sections_content/home/home.tscn"),
	"Following": load("res://src/scenes/sections_content/following/following.tscn"),
}
export(PackedScene) var main_region: PackedScene


var _tab_title_trackers: Array = []
var _async_helper := AsyncHelper.new(self)
onready var _tabs_node: Tabs = find_node("Tabs")
onready var _main_regions_node: PanelContainer = find_node("MainRegions")
onready var sections_order: PoolStringArray = Data.get_sections_order()


func _ready() -> void:
	_tabs_node.connect("tab_changed", self, "_on_Tabs_tab_changed")
	_tabs_node.connect("reposition_active_tab_request", self,
			"_on_Tabs_reposition_active_tab_request")
	_tabs_node.connect("tab_close", self, "_on_Tabs_tab_close")
	
	var extensions: Dictionary = Extensions.load_extensions()
	for section_name in extensions:
		if section_name and extensions[section_name]:
			sections[section_name] = extensions[section_name]
	add_main_region()


func _exit_tree() -> void:
	Data.save_sections_order(sections_order)


func add_main_region(duplicate_current_region: bool=false) -> void:
	var region: MainRegion = main_region.instance()
	region.connect("window_changed", self, "_on_MainRegion_window_changed",
			[region])
	region.connect(
			"sections_reordered", self, "_on_MainRegion_sections_reordered")
	
	if duplicate_current_region:
		var state: Dictionary = {}
		# Get state of the current main region
		for i in range(_main_regions_node.get_child_count()):
			var region_node: MainRegion = _main_regions_node.get_child(i)
			if region_node.is_visible():
				state = region_node.get_state()
				break
		
		if not state.empty():
			region.set_state(state)
	
	_tabs_node.add_tab()
	_main_regions_node.add_child(region)
	region.init(sections, sections_order)
	
	_tabs_node.set_current_tab(_tabs_node.get_tab_count() - 1)


func _on_Tabs_tab_changed(tab_idx: int) -> void:
	"""
	Makes the main region associated with the tab at `tab_idx` visible, hides
	all other main regions
	"""
	if tab_idx < 0 or tab_idx >= _main_regions_node.get_child_count():
		push_error("No node assiciated with the tab at index %d" % tab_idx)
		return
	
	for child in _main_regions_node.get_children():
		child.set_visible(false)
	_main_regions_node.get_child(tab_idx).set_visible(true)


func _on_Tabs_reposition_active_tab_request(tab_to_idx: int) -> void:
	"""
	Rearranges the main regions in accordance to the rearrangement of the tabs
	"""
	var tab_idx: int = _tabs_node.get_current_tab()
	if tab_idx < 0 or tab_idx >= _main_regions_node.get_child_count():
		push_error("No node assiciated with the tab at index %d" % tab_idx)
		return
	
	_main_regions_node.move_child(_main_regions_node.get_child(tab_idx),
			tab_to_idx)


func _on_Tabs_tab_close(tab_idx: int) -> void:
	"""
	Removes the tab and main region when the tab's close button is pressed
	"""
	if tab_idx < 0 or tab_idx >= _main_regions_node.get_child_count():
		push_error("No node assiciated with the tab at index %d" % tab_idx)
		return
	
	var child: Control = _main_regions_node.get_child(tab_idx)
	_main_regions_node.remove_child(child)
	child.queue_free()
	_tabs_node.remove_tab(tab_idx)
	
	if _tabs_node.get_current_tab() > -1:
		# Update to show the newly selected tab
		_on_Tabs_tab_changed(_tabs_node.get_current_tab())


func _on_MainRegion_window_changed(window: Control, container: Control
		) -> void:
	""" Sets the text of the tab that `container` is in """
	var tab_title
	var cancelled: bool = false
	
	# Cancel all other trackers waiting for a tab title, so only the most
	# recent call will be applied
	for tab_title_tracker in _tab_title_trackers:
		_async_helper.cancel(tab_title_tracker["id"])
	
	if window.has_method("get_tab_title"):
		tab_title = window.get_tab_title()
		if tab_title is GDScriptFunctionState:
			# Wait for tab title to be returned
			var tracker: Dictionary = _async_helper.connect_wrapped(
					window.get_tab_title(), "completed")
			_tab_title_trackers.append(tracker)
			cancelled = yield(_async_helper.wait_until_finished([tracker]),
					"completed")[0]
			tab_title = tracker["result"]
			_tab_title_trackers.erase(tracker)
	else:
		tab_title = window.get_name()
	
	if not cancelled:
		if len(tab_title) > TAB_TITLE_MAX_LENGTH:
			tab_title = tab_title.substr(0, TAB_TITLE_MAX_LENGTH - 3) + "..."
		_tabs_node.set_tab_title(container.get_position_in_parent(), tab_title)


func _on_MainRegion_sections_reordered(region: MainRegion) -> void:
	"""
	When the order of the sections is updated in one `MainRegion`, that is
	saved as the order that should be used in the future and all other
	`MainRegion`s are updated to use that order
	"""
	sections_order = region.get_sections_order()
	for child in _tabs_node.get_children():
		var a_region: MainRegion = child.get_child(0)
		if not a_region is MainRegion:
			push_warning("MainRegion not found")
			continue
		for position in range(len(sections_order)):
			a_region.set_section_position(sections_order[position], position)
