#pragma once

#include "dllinterface.h"
#include "..\Utilities\list.h"
#include "d3dx9.h"
#include "..\dxfunctions\dllinterface.h"
#include "..\dxfunctions\difunctions.h"
#include "..\dxfunctions\dxvector2.h"

class Menu;
class MenuManager;

enum ALIGNMENT
{
	AL_RIGHTBOTTOM = 0,
	AL_RIGHTCENTER,
	AL_RIGHTTOP,
	AL_LEFTBOTTOM,
	AL_LEFTCENTER,
	AL_LEFTTOP,
	AL_CENTERBOTTOM,
	AL_CENTER,
	AL_CENTERTOP
};

/*enum GUIEVENT
{
	GE_NONE = 0x0000,
	GE_UPDATE = 0x0001,
	GE_DRAW = 0x0002,
	GE_MOUSEOVER = 0x0004,
	GE_MOUSEON = 0x0008,
	GE_MOUSEOFF = 0x0010,
	GE_BUTTONDOWN = 0x0020,
	GE_BUTTONUP = 0x0040,
	GE_BUTTONCLICK = 0x0080,
	GE_BUTTONDCLICK = 0x0100,
	GE_WHEEL = 0x0200,
	GE_HASFOCUS = 0x0400,
	GE_GOTFOCUS = 0x0800,
	GE_LOSTFOCUS = 0x1000,
	GE_KEYDOWN = 0x2000,
	GE_KEYUP = 0x4000,
	GE_KEYPRESS = 0x8000,
	//GE_FORCEDWORD = 0xffffffff
};*/

enum GUIEVENT
{
	GE_NONE = 0,
	GE_UPDATE,
	GE_DRAW,
	GE_MOUSEOVER,
	GE_MOUSEON,
	GE_MOUSEOFF,
	GE_BUTTONDOWN,
	GE_BUTTONUP,
	GE_BUTTONCLICK,
	GE_BUTTONDCLICK,
	GE_WHEEL,
	GE_HASFOCUS,
	GE_GOTFOCUS,
	GE_LOSTFOCUS,
	GE_KEYDOWN,
	GE_KEYUP,
	GE_KEYPRESS,
	GE_VALUECHANGED,
	GE_COUNT
	//GE_FORCEDWORD = 0xffffffff
};

class GAMEGUI_API GUIElement
{
	//the menumanager to have access to all the basic functions
	MenuManager*		m_Manager;

	//the menu in which element is embedded, required to raise events
	Menu*				m_Menu;

	//parent of element for a faster navigation, parent determinates the clipping
	GUIElement*			m_Parent;

	//childs of this element
	LList<GUIElement>	m_Childs;

	DWORD				m_ID;
	bool				m_Asolute;
	float				m_X,m_Y,m_Xl,m_Yl;
	ALIGNMENT			m_Align;
	bool				m_Enable;
	bool				m_Visible;
	bool				m_Focus;
	bool				m_FocusByClick;
	DWORD				m_TabIndex;

	bool				m_MouseOver;
	BYTE				m_MouseButtons[3];
	DWORD				m_MouseClickTime[3];

	BYTE				m_CurKey;
	bool				m_FirstRepeat;
	DWORD				m_LastPressEventTime;

	void*				m_pUserData;

	//DWORD				m_HandledEvents;
	void(*m_EventHandlers[GE_COUNT])(GUIElement* const sender, const GUIEVENT evnt, void* const pData);

protected:

	friend LList<GUIElement>;
	friend ListElement<GUIElement>;

	//internal function that sets the menu and of its childs, needed to relink elements
	void SetMenu(Menu* menu);
	//internal function that sets the parent, needed to relink elements
	void SetParent(GUIElement *parent){m_Parent = parent;}

	virtual ~GUIElement(void);

	static void OnFwdEvent(GUIElement* const sender, const GUIEVENT evnt, void* const pData);

public:
	//the constructor initalizes the members
	//all the other members have default values
	GUIElement(MenuManager* const manager, const DWORD id);

	MenuManager*GetManager(void){return m_Manager;}
	Menu*GetMenu(void){return m_Menu;}
	
	void AddChild(GUIElement*el);
	void RemoveChild(GUIElement*el);
	void RemoveAllChilds(void);
	const LList<GUIElement>& GetChilds(void) const { return m_Childs; }
	GUIElement* GetChildByID(const DWORD id) const;
	void Unlink(void);
	void Delete(void);

	void Update(const bool withcilds = true);
	void UpdateMouseOver(void);
	void Draw(const bool withchilds = true);

	void HandleEvent(const GUIEVENT evnt, const DWORD param=0);
	
	virtual void OnUpdate(void){}
	virtual void OnDraw(void){}
	virtual void OnMouseOn(void){}
	virtual void OnMouseOver(void){}
	virtual void OnMouseOff(void){}
	virtual void OnButtonDown(const MOUSEBUTTON btn){}
	virtual void OnButtonUp(const MOUSEBUTTON btn){}
	virtual void OnButtonClick(const MOUSEBUTTON btn){}
	virtual void OnButtonDClick(const MOUSEBUTTON btn){}
	virtual void OnWheel(int d){}
	virtual void OnGotFocus(void){}
	virtual void OnHasFocus(void){}
	virtual void OnLostFocus(void){}
	virtual void OnKeyDown(BYTE key){}
	virtual void OnKeyUp(BYTE key){}
	virtual void OnKeyPress(BYTE key){}
	virtual void OnValueChanged(void){}

	DWORD GetID(void) const { return m_ID; }

	virtual void SetAlign(const ALIGNMENT al) { m_Align = al; }
	ALIGNMENT GetAlign(void) const { return m_Align; }

	virtual void SetPosition(const float x, const float y) { m_X = x; m_Y = y; }
	float GetX(void) const { return m_X; }
	float GetY(void) const { return m_Y; }

	virtual void SetSize(const float xl, const float yl) { m_Xl = xl;m_Yl = yl; }
	float GetXl(void) const { return m_Xl; }
	float GetYl(void) const { return m_Yl; }

	void SetFocus(const bool focus){ if(focus && !m_Focus)HandleEvent(GE_GOTFOCUS);else if(!focus && m_Focus)HandleEvent(GE_LOSTFOCUS); m_Focus = focus; }
	bool GetFocus(void) const { return m_Focus; }

	void SetVisible(const bool vis) { m_Visible = vis; }
	bool IsVisible(void) const { return m_Visible; }

	void SetFocusByClick(const bool fbc) { m_FocusByClick = fbc; }
	bool GetFocusByClick(void) const { return m_FocusByClick; }

	void SetTabIndex(const DWORD tabindex);
	DWORD GetTabIndex(void) const { return m_TabIndex; }

	void SetEnable(const bool ena) { m_Enable = ena; }
	bool IsEnable(void) const { return m_Enable; }

	bool IsMouseOver(void) const { return m_MouseOver; }

	GUIElement* GetParent(void) const { return m_Parent; }

	//DWORD GetHandledEvents(void) const { return m_HandledEvents; }
	//void SetHandledEvents(DWORD events) { m_HandledEvents = events; }
	void SetEventHandler(const GUIEVENT evnt, void(*handler)(GUIElement* const sender, const GUIEVENT evnt, void* const pData));

	BYTE GetMouseButton(const MOUSEBUTTON btn) { return m_MouseButtons[btn]; }

	DXVector2 GetDrawPos(void) const;

	void SetUserData(void* const pUserData) { m_pUserData = pUserData; }
	void* GetUserData(void) const { return m_pUserData; }
};
