class_name PromptMap
## Tools for mapping input events to PromptFont glyphs.

const COMPOSE_FMT := "{0}+{1}"
const UNKNOWN_INPUT_SYMBOL := PromptFont.ICON_QUESTION

## Keyboard key map
const KEYBOARD := {
	KEY_LEFT: PromptFont.KEYBOARD_LEFT,
	KEY_UP: PromptFont.KEYBOARD_UP,
	KEY_RIGHT: PromptFont.KEYBOARD_RIGHT,
	KEY_DOWN: PromptFont.KEYBOARD_DOWN,
	KEY_CTRL: PromptFont.KEYBOARD_CONTROL,
	KEY_ALT: PromptFont.KEYBOARD_ALT,
	KEY_SHIFT: PromptFont.KEYBOARD_SHIFT,
	KEY_META: PromptFont.KEYBOARD_SUPER,
	KEY_TAB: PromptFont.KEYBOARD_TAB,
	KEY_CAPSLOCK: PromptFont.KEYBOARD_CAPS,
	KEY_BACKSPACE: PromptFont.KEYBOARD_BACKSPACE,
	KEY_ENTER: PromptFont.KEYBOARD_ENTER,
	KEY_KP_ENTER: PromptFont.KEYBOARD_ENTER,
	KEY_ESCAPE: PromptFont.KEYBOARD_ESCAPE,
	KEY_PRINT: PromptFont.KEYBOARD_PRINT_SCREEN,
	KEY_SCROLLLOCK: PromptFont.KEYBOARD_SCROLL_LOCK,
	KEY_PAUSE: PromptFont.KEYBOARD_PAUSE,
	KEY_NUMLOCK: PromptFont.KEYBOARD_NUM_LOCK,
	KEY_INSERT: PromptFont.KEYBOARD_INSERT,
	KEY_HOME: PromptFont.KEYBOARD_HOME,
	KEY_PAGEUP: PromptFont.KEYBOARD_PAGE_UP,
	KEY_DELETE: PromptFont.KEYBOARD_DELETE,
	KEY_END: PromptFont.KEYBOARD_END,
	KEY_PAGEDOWN: PromptFont.KEYBOARD_PAGE_DOWN,
	KEY_SPACE: PromptFont.KEYBOARD_SPACE,
	KEY_F1: PromptFont.KEYBOARD_F1,
	KEY_F2: PromptFont.KEYBOARD_F2,
	KEY_F3: PromptFont.KEYBOARD_F3,
	KEY_F4: PromptFont.KEYBOARD_F4,
	KEY_F5: PromptFont.KEYBOARD_F5,
	KEY_F6: PromptFont.KEYBOARD_F6,
	KEY_F7: PromptFont.KEYBOARD_F7,
	KEY_F8: PromptFont.KEYBOARD_F8,
	KEY_F9: PromptFont.KEYBOARD_F9,
	KEY_F10: PromptFont.KEYBOARD_F10,
	KEY_F11: PromptFont.KEYBOARD_F11,
	KEY_F12: PromptFont.KEYBOARD_F12,
	KEY_0: PromptFont.KEYBOARD_0,
	KEY_1: PromptFont.KEYBOARD_1,
	KEY_2: PromptFont.KEYBOARD_2,
	KEY_3: PromptFont.KEYBOARD_3,
	KEY_4: PromptFont.KEYBOARD_4,
	KEY_5: PromptFont.KEYBOARD_5,
	KEY_6: PromptFont.KEYBOARD_6,
	KEY_7: PromptFont.KEYBOARD_7,
	KEY_8: PromptFont.KEYBOARD_8,
	KEY_9: PromptFont.KEYBOARD_9,
	KEY_KP_0: PromptFont.KEYBOARD_0,
	KEY_KP_1: PromptFont.KEYBOARD_1,
	KEY_KP_2: PromptFont.KEYBOARD_2,
	KEY_KP_3: PromptFont.KEYBOARD_3,
	KEY_KP_4: PromptFont.KEYBOARD_4,
	KEY_KP_5: PromptFont.KEYBOARD_5,
	KEY_KP_6: PromptFont.KEYBOARD_6,
	KEY_KP_7: PromptFont.KEYBOARD_7,
	KEY_KP_8: PromptFont.KEYBOARD_8,
	KEY_KP_9: PromptFont.KEYBOARD_9,
	KEY_A: PromptFont.KEYBOARD_A,
	KEY_B: PromptFont.KEYBOARD_B,
	KEY_C: PromptFont.KEYBOARD_C,
	KEY_D: PromptFont.KEYBOARD_D,
	KEY_E: PromptFont.KEYBOARD_E,
	KEY_F: PromptFont.KEYBOARD_F,
	KEY_G: PromptFont.KEYBOARD_G,
	KEY_H: PromptFont.KEYBOARD_H,
	KEY_I: PromptFont.KEYBOARD_I,
	KEY_J: PromptFont.KEYBOARD_J,
	KEY_K: PromptFont.KEYBOARD_K,
	KEY_L: PromptFont.KEYBOARD_L,
	KEY_M: PromptFont.KEYBOARD_M,
	KEY_N: PromptFont.KEYBOARD_N,
	KEY_O: PromptFont.KEYBOARD_O,
	KEY_P: PromptFont.KEYBOARD_P,
	KEY_Q: PromptFont.KEYBOARD_Q,
	KEY_R: PromptFont.KEYBOARD_R,
	KEY_S: PromptFont.KEYBOARD_S,
	KEY_T: PromptFont.KEYBOARD_T,
	KEY_U: PromptFont.KEYBOARD_U,
	KEY_V: PromptFont.KEYBOARD_V,
	KEY_W: PromptFont.KEYBOARD_W,
	KEY_X: PromptFont.KEYBOARD_X,
	KEY_Y: PromptFont.KEYBOARD_Y,
	KEY_Z: PromptFont.KEYBOARD_Z
}

## Mouse button & scroll map
const MOUSE := {
	MOUSE_BUTTON_LEFT: PromptFont.MOUSE_1,
	MOUSE_BUTTON_RIGHT: PromptFont.MOUSE_2,
	MOUSE_BUTTON_MIDDLE: PromptFont.MOUSE_3,
	MOUSE_BUTTON_WHEEL_LEFT: PromptFont.MOUSE_4,
	MOUSE_BUTTON_WHEEL_RIGHT: PromptFont.MOUSE_5,
	MOUSE_BUTTON_XBUTTON1: PromptFont.MOUSE_6,
	MOUSE_BUTTON_XBUTTON2: PromptFont.MOUSE_7,
	# PromptFont.MOUSE_8,
	MOUSE_BUTTON_WHEEL_UP: PromptFont.MOUSE_SCROLL_UP,
	MOUSE_BUTTON_WHEEL_DOWN: PromptFont.MOUSE_SCROLL_DOWN
	# PromptFont.MOUSE_LEFT,
	# PromptFont.MOUSE_RIGHT,
	# PromptFont.MOUSE_MIDDLE,
	# PromptFont.MOUSE_LEFT_RIGHT,
	# PromptFont.MOUSE_UP_DOWN,
	# PromptFont.MOUSE_ANY
}

## Generic gamepad button map
const GAMEPAD_BUTTON := {
	JOY_BUTTON_X: PromptFont.GAMEPAD_X,
	JOY_BUTTON_Y: PromptFont.GAMEPAD_Y,
	JOY_BUTTON_B: PromptFont.GAMEPAD_B,
	JOY_BUTTON_A: PromptFont.GAMEPAD_A,
	JOY_BUTTON_BACK: PromptFont.GAMEPAD_SELECT,
	JOY_BUTTON_START: PromptFont.GAMEPAD_START,
	JOY_BUTTON_GUIDE: PromptFont.GAMEPAD_HOME,
	JOY_BUTTON_LEFT_STICK: PromptFont.ANALOG_L_CLICK,
	JOY_BUTTON_RIGHT_STICK: PromptFont.ANALOG_R_CLICK,
	JOY_BUTTON_LEFT_SHOULDER: PromptFont.XBOX_LEFT_SHOULDER,
	JOY_BUTTON_RIGHT_SHOULDER: PromptFont.XBOX_RIGHT_SHOULDER,
	JOY_BUTTON_DPAD_UP: PromptFont.DPAD_UP,
	JOY_BUTTON_DPAD_DOWN: PromptFont.DPAD_DOWN,
	JOY_BUTTON_DPAD_LEFT: PromptFont.DPAD_LEFT,
	JOY_BUTTON_DPAD_RIGHT: PromptFont.DPAD_RIGHT,
	JOY_BUTTON_MISC1: PromptFont.XBOX_VIEW,
	# JOY_BUTTON_PADDLE_1:  ## Wtf is this?
	JOY_BUTTON_TOUCHPAD: PromptFont.SONY_TOUCHPAD
}

## Generic gamepad axis map
const GAMEPAD_AXIS := {
	JOY_AXIS_LEFT_X: PromptFont.ANALOG_L_LEFT_RIGHT,
	JOY_AXIS_LEFT_Y: PromptFont.ANALOG_L_UP_DOWN,
	JOY_AXIS_RIGHT_X: PromptFont.ANALOG_R_LEFT_RIGHT,
	JOY_AXIS_RIGHT_Y: PromptFont.ANALOG_R_UP_DOWN,
	JOY_AXIS_TRIGGER_LEFT: PromptFont.XBOX_LEFT_TRIGGER,
	JOY_AXIS_TRIGGER_RIGHT: PromptFont.XBOX_RIGHT_TRIGGER
}

## Xbox gamepad button map
const XBOX_BUTTON := {
	JOY_BUTTON_LEFT_SHOULDER: PromptFont.XBOX_LEFT_SHOULDER,
	JOY_BUTTON_RIGHT_SHOULDER: PromptFont.XBOX_RIGHT_SHOULDER,
	JOY_BUTTON_X: PromptFont.XBOX_X,
	JOY_BUTTON_Y: PromptFont.XBOX_Y,
	JOY_BUTTON_B: PromptFont.XBOX_B,
	JOY_BUTTON_A: PromptFont.XBOX_A,
	JOY_BUTTON_MISC1: PromptFont.XBOX_VIEW,
	JOY_BUTTON_START: PromptFont.XBOX_MENU,
	JOY_BUTTON_DPAD_LEFT: PromptFont.XBOX_DPAD_LEFT,
	JOY_BUTTON_DPAD_UP: PromptFont.XBOX_DPAD_UP,
	JOY_BUTTON_DPAD_RIGHT: PromptFont.XBOX_DPAD_RIGHT,
	JOY_BUTTON_DPAD_DOWN: PromptFont.XBOX_DPAD_DOWN,
	JOY_BUTTON_GUIDE: PromptFont.ICON_XBOX
}

## Xbox gamepad axis map
const XBOX_AXIS := {
	JOY_AXIS_TRIGGER_LEFT: PromptFont.XBOX_LEFT_TRIGGER,
	JOY_AXIS_TRIGGER_RIGHT: PromptFont.XBOX_RIGHT_TRIGGER
}

## Sony gamepad button map
const SONY_BUTTON := {
	JOY_BUTTON_LEFT_SHOULDER: PromptFont.SONY_LEFT_SHOULDER,
	JOY_BUTTON_RIGHT_SHOULDER: PromptFont.SONY_RIGHT_SHOULDER,
	JOY_BUTTON_X: PromptFont.SONY_X,
	JOY_BUTTON_Y: PromptFont.SONY_Y,
	JOY_BUTTON_B: PromptFont.SONY_B,
	JOY_BUTTON_A: PromptFont.SONY_A,
	JOY_BUTTON_MISC1: PromptFont.SONY_SHARE,
	JOY_BUTTON_TOUCHPAD: PromptFont.SONY_TOUCHPAD,
	JOY_BUTTON_START: PromptFont.SONY_OPTIONS,
	JOY_BUTTON_GUIDE: PromptFont.ICON_PLAYSTATION
}

## Sony gamepad axis map
const SONY_AXIS := {
	JOY_AXIS_TRIGGER_LEFT: PromptFont.SONY_LEFT_TRIGGER,
	JOY_AXIS_TRIGGER_RIGHT: PromptFont.SONY_RIGHT_TRIGGER
}

## Nintendo gamepad button map
const NINTENDO_BUTTON := {
	JOY_BUTTON_LEFT_SHOULDER: PromptFont.NINTENDO_LEFT_SHOULDER,
	JOY_BUTTON_RIGHT_SHOULDER: PromptFont.NINTENDO_RIGHT_SHOULDER,
	JOY_BUTTON_BACK: PromptFont.NINTENDO_MINUS,
	JOY_BUTTON_START: PromptFont.NINTENDO_PLUS,
	JOY_BUTTON_DPAD_LEFT: PromptFont.NINTENDO_DPAD_LEFT,
	JOY_BUTTON_DPAD_UP: PromptFont.NINTENDO_DPAD_UP,
	JOY_BUTTON_DPAD_RIGHT: PromptFont.NINTENDO_DPAD_RIGHT,
	JOY_BUTTON_DPAD_DOWN: PromptFont.NINTENDO_DPAD_DOWN
}

## Nintendo gamepad axis map
const NINTENDO_AXIS := {
	JOY_AXIS_TRIGGER_LEFT: PromptFont.NINTENDO_LEFT_TRIGGER,
	JOY_AXIS_TRIGGER_RIGHT: PromptFont.NINTENDO_RIGHT_TRIGGER
}


static func _compose_modifiers(event: InputEventWithModifiers, base: String) -> String:
	# Control -> Alt -> Shift -> Super/Meta
	var composed := base
	if event.meta_pressed:
		composed = COMPOSE_FMT.format([PromptFont.KEYBOARD_SUPER, composed])
	if event.shift_pressed:
		composed = COMPOSE_FMT.format([PromptFont.KEYBOARD_SHIFT, composed])
	if event.alt_pressed:
		composed = COMPOSE_FMT.format([PromptFont.KEYBOARD_ALT, composed])
	if event.ctrl_pressed:
		composed = COMPOSE_FMT.format([PromptFont.KEYBOARD_CONTROL, composed])
	return composed


## Get the symbol representing the given keyboard input event.
##
## If there is no such symbol available, returns the key label.
static func key(event: InputEventKey) -> String:
	if event.physical_keycode not in KEYBOARD:
		return OS.get_keycode_string(
			DisplayServer.keyboard_get_keycode_from_physical(event.physical_keycode)
		)
	@warning_ignore("unsafe_cast")
	return _compose_modifiers(event, KEYBOARD[event.physical_keycode] as String)


## Get the symbol representing the given mouse button event.
static func mouse_button(event: InputEventMouseButton) -> String:
	@warning_ignore("unsafe_cast")
	return _compose_modifiers(event, MOUSE.get(event.button_index, UNKNOWN_INPUT_SYMBOL) as String)


## Get the symbol representing the given gamepad button event.
static func gamepad_button(event: InputEventJoypadButton) -> String:
	return GAMEPAD_BUTTON.get(event.button_index, UNKNOWN_INPUT_SYMBOL)


## Get the symbol representing the given gamepad axis event.
static func gamepad_axis(event: InputEventJoypadMotion) -> String:
	return GAMEPAD_AXIS.get(event.axis, UNKNOWN_INPUT_SYMBOL)


## Get the symbol representing the given gamepad button event.
##
## Symbols specific to Xbox gamepads will be used where possible.
static func xbox_button(event: InputEventJoypadButton) -> String:
	return XBOX_BUTTON.get(event.button_index, gamepad_button(event))


## Get the symbol representing the given gamepad axis event.
##
## Symbols specific to Xbox gamepads will be used where possible.
static func xbox_axis(event: InputEventJoypadMotion) -> String:
	return XBOX_AXIS.get(event.axis, gamepad_axis(event))


## Get the symbol representing the given gamepad button event.
##
## Symbols specific to Playstation Dualshock gamepads will be used where possible.
static func sony_button(event: InputEventJoypadButton) -> String:
	return SONY_BUTTON.get(event.button_index, gamepad_button(event))


## Get the symbol representing the given gamepad axis event.
##
## Symbols specific to Playstation Dualshock gamepads will be used where possible.
static func sony_axis(event: InputEventJoypadMotion) -> String:
	return SONY_AXIS.get(event.axis, gamepad_axis(event))


## Get the symbol representing the given gamepad button event.
##
## Symbols specific to Nintendo Switch joycons will be used where possible.
static func nintendo_button(event: InputEventJoypadButton) -> String:
	return NINTENDO_BUTTON.get(event.button_index, gamepad_button(event))


## Get the symbol representing the given gamepad axis event.
##
## Symbols specific to Nintendo Switch joycons will be used where possible.
static func nintendo_axis(event: InputEventJoypadMotion) -> String:
	return NINTENDO_AXIS.get(event.axis, gamepad_axis(event))


## Get the symbol representing the given event.
static func from_event(event: InputEvent) -> String:
	if event is InputEventKey:
		return key(event as InputEventKey)
	if event is InputEventMouseButton:
		return mouse_button(event as InputEventMouseButton)
	if event is InputEventJoypadButton:
		return gamepad_button(event as InputEventJoypadButton)
	if event is InputEventJoypadMotion:
		return gamepad_axis(event as InputEventJoypadMotion)
	return UNKNOWN_INPUT_SYMBOL
