#include "Input.hpp"
#include "GLFW/glfw3.h"

namespace Input
{
	extern GLFWwindow* g_GlfwWindowPtr = nullptr;
	extern float MousWheelPos = 0;
	extern float OldMouseWheelPos = 0;

	namespace intern
	{
		std::array<bool, 8> last_mouse_state;
		std::array<bool, 348> last_key_state;

		double last_cursor_x, last_cursor_y;
		double rel_cursor_x, rel_cursor_y;
	}

	bool GetKeyState(int Key)
	{
		return static_cast<bool>(glfwGetKey(g_GlfwWindowPtr, Key));
	}

	bool GetKeyClicked(int Key)
	{
		return !intern::last_key_state[Key] && static_cast<bool>(glfwGetKey(g_GlfwWindowPtr, Key));
	}


	void GetCursorPos(double* x, double* y)
	{
		glfwGetCursorPos(g_GlfwWindowPtr, x, y);
	}

	void GetCursorRel(double* x, double* y)
	{
		*x = intern::rel_cursor_x;
		*y = intern::rel_cursor_y;
	}

	bool GetMouseButtonState(int Button)
	{
		return static_cast<bool>(glfwGetMouseButton(g_GlfwWindowPtr, Button));
	}

	bool GetMouseButtonClicked(int Button)
	{
		// TODO: should we check Button value? I think not, since in practice we will always use enums, so it is safe.
		return !intern::last_mouse_state[Button] && static_cast<bool>(glfwGetMouseButton(g_GlfwWindowPtr, Button));
	}

	void ScrollCallback(GLFWwindow* window, double xOffset, double yOffset)
	{
		MousWheelPos += static_cast<float>(yOffset);
	}

	void Init(GLFWwindow* window)
	{
		g_GlfwWindowPtr = window;
		glfwSetScrollCallback(window, ScrollCallback);
	}

	void Update()
	{
		for(auto i = 0u; i<intern::last_mouse_state.size(); ++i)
		{
			intern::last_mouse_state[i] = GetMouseButtonState(i);
		}
		for(auto i = 0u; i<intern::last_key_state.size(); ++i)
		{
			intern::last_key_state[i] = GetKeyState(i);
		}
		OldMouseWheelPos = MousWheelPos;

		double x, y;
		Input::GetCursorPos(&x, &y);
		intern::rel_cursor_x = x - intern::last_cursor_x;
		intern::rel_cursor_y = y - intern::last_cursor_y;
		intern::last_cursor_x = x;
		intern::last_cursor_y = y;

		glfwPollEvents();
	}

}