
/******************************************************************************
*	File		-	Keyboard.cpp
*	Author		-	Joey Pollack
*	Date		-	2019/11/15 (y/m/d)
*	Mod Date	-	2019/11/15 (y/m/d)
*	Description	-	Stores data about the keys on the keyboard
*
******************************************************************************/

#include "keyboard.h"

namespace lunarium
{
	Keyboard* Keyboard::mpInstance = nullptr;

	void Keyboard::Shutdown()
	{
		if (mpInstance)
		{
			delete mpInstance;
			mpInstance = nullptr;
		}
	}

	Keyboard * Keyboard::GetInstance()
	{
		if (!mpInstance)
		{
			mpInstance = new Keyboard;
			mpInstance->Initialize();
		}

		return mpInstance;
	}

	Keyboard::Keyboard()
	{

	}

	void Keyboard::Initialize()
	{
		// Add letters
		for (char letter = 'A'; letter <= 'Z'; letter++)
		{
			Key k;
			k.Code = (KeyCode)letter;
			k.Name = std::string() + letter;
			k.ShiftName = std::string() + (char)(letter + 32);
			k.AsciiValue = letter;
			k.ShiftAsciiValue = letter + 32;

			mKeyboard.insert(std::pair<KeyCode, Key>(k.Code, k));
		}

		// Add Numbers
		char numShift[10] = { ')', '!', '@', '#', '$', '%', '^', '&', '*', '(' };
		for (int i = 0; i <= 9; i++)
		{
			Key k;
			k.Code = (KeyCode)(i + 48);

			char name[2];
			sprintf(name, "%d", i);

			k.Name = std::string(name);
			k.ShiftName = std::string() + numShift[i];
			k.AsciiValue = (char)(i + 48);
			k.ShiftAsciiValue = numShift[i];

			mKeyboard.insert(std::pair<KeyCode, Key>(k.Code, k));
		}

		// Punctuation
		/*
		SEMICOLON = GLFW_KEY_SEMICOLON,			// ';:' for US
		EQUALS = GLFW_KEY_EQUAL,				// '+' any country
		COMMA = GLFW_KEY_COMMA,					// ',' any country
		DASH = GLFW_KEY_MINUS,					// '-' any country
		DOT = GLFW_KEY_PERIOD,					// '.' any country
		FORWARD_SLASH = GLFW_KEY_SLASH,   		// '/?' for US
		TILDE = GLFW_KEY_GRAVE_ACCENT,			// '`~' for US

		OPEN_BRACKET = GLFW_KEY_LEFT_BRACKET,	//  '[{' for US
		BACKSLASH = GLFW_KEY_BACKSLASH,			//  '\|' for US
		CLOSE_BRACKET = GLFW_KEY_RIGHT_BRACKET,	//  ']}' for US
		QUOTE = GLFW_KEY_APOSTROPHE,			//  ''"' for US
		*/	
		mKeyboard.insert(std::pair<KeyCode, Key>(SEMICOLON, { SEMICOLON, "semi colon", "colon", ';', ';' }));
		mKeyboard.insert(std::pair<KeyCode, Key>(EQUALS, { EQUALS, "equals", "plus", '=', '+' }));
		mKeyboard.insert(std::pair<KeyCode, Key>(COMMA, { COMMA, "comma", "less than", ',', '<' }));
		mKeyboard.insert(std::pair<KeyCode, Key>(DASH, { DASH, "dash", "underscore", '-', '_' }));
		mKeyboard.insert(std::pair<KeyCode, Key>(DOT, { DOT, "dot", "greater than", '.', '>' }));
		mKeyboard.insert(std::pair<KeyCode, Key>(FORWARD_SLASH, { FORWARD_SLASH, "forward slash", "question mark", '/', '?' }));
		mKeyboard.insert(std::pair<KeyCode, Key>(TILDE, { TILDE, "tick", "tilde", '`', '~' }));
		mKeyboard.insert(std::pair<KeyCode, Key>(OPEN_BRACKET, { OPEN_BRACKET, "open square bracket", "open curly brace", '[', '{' }));
		mKeyboard.insert(std::pair<KeyCode, Key>(BACKSLASH, { BACKSLASH, "back slash", "pipe", '\\', '|' }));
		mKeyboard.insert(std::pair<KeyCode, Key>(CLOSE_BRACKET, { CLOSE_BRACKET, "close square bracket", "close curly brace", ']', '}' }));
		mKeyboard.insert(std::pair<KeyCode, Key>(QUOTE, { QUOTE, "single quote", "double quote", '\'', '\"' }));


		// Modifiers
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::LSHIFT, { KeyCode::LSHIFT, "left shift", "left shift", (char)0, (char)0 }));
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::RSHIFT, { KeyCode::RSHIFT, "right shift", "right shift", (char)0, (char)0 }));

		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::LCONTROL, { KeyCode::LCONTROL, "left control", "left control", (char)0, (char)0 }));
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::RCONTROL, { KeyCode::RCONTROL, "right control", "right control", (char)0, (char)0 }));

		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::LALT, { KeyCode::LALT, "left alt", "left alt", (char)0, (char)0 }));
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::RALT, { KeyCode::RALT, "right alt", "right alt", (char)0, (char)0 }));


		// Control characters
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::DEL, { KeyCode::DEL, "delete", "delete", (char)(127), (char)(127) }));
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::BACKSPACE, { KeyCode::BACKSPACE, "backspace", "backspace", (char)(8), (char)(8) }));
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::TAB, { KeyCode::TAB, "tab", "tab", (char)(9), (char)(9) }));
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::RETURN, { KeyCode::RETURN, "return", "return", (char)(10), (char)(10) }));
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::ESCAPE, { KeyCode::ESCAPE, "escape", "escape", (char)(27), (char)(27) }));
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::SPACE, { KeyCode::SPACE, "space", "space", (char)(32), (char)(32) }));
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::PAGE_UP, { KeyCode::PAGE_UP, "page up", "page up", (char)(0), (char)(0) }));
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::PAGE_DOWN, { KeyCode::PAGE_DOWN, "page down", "page down", (char)(0), (char)(0) }));

		// Arrow Keys
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::LEFT, { KeyCode::LEFT, "Left Arrow", "Left Arrow", (char)(0), (char)(0) }));
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::UP, { KeyCode::UP, "Up Arrow", "Up Arrow", (char)(0), (char)(0) }));
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::RIGHT, { KeyCode::RIGHT, "Right Arrow", "Right Arrow", (char)(0), (char)(0) }));
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::DOWN, { KeyCode::DOWN, "Down Arrow", "Down Arrow", (char)(0), (char)(0) }));

		// F Keys
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::F1, { KeyCode::F1, "F1", "F1", (char)(0), (char)(0) }));
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::F2, { KeyCode::F2, "F2", "F2", (char)(0), (char)(0) }));
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::F3, { KeyCode::F3, "F3", "F3", (char)(0), (char)(0) }));
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::F4, { KeyCode::F4, "F4", "F4", (char)(0), (char)(0) }));
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::F5, { KeyCode::F5, "F5", "F5", (char)(0), (char)(0) }));
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::F6, { KeyCode::F6, "F6", "F6", (char)(0), (char)(0) }));
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::F7, { KeyCode::F7, "F7", "F7", (char)(0), (char)(0) }));
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::F8, { KeyCode::F8, "F8", "F8", (char)(0), (char)(0) }));
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::F9, { KeyCode::F9, "F9", "F9", (char)(0), (char)(0) }));
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::F10, { KeyCode::F10, "F10", "F10", (char)(0), (char)(0) }));
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::F11, { KeyCode::F11, "F11", "F11", (char)(0), (char)(0) }));
		mKeyboard.insert(std::pair<KeyCode, Key>(KeyCode::F12, { KeyCode::F12, "F12", "F12", (char)(0), (char)(0) }));


		// Set up the cross references
		InitKeysByName();
		InitKeysByAscii();
	}


	Keyboard::Key Keyboard::GetKey(KeyCode code)
	{
		auto iter = mKeyboard.find(code);
		if (mKeyboard.end() == iter)
			return Key::Unknown();

		return (*iter).second;
	}

	Keyboard::Key Keyboard::GetKey(std::string name)
	{
		auto iter = mKeysByName.find(name);
		if (mKeysByName.end() == iter)
			return Key::Unknown();

		return (*iter).second;
	}

	Keyboard::Key Keyboard::GetKey(char ascii)
	{
		auto iter = mKeysByAscii.find(ascii);
		if (mKeysByAscii.end() == iter)
			return Key::Unknown();

		return (*iter).second;
	}

	void Keyboard::InitKeysByName()
	{
		for (auto iter = mKeyboard.begin(); iter != mKeyboard.end(); iter++)
		{
			mKeysByName.insert(std::pair<std::string, Key&>((*iter).second.Name, (*iter).second));
		}
	}

	void Keyboard::InitKeysByAscii()
	{
		for (auto iter = mKeyboard.begin(); iter != mKeyboard.end(); iter++)
		{
			mKeysByAscii.insert(std::pair<char, Key&>((*iter).second.AsciiValue, (*iter).second));
			mKeysByAscii.insert(std::pair<char, Key&>((*iter).second.ShiftAsciiValue, (*iter).second));
		}
	}

	Keyboard::Key Keyboard::Key::Unknown()
	{
		Key k;
		k.Code = KeyCode::KEY_UNKNOWN;
		k.Name = "unknown";
		k.ShiftName = "unknown";
		k.AsciiValue = (char)0;
		k.ShiftAsciiValue = (char)0;

		return k;
	}
}