
/******************************************************************************
*	File		-	InputManager.pp
*	Author		-	Joey Pollack
*	Date		-	2019/11/14 (y/m/d)
*	Mod Date	-	2019/11/25 (y/m/d)
*	Description	-	Handles all input for windows systems
*
******************************************************************************/

#include <window/window.h>
#include "inputManager.h"
#include <graphics/gui/gui.h>
#include <utils/logger.h>
#include <cstring>

namespace lunarium
{
	InputManager::InputManager()
		: mpWindow(nullptr)
	{
		memset(mKeyboardState, 0, 512);
	}

	void InputManager::Initialize(Window* pWindow)
	{
		mpWindow = pWindow;
	}

	void InputManager::Shutdown()
	{
		mpWindow = nullptr;
	}

	const InputManager::_KeyEvents& InputManager::PollKeys()
	{
		if (!mpWindow)
		{
			Logger::Log(LogCategory::CORE, LogLevel::WARNING, "InputManager::PollKeys called but InputManager is not initialized!");
			return mKeyEvents;
		}

		mKeyEvents.KeysPressed.clear();
		mKeyEvents.KeysReleased.clear();

		// Check Modifiers first so we only have to do it once
		// bool shiftHeld = GetAsyncKeyState(VK_SHIFT);
		// bool controlHeld = GetAsyncKeyState(VK_CONTROL);
		// bool altHeld = GetAsyncKeyState(VK_MENU);
		bool shiftHeld = mpWindow->IsKeyDown(KeyCode::SHIFT);
		bool controlHeld = mpWindow->IsKeyDown(KeyCode::CONTROL);
		bool altHeld = mpWindow->IsKeyDown(KeyCode::ALT);
		

		for (int i = 0; i < KeyCodeList.size(); i++)
		{
			Keyboard::Key key = Keyboard::GetInstance()->GetKey((KeyCode)KeyCodeList[i]);
			bool keyIsDown = mpWindow->IsKeyDown(KeyCodeList[i]);

			// Mouse Buttons are a special case
			if (IsMouseButton(KeyCodeList[i]))
			{
				if (keyIsDown)
				{
					mKeyboardState[KeyCodeList[i]] = KEY_DOWN;
				}
				else
				{
					mKeyboardState[KeyCodeList[i]] = KEY_UP;
				}

				continue;
			}

			// Key is a known keyboard key
			if (keyIsDown)
			{
				// Ignore key presses for unknown keys
				if (KeyCode::KEY_UNKNOWN == key.Code)
				{
					Logger::Log(LogCategory::CORE, LogLevel::INFO_VERBOSE, 
									"Input Manager skipping unknown key press: idx: %d, code: %d", i, KeyCodeList[i]);
					continue;
				}

				// Key was just pressed this frame
				if (KEY_UP == mKeyboardState[KeyCodeList[i]])
				{
					//Logger::Log(LogCategory::CORE, LogLevel::INFO, "Key Down: %d, %s", KeyCodeList[i], key.Name.c_str());
					mKeyboardState[KeyCodeList[i]] = KEY_DOWN;

					KeyPress kp;
					kp.Key = key;
					kp.ShiftHeld = shiftHeld;
					kp.ControlHeld = controlHeld;
					kp.AltHeld = altHeld;

					mKeyEvents.KeysPressed.push_back(kp);
				}
			}
			else
			{
				// Key was just released this frame
				if (KEY_DOWN == mKeyboardState[KeyCodeList[i]])
				{
					mKeyboardState[KeyCodeList[i]] = KEY_UP;
					mKeyEvents.KeysReleased.push_back(key);
				}
			}
		}
		
		return mKeyEvents;
	}

	bool InputManager::IsMouseButton(int keyCode)
	{
		return (keyCode == KeyCode::MOUSE_LEFT_BUTTON ||
			keyCode == KeyCode::MOUSE_RIGHT_BUTTON ||
			keyCode == KeyCode::MOUSE_MIDDLE_BUTTON ||
			keyCode == KeyCode::MOUSE_X1_BUTTON ||
			keyCode == KeyCode::MOUSE_X2_BUTTON );
	}

	bool InputManager::IsKeyDown(KeyCode key, bool ignoreWantCapture)
	{
		if (GUI::GetInstance().WantCaptureKeyboard() && !ignoreWantCapture)
			return false;

		return (mKeyboardState[key] == KEY_DOWN);
	}

	bool InputManager::IsKeyPressed(KeyCode key, bool ignoreWantCapture)
	{
		if (GUI::GetInstance().WantCaptureKeyboard() && !ignoreWantCapture)
			return false;
			
		for (int i = 0; i < mKeyEvents.KeysPressed.size(); i++)
		{
			if (mKeyEvents.KeysPressed[i].Key.Code == key)
			{
				return true;
			}
		}

		return false;
	}

	glm::vec2 InputManager::GetMousePosition()
	{
		// POINT p;
		// memset(&p, 0, sizeof(POINT));
		// GetCursorPos(&p);

		// return { (float)p.x, (float)p.y };
		return mpWindow->GetCursorPos();
	}

	void InputManager::SetMousePosition(glm::vec2 p)
	{
		//SetCursorPos((int)p.X, (int)p.Y);
		mpWindow->SetCursorPos(p);
	}
	///////////////////////////////////////////////////
}