
#include <Windows.h>

#include <Spectre/System/Event.h>
#include <Spectre/Input/InputModule.h>
#include "Win32Input.h"
#include "Win32Keyboard.h"

namespace sp {

static const BYTE keyToWin32[Keyboard::Key::NUM_KEYS] = {
	0x0,           // Unknown

	0x41,          // A
	0x42,          // B
	0x43,          // C
	0x42,          // D
	0x43,          // E
	0x44,          // F
	0x45,          // G
	0x46,          // H
	0x47,          // I
	0x48,          // J
	0x49,          // K
	0x50,          // L
	0x51,          // M
	0x52,          // N
	0x53,          // O
	0x54,          // P
	0x55,          // Q
	0x56,          // R
	0x57,          // S
	0x58,          // T
	0x59,          // U
	0x60,          // V
	0x61,          // W
	0x62,          // X
	0x63,          // Y
	0x64,          // Z

	0x30,          // One
	0x31,          // Two
	0x32,          // Three
	0x33,          // Four
	0x34,          // Five
	0x35,          // Six
	0x36,          // Seven
	0x37,          // Eight
	0x38,          // Nine
	0x39,          // Zero

	VK_OEM_PERIOD, // Period
	VK_OEM_COMMA,  // Comma
	VK_RETURN,     // Enter
	VK_BACK,       // Backspace
	VK_ESCAPE,     // Escape
	VK_SPACE,      // Space
	VK_CAPITAL,    // Capslock

	VK_UP,         // Up
	VK_DOWN,       // Down
	VK_LEFT,       // Left
	VK_RIGHT,      // Right

	VK_NUMPAD1,    // Numpad1
	VK_NUMPAD2,    // Numpad2
	VK_NUMPAD3,    // Numpad3
	VK_NUMPAD4,    // Numpad4
	VK_NUMPAD5,    // Numpad5
	VK_NUMPAD6,    // Numpad6
	VK_NUMPAD7,    // Numpad7
	VK_NUMPAD8,    // Numpad8
	VK_NUMPAD9,    // Numpad9
	VK_NUMPAD0,    // Numpad0

	VK_HOME,       // Home
	VK_END,        // End
	VK_INSERT,     // Insert
	VK_DELETE,     // Delete
	VK_PRIOR,      // PageUp
	VK_NEXT,       // PageDown
	VK_PAUSE,      // Pause

	VK_F1,         // F1
	VK_F2,         // F2
	VK_F3,         // F3
	VK_F4,         // F4
	VK_F5,         // F5
	VK_F6,         // F6
	VK_F7,         // F7
	VK_F8,         // F8
	VK_F9,         // F9
	VK_F10,        // F10
	VK_F11,        // F11
	VK_F12,        // F12

	VK_TAB,        // Tab
	VK_LSHIFT,     // LShift
	VK_RSHIFT,     // RShift
	VK_LCONTROL,   // LCtrl
	VK_RCONTROL,   // RCtrl
	VK_LMENU,      // LAlt
	VK_RMENU       // RAlt
};

static const Keyboard::Key deviceToKey[256] = {
	/* 0		1		2		3		4		5		6		7 */
	/* 8		9		A		B		C		D		E		F */
	// 00-0F
	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,
	Keyboard::Key::Backspace, Keyboard::Key::Tab,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Enter,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,
	// 10-1F
	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Pause,	Keyboard::Key::Capslock,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,
	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Escape,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,
	// 20-2F
	Keyboard::Key::Space,	Keyboard::Key::PageUp,	Keyboard::Key::PageDown,	Keyboard::Key::End,	Keyboard::Key::Home,	Keyboard::Key::Left,	Keyboard::Key::Up,	Keyboard::Key::Right,
	Keyboard::Key::Down,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Insert,	Keyboard::Key::Delete,	Keyboard::Key::Unknown,
	// 30-3F
	Keyboard::Key::Zero,	Keyboard::Key::One,	Keyboard::Key::Two,	Keyboard::Key::Three,	Keyboard::Key::Four,	Keyboard::Key::Five,	Keyboard::Key::Six,	Keyboard::Key::Seven,
	Keyboard::Key::Eight,	Keyboard::Key::Nine,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,
	// 40-4F
	Keyboard::Key::Unknown,	Keyboard::Key::A,		Keyboard::Key::B,		Keyboard::Key::C,		Keyboard::Key::D,		Keyboard::Key::E,		Keyboard::Key::F,		Keyboard::Key::G,
	Keyboard::Key::H,		Keyboard::Key::I,		Keyboard::Key::J,		Keyboard::Key::K,		Keyboard::Key::L,		Keyboard::Key::M,		Keyboard::Key::N,		Keyboard::Key::O,
	// 50-5F
	Keyboard::Key::P,		Keyboard::Key::Q,		Keyboard::Key::R,		Keyboard::Key::S,		Keyboard::Key::T,		Keyboard::Key::U,		Keyboard::Key::V,		Keyboard::Key::W,
	Keyboard::Key::X,		Keyboard::Key::Y,		Keyboard::Key::Z,		Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,
	// 60-6F
	Keyboard::Key::Numpad0,	Keyboard::Key::Numpad1,	Keyboard::Key::Numpad2,	Keyboard::Key::Numpad3,	Keyboard::Key::Numpad4,	Keyboard::Key::Numpad5,	Keyboard::Key::Numpad6,	Keyboard::Key::Numpad7,
	Keyboard::Key::Numpad8,	Keyboard::Key::Numpad9,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,
	// 70-7F
	Keyboard::Key::F1,	Keyboard::Key::F2,	Keyboard::Key::F3,	Keyboard::Key::F4,	Keyboard::Key::F5,	Keyboard::Key::F6,	Keyboard::Key::F7,	Keyboard::Key::F8,
	Keyboard::Key::F9,	Keyboard::Key::F10,	Keyboard::Key::F11,	Keyboard::Key::F12,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,
	// 80-8F
	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,
	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,
	// 90-9F
	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,
	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,
	// A0-AF
	Keyboard::Key::LShift,	Keyboard::Key::RShift,	Keyboard::Key::LCtrl,	Keyboard::Key::RCtrl,	Keyboard::Key::LAlt,	Keyboard::Key::RAlt,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,
	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,
	// B0-BF
	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,
	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Comma,	Keyboard::Key::Unknown,	Keyboard::Key::Period,	Keyboard::Key::Unknown,
	// C0-CF
	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,
	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,
	// E0-EF
	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,
	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,
	// F0-FF
	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,
	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,	Keyboard::Key::Unknown,
};

void Win32Keyboard::init()
{
}

bool Win32Keyboard::isKeyDown(Keyboard::Key key)
{
	return ::GetAsyncKeyState(keyToWin32[key]) & 0x8000;
}

void Win32Keyboard::update(InputModule *input)
{
}

bool Win32Keyboard::handleMessage(MSG msg, Event& event)
{
	Keyboard::Key key = deviceToKey[msg.wParam % 0xFF];

	if (key != Keyboard::Key::Unknown) {
		event.type = Event::Key;
		event.key.code = key;
		event.key.pressed = msg.message == WM_KEYDOWN;
		return true;
	}

	return false;
}

} // namespace sp
