# The keys, listed and rebindable. Every command the game answers to is on this
# sheet — which is the point: a shortcut nobody can find is a shortcut nobody has.
#
# Click a key (or reach it with Tab and press Enter) and the button waits for the
# next press. Take a key another action already holds and the two swap, so no
# action is ever left with nothing to press. Escape gets out of the wait, and out
# of the panel.
extends Control

signal closed()

# The list scrolls, and the scroll follows the focus (see the scene): twelve rows
# do not fit a 720-high screen, and a row you can Tab to but not see is a row you
# cannot rebind.
const ROW_HEIGHT := 30

var _rows := {}
# Which action is listening for a key, or "" — the panel is a modal within a
# modal while this is set, and everything else on it stops answering.
var _capturing := ""
var _capturing_button: Button

func _ready() -> void:
	%BackButton.pressed.connect(_close)
	%ResetButton.pressed.connect(_reset)
	_build_rows()
	# The focus lands inside the panel the moment it opens, on the way out of it.
	%BackButton.grab_focus.call_deferred()

# What each command is called on this sheet. Written out as tr() literals rather
# than looked up from a table: /extract-translations reads literals, and a name
# it cannot see is a name that ships in English in every other language.
func row_name(action: String) -> String:
	match action:
		"move_up": return tr("Walk forward")
		"move_down": return tr("Walk back")
		"move_left": return tr("Walk left")
		"move_right": return tr("Walk right")
		"interact": return tr("Take a closer look")
		"judge_original": return tr("Call it original")
		"judge_fake": return tr("Call it fake")
		"look_up": return tr("Look the piece up")
		"overview": return tr("See the whole museum")
		"clipboard": return tr("Clipboard")
		"mute": return tr("Mute")
	return action

func _build_rows() -> void:
	for action: String in Settings.BINDINGS:
		var row := HBoxContainer.new()
		row.custom_minimum_size.y = ROW_HEIGHT
		%Rows.add_child(row)

		var label := Label.new()
		label.text = row_name(action)
		label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
		label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
		row.add_child(label)

		var button := Button.new()
		button.custom_minimum_size.x = 140
		button.text = Settings.key_name(action)
		button.pressed.connect(_start_capture.bind(action, button))
		row.add_child(button)
		_rows[action] = button

func _refresh() -> void:
	for action: String in _rows:
		_rows[action].text = Settings.key_name(action)

func _start_capture(action: String, button: Button) -> void:
	if not _capturing.is_empty():
		return
	_capturing = action
	_capturing_button = button
	button.text = tr("press a key…")
	%Notice.text = tr("Escape cancels. A key another action holds swaps with it.")

func _stop_capture() -> void:
	_capturing = ""
	_capturing_button = null
	%Notice.text = ""
	_refresh()

# The capture reads the key by its label — what is printed on the key in front of
# the player — rather than by its position, so an AZERTY player who binds A gets
# the A they pressed. Handled here rather than in _gui_input because the panel
# must hear the press wherever the focus happens to sit.
func _input(event: InputEvent) -> void:
	if not visible:
		return
	if _capturing.is_empty():
		if event.is_action_pressed("cancel"):
			_close()
			get_viewport().set_input_as_handled()
		return
	if not (event is InputEventKey) or not event.is_pressed() or (event as InputEventKey).is_echo():
		return
	get_viewport().set_input_as_handled()
	var key := event as InputEventKey
	if key.keycode == KEY_ESCAPE:
		_stop_capture()
		return
	# key_label is what the key is engraved with when the layout has an opinion
	# (the é of an AZERTY row); keycode is that same letter for the plain ones.
	var wanted: int = key.key_label if key.key_label != KEY_NONE else key.keycode
	if not Settings.rebind(_capturing, wanted):
		%Notice.text = tr("That key belongs to the browser or the window.")
		_capturing_button.text = Settings.key_name(_capturing)
		_capturing = ""
		_capturing_button = null
		return
	_stop_capture()

func _reset() -> void:
	Settings.reset_keybinds()
	_refresh()

func _close() -> void:
	if not _capturing.is_empty():
		_stop_capture()
		return
	closed.emit()
