
#include <Windows.h>
#include <Spectre/System/Log.h>
#include <Spectre/Input/InputModule.h>
#include "Win32MsgBuffer.h"
#include "Win32Input.h"
#include "Win32Mouse.h"

static Win32MsgBuffer msg_buf;

static Vector2f _normalizePos(int x, int y, RECT area) 
{
	Vector2f out;

	out.x = x / ((float) (area.right - area.left));
	out.y = y / ((float) (area.bottom - area.top));

	return out;
}

static RECT GetClientArea(HWND hwnd) {

	RECT rect;
	GetClientRect(hwnd, &rect);
	return rect;
}

void Win32Mouse::init()
{
	memset(m_state, 0, MouseButton::NUM_MBUTTONS);
	m_tracked = false;
}

Vector2f Win32Mouse::getPosition() const
{
	return m_position;
}

bool Win32Mouse::isButtonDown(MouseButton::Type button) const
{
	return m_state[button];
}

void Win32Mouse::update(InputModule *input)
{
	// TODO: Clean this.
	for(int i = 0; i < msg_buf.index; i++) {

		MSG msg = msg_buf.messages[i];

		if (msg.message == WM_LBUTTONDOWN || msg.message == WM_LBUTTONUP) {
			InputEvent event(InputEvent::MouseButton);

			event.mouseButton.button = MouseButton::Left;
			event.mouseButton.pressed = msg.message == WM_LBUTTONDOWN;

			m_state[MouseButton::Left] = event.mouseButton.pressed;
			input->postInputEvent(event);
		} else if (msg.message == WM_RBUTTONDOWN || msg.message == WM_RBUTTONUP) {
			InputEvent event(InputEvent::MouseButton);

			event.mouseButton.button = MouseButton::Right;
			event.mouseButton.pressed = msg.message == WM_RBUTTONDOWN;

			m_state[MouseButton::Right] = event.mouseButton.pressed;
			input->postInputEvent(event);
		} else if (msg.message == WM_MBUTTONDOWN || msg.message == WM_MBUTTONUP) {
			InputEvent event(InputEvent::MouseButton);

			event.mouseButton.button = MouseButton::Middle;
			event.mouseButton.pressed = msg.message == WM_MBUTTONDOWN;

			m_state[MouseButton::Middle] = event.mouseButton.pressed;
			input->postInputEvent(event);

		} else if (msg.message == WM_XBUTTONDOWN || msg.message == WM_XBUTTONUP) { 
		
			int btn = GET_XBUTTON_WPARAM(msg.wParam);
			InputEvent event(InputEvent::MouseButton);

			event.mouseButton.button = btn == XBUTTON1 ? MouseButton::Button1 : MouseButton::Button2;
			event.mouseButton.pressed = msg.message == WM_XBUTTONDOWN;

			m_state[MouseButton::Button1] = event.mouseButton.pressed;
			input->postInputEvent(event);

		} else if (msg.message == WM_MOUSEMOVE) {

			InputEvent event(InputEvent::MousePosition);
			RECT area = GetClientArea(msg.hwnd);
			
			int x = LOWORD(msg.lParam);
			int y = HIWORD(msg.lParam);

			// Do not forward the message if mouse is outside client area.
			if ((x < area.left) || (x > area.right) || (y < area.top) || (y > area.bottom)) {
				continue;
			}

			event.mouse.x = x;
			event.mouse.y = y;

			input->postInputEvent(event);

			m_position = _normalizePos(x, y, area);
		}
	}

	msg_buf.index = 0;
}

bool Win32Mouse::handleMessage(MSG message)
{
	return msg_buf.postMessage(message);
}