#include <assert.h>
#include <memory.h>
#include "utils/logger.h"
#include "utils/maths.h"
#include "input/input_system.h"

const int kMaxKeyboardKeys = 460;
const int kMaxMouseButtons = mouseButton_LastNamed + 1; //5;
const float kKeyThreshold = 0.2f;

IInputSystem* g_inputSystem = nullptr;

class InputSystem : public IInputSystem
{
public:
	InputSystem();
	~InputSystem();

	void Init();
	void Shutdown();
	void Update();

	size_t GetMaxScancode() const;
	size_t GetMaxMouseButton() const;

	char   TranslateScancode(scanCode_t scancode) const;

	void OnKeyDown(scanCode_t scancode);
	void OnKeyUp(scanCode_t scancode);
	void OnMouseKeyDown(mouseButton_t mousebutton);
	void OnMouseKeyUp(mouseButton_t mousebutton);
	void OnMouseMove(int32_t x, int32_t y);
	void OnMouseWheel(int32_t x, int32_t y);

	bool IsKeyPressed(scanCode_t scancode) const;
	bool IsMouseButtonPressed(mouseButton_t mousebutton) const;

	void GetMousePosition(int32_t* x, int32_t* y) const;
	void GetMouseWheelPosition(int32_t* x, int32_t* y) const;

	const char* ActionToString(Action action) const;
	void		BindKey(Action action, scanCode_t scancode);
	bool		IsActionActive(Action action) const;
	void		UnBindKey(Action action);
	void		UnBindAll();

private:
	bool m_keyboardKeys[kMaxKeyboardKeys];
	bool m_mouseButtons[kMaxMouseButtons];
	Point2 m_mousePosition;
};

InputSystem::InputSystem()
{
	memset( m_keyboardKeys, 0, sizeof( m_keyboardKeys ) );
	memset( m_mouseButtons, 0, sizeof( m_mouseButtons ) );
	memset( &m_mousePosition, 0, sizeof( m_mousePosition ) );
}

InputSystem::~InputSystem()
{
}

void InputSystem::Init()
{
	// Nothing to do
}

void InputSystem::Shutdown()
{
	// Nothing to do
}

void InputSystem::Update()
{
	// TODO: Reset all pressed keys ...
}

size_t InputSystem::GetMaxScancode() const
{
	return kMaxKeyboardKeys;
}

size_t InputSystem::GetMaxMouseButton() const
{
	return kMaxMouseButtons;
}

char InputSystem::TranslateScancode(scanCode_t scancode) const
{
	assert(0 && "Not implemented");
	return 0;
}

void InputSystem::OnKeyDown(scanCode_t scancode)
{
	assert(scancode <= kMaxKeyboardKeys);
	m_keyboardKeys[scancode] = true;
}

void InputSystem::OnKeyUp(scanCode_t scancode)
{
	assert(scancode <= kMaxKeyboardKeys);
	m_keyboardKeys[scancode] = false;
}

void InputSystem::OnMouseKeyDown(mouseButton_t mousebutton)
{
	assert(mousebutton <= kMaxMouseButtons);
	m_mouseButtons[mousebutton] = true;
}

void InputSystem::OnMouseKeyUp(mouseButton_t mousebutton)
{
	assert(mousebutton <= kMaxMouseButtons);
	m_mouseButtons[mousebutton] = false;
}

void InputSystem::OnMouseMove(int32_t x, int32_t y)
{
	m_mousePosition.x = (int)x;
	m_mousePosition.y = (int)y;
}

void InputSystem::OnMouseWheel(int32_t x, int32_t y)
{
}

bool InputSystem::IsKeyPressed(scanCode_t scancode) const
{
	assert(scancode <= KEY_MAX);
	return m_keyboardKeys[scancode];
}

bool InputSystem::IsMouseButtonPressed(mouseButton_t mousebutton) const
{
	assert(mousebutton <= kMaxMouseButtons);
	return m_mouseButtons[mousebutton];
}

void InputSystem::GetMousePosition(int32_t* x, int32_t* y) const
{
	if (x) *x = (int32_t)m_mousePosition.x;
	if (y) *y = (int32_t)m_mousePosition.y;
}

void InputSystem::GetMouseWheelPosition(int32_t* x, int32_t* y) const
{
}

const char* InputSystem::ActionToString(Action action) const
{
	return nullptr;
}

void InputSystem::BindKey(Action action, scanCode_t scancode)
{
}

bool InputSystem::IsActionActive(Action action) const
{
	return false;
}

void InputSystem::UnBindKey(Action action)
{
}

void InputSystem::UnBindAll()
{
}

IInputSystem* CreateInputSystem(void* wndHandle)
{
	return new InputSystem();
}

void DestroyInputSystem(IInputSystem* pInstance)
{
	InputSystem* pInput = (InputSystem*)pInstance;
	delete pInput;
}
