#pragma once

struct KeyboardEvent
{
	enum EType
	{
		KBD_KEY_DOWN,
		KBD_KEY_PRESSED,
		KBD_KEY_UP,
		KBD_KEY_REPEAT,
	};

	  // My own event type, because Allegro lacks some useful events
	EType m_type;
	  // Allegro key code
	int m_keycode;
	  // The following two fields are only valid is SOME events
	int m_flags;
	int m_unichar;
};

struct MouseEvent
{
	enum EType
	{
		MOUSE_POS,
		MOUSE_MOVE,
		MOUSE_B1_DOWN,
		MOUSE_B1_PRESSED,
		MOUSE_B1_UP,
		MOUSE_B2_DOWN,
		MOUSE_B2_PRESSED,
		MOUSE_B2_UP,
		MOUSE_B3_DOWN,
		MOUSE_B3_PRESSED,
		MOUSE_B3_UP,
		MOUSE_B1_DOUBLECLICK,
		MOUSE_WHEEL,
	};

	EType m_type;
	int m_x, m_y;
	int m_deltaWheel;
};

struct GamepadEvent
{
	enum EType
	{
		GP_AXIS,
		GP_BUTTON,
	};
	EType m_type;
	int m_buttons;
};

struct InputEvent
{
	enum EType
	{
		EV_INVALID,
		EV_KEYBOARD,
		EV_MOUSE,
		EV_GAMEPAD,
	};

	InputEvent()
		: m_type( EV_INVALID )
	{}

	EType m_type;

	  // Aren't unions nice? :)
	union
	{
		KeyboardEvent m_keyboardEvent;
		MouseEvent m_mouseEvent;
		GamepadEvent m_gamepadEvent;
	};

	static InputEvent KeyboardEvent( KeyboardEvent::EType type, int code, int unichar, int flags )
	{
		InputEvent ev;
		ev.m_type = EV_KEYBOARD;
		ev.m_keyboardEvent.m_type = type;
		ev.m_keyboardEvent.m_keycode = code;
		ev.m_keyboardEvent.m_flags = flags;
		ev.m_keyboardEvent.m_unichar = unichar;
		return ev;
	}

	static InputEvent MouseEvent( MouseEvent::EType type, int x, int y, int dWheel )
	{
		InputEvent ev;
		ev.m_type = EV_MOUSE;
		ev.m_mouseEvent.m_type = type;
		ev.m_mouseEvent.m_x = x;
		ev.m_mouseEvent.m_y = y;
		ev.m_mouseEvent.m_deltaWheel = dWheel;
		return ev;
	}

	static InputEvent GamepadEvent( GamepadEvent::EType type )
	{
		InputEvent ev;
		ev.m_type = EV_GAMEPAD;
		ev.m_gamepadEvent.m_type = type;
		return ev;
	}
};

// See AllegroInput5 for some comments
class IInput
{
public:
	virtual bool Init( bool keyboard, bool mouse, bool gamepad ) = 0;
	virtual void WaitAnyKey() = 0;
	virtual InputEvent GetEvent() = 0;
	virtual void BeginRead() = 0;
	virtual void PopEvent() = 0;
	virtual void NextEvent() = 0;
	virtual void Update( int dt ) = 0;
	virtual void Clear() = 0;
};

IInput & GetInput();
