// ------------------------------------------------------------------------------------ //
//																						//
//	File: Asura_GUIMenu_Widget_Base.h													//
//																						//
//	Description: base class for all widgets												//
//																						//
//	Created: Steve Keen - 9/11/06														//
//																						//
//	Copyright (C) 2006 Rebellion (Derby), All Rights Reserved.							//
// ------------------------------------------------------------------------------------ //

#ifndef __ASURA_GUIMENU_WIDGET_BASE_H__
#define __ASURA_GUIMENU_WIDGET_BASE_H__

#ifdef ASURA_USE_PRAGMA_ONCE
#pragma once
#endif

#ifdef ASURA_USE_GUI_MENU_SYSTEM
#include "GUIMenu/Asura_GUIMenu_Root.h"
#include "GUIMenu/Asura_GUIMenu_CommandConsole.h"


// -- Typedef -------------------------------------------------------------------------


// -- Enums ---------------------------------------------------------------------------

enum Asura_GUIMenu_Action_BitShift
{
	ASURA_GUIMENU_ACTION_BITSHIFT_UP = 0,		// bit 0
	ASURA_GUIMENU_ACTION_BITSHIFT_DOWN,			// bit 1
	ASURA_GUIMENU_ACTION_BITSHIFT_LEFT,			// bit 2
	ASURA_GUIMENU_ACTION_BITSHIFT_RIGHT,		// bit 3
	ASURA_GUIMENU_ACTION_BITSHIFT_ACCEPT,		// bit 4
	ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT1,	// bit 5
	ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT2,	// bit 6
	ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT3,	// bit 7
	ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT4,	// bit 8
	ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT5,	// bit 9
	ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT6,	// bit 10
	ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT7,	// bit 11
	ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT8,	// bit 12
	ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT9,	// bit 13
	ASURA_GUIMENU_ACTION_BITSHIFT_CANCEL,		// bit 14

	ASURA_GUIMENU_ACTION_BITSHIFT_UP_HELD,		// bit 15
	ASURA_GUIMENU_ACTION_BITSHIFT_DOWN_HELD,	// bit 16
	ASURA_GUIMENU_ACTION_BITSHIFT_LEFT_HELD,	// bit 17
	ASURA_GUIMENU_ACTION_BITSHIFT_RIGHT_HELD,	// bit 18
	ASURA_GUIMENU_ACTION_BITSHIFT_ACCEPT_HELD,	// bit 19
	ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT1_HELD,	// bit 20
	ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT2_HELD,	// bit 21
	ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT3_HELD,	// bit 22
	ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT4_HELD,	// bit 23
	ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT5_HELD,	// bit 24
	ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT6_HELD,	// bit 25
	ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT7_HELD,	// bit 26
	ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT8_HELD,	// bit 27
	ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT9_HELD,	// bit 28
	ASURA_GUIMENU_ACTION_BITSHIFT_CANCEL_HELD,		// bit 29
	ASURA_GUIMENU_ACTION_BITSHIFT_CLICK,			// bit 30
	ASURA_GUIMENU_ACTION_BITSHIFT_CLICK_HELD		// bit 31
};

enum Asura_GUIMenu_Navigation_Exit
{
	ASURA_GUIMENU_UI_NAV_EXIT_LEFT = 0,
	ASURA_GUIMENU_UI_NAV_EXIT_RIGHT,
	ASURA_GUIMENU_UI_NAV_EXIT_UP,
	ASURA_GUIMENU_UI_NAV_EXIT_DOWN,
	ASURA_GUIMENU_UI_NAV_EXIT_MAX
};

enum Asura_GUIMenu_Widget_State
{
	// for convenience, the states are the same values as the root flags indicating
	// which states an item is valid for. 
	// (MH - 02.03.2007) Probably shouldn't add any states.
	ASURA_GUIMENU_WIDGET_STATE_DEFAULT = ASURA_GUIMENU_ACTION_FLAG_IS_DEFAULT,
	ASURA_GUIMENU_WIDGET_STATE_DISABLED = ASURA_GUIMENU_ACTION_FLAG_IS_DISABLED,
	ASURA_GUIMENU_WIDGET_STATE_CLICKED = ASURA_GUIMENU_ACTION_FLAG_IS_CLICKED,
	ASURA_GUIMENU_WIDGET_STATE_ROLL_ON = ASURA_GUIMENU_ACTION_FLAG_IS_ROLL_ON,
	ASURA_GUIMENU_WIDGET_STATE_ROLL_OFF = ASURA_GUIMENU_ACTION_FLAG_IS_ROLL_OFF,
	ASURA_GUIMENU_WIDGET_STATE_HILIGHTED = ASURA_GUIMENU_ACTION_FLAG_IS_HILIGHTED,
	
	// SK 21.03.07 - added to reflect additions in root.
	ASURA_GUIMENU_WIDGET_STATE_EDITING = ASURA_GUIMENU_ACTION_FLAG_IS_EDITING
	// (MH - 02.03.2007) following 2 aren't widget states, but were presumably added to keep
	// this enum in sync with the root flags. I'm not going to continue that practice.
	//ASURA_GUIMENU_WIDGET_NOTIFY_ON_EXIT = ASURA_GUIMENU_ACTION_FLAG_NOTIFY_DATA_CHANGE_ON_EXIT,
	//ASURA_GUIMENU_WIDGET_NOTIFY_IMMEDIATE = ASURA_GUIMENU_ACTION_FLAG_NOTIFY_DATA_CHANGE_IMMEDIATE
};

// -- Defines -------------------------------------------------------------------------

#define ASURA_GUIMENU_ACTION_BUTTON_UP		(1<<ASURA_GUIMENU_ACTION_BITSHIFT_UP)
#define ASURA_GUIMENU_ACTION_BUTTON_DOWN		(1<<ASURA_GUIMENU_ACTION_BITSHIFT_DOWN)
#define ASURA_GUIMENU_ACTION_BUTTON_LEFT		(1<<ASURA_GUIMENU_ACTION_BITSHIFT_LEFT)
#define ASURA_GUIMENU_ACTION_BUTTON_RIGHT		(1<<ASURA_GUIMENU_ACTION_BITSHIFT_RIGHT)

#define ASURA_GUIMENU_ACTION_BUTTON_ACCEPT	(1<<ASURA_GUIMENU_ACTION_BITSHIFT_ACCEPT)
#define ASURA_GUIMENU_ACTION_BUTTON_ALT_ACCEPT1	(1<<ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT1)
#define ASURA_GUIMENU_ACTION_BUTTON_ALT_ACCEPT2	(1<<ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT2)
#define ASURA_GUIMENU_ACTION_BUTTON_ALT_ACCEPT3	(1<<ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT3)
#define ASURA_GUIMENU_ACTION_BUTTON_ALT_ACCEPT4	(1<<ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT4)
#define ASURA_GUIMENU_ACTION_BUTTON_ALT_ACCEPT5	(1<<ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT5)
#define ASURA_GUIMENU_ACTION_BUTTON_ALT_ACCEPT6	(1<<ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT6)
#define ASURA_GUIMENU_ACTION_BUTTON_ALT_ACCEPT7	(1<<ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT7)
#define ASURA_GUIMENU_ACTION_BUTTON_ALT_ACCEPT8	(1<<ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT8)
#define ASURA_GUIMENU_ACTION_BUTTON_ALT_ACCEPT9	(1<<ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT9)
#define ASURA_GUIMENU_ACTION_BUTTON_CANCEL	(1<<ASURA_GUIMENU_ACTION_BITSHIFT_CANCEL)

#define ASURA_GUIMENU_ACTION_BUTTON_UP_HELD		(1<<ASURA_GUIMENU_ACTION_BITSHIFT_UP_HELD)
#define ASURA_GUIMENU_ACTION_BUTTON_DOWN_HELD		(1<<ASURA_GUIMENU_ACTION_BITSHIFT_DOWN_HELD)
#define ASURA_GUIMENU_ACTION_BUTTON_LEFT_HELD		(1<<ASURA_GUIMENU_ACTION_BITSHIFT_LEFT_HELD)
#define ASURA_GUIMENU_ACTION_BUTTON_RIGHT_HELD	(1<<ASURA_GUIMENU_ACTION_BITSHIFT_RIGHT_HELD)

#define ASURA_GUIMENU_ACTION_BUTTON_ACCEPT_HELD	(1<<ASURA_GUIMENU_ACTION_BITSHIFT_ACCEPT_HELD)
#define ASURA_GUIMENU_ACTION_BUTTON_ALT_ACCEPT1_HELD	(1<<ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT1_HELD)
#define ASURA_GUIMENU_ACTION_BUTTON_ALT_ACCEPT2_HELD	(1<<ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT2_HELD)
#define ASURA_GUIMENU_ACTION_BUTTON_ALT_ACCEPT3_HELD	(1<<ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT3_HELD)
#define ASURA_GUIMENU_ACTION_BUTTON_ALT_ACCEPT4_HELD	(1<<ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT4_HELD)
#define ASURA_GUIMENU_ACTION_BUTTON_ALT_ACCEPT5_HELD	(1<<ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT5_HELD)
#define ASURA_GUIMENU_ACTION_BUTTON_ALT_ACCEPT6_HELD	(1<<ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT6_HELD)
#define ASURA_GUIMENU_ACTION_BUTTON_ALT_ACCEPT7_HELD	(1<<ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT7_HELD)
#define ASURA_GUIMENU_ACTION_BUTTON_ALT_ACCEPT8_HELD	(1<<ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT8_HELD)
#define ASURA_GUIMENU_ACTION_BUTTON_ALT_ACCEPT9_HELD	(1<<ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT9_HELD)

#define ASURA_GUIMENU_ACTION_BUTTON_CANCEL_HELD	(1<<ASURA_GUIMENU_ACTION_BITSHIFT_CANCEL_HELD)

#define ASURA_GUIMENU_ACTION_BUTTON_CLICK		(1<<ASURA_GUIMENU_ACTION_BITSHIFT_CLICK)
#define ASURA_GUIMENU_ACTION_BUTTON_CLICK_HELD	(1<<ASURA_GUIMENU_ACTION_BITSHIFT_CLICK_HELD)


#define ASURA_GUIMENU_MAX_ACTION_BUTTON_COMMANDS	(4)

#define ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_START	8

// version history: 
// 0 - initial version
// 1 - added m_bCanBeSelectable (MH - 02.04.2007) 
// 2 - added OnRollIn and OnRollOut events (CW - 11.03.2008)
// 3 - added m_bIsAlwaysSelectable (CW - 12.06.2008)
#define ASURA_CHUNK_WIDGET_BASE_VERSION 3

// -- Structures ----------------------------------------------------------------------

// -- Class ---------------------------------------------------------------------------
class Asura_GUIMenu_Root;

class Asura_GUIMenu_Widget_Base : public Asura_GUIMenu_Root
{
	friend class Tools_GUIMenu_Widget_Base;

	// -- Functions -----------------------------------------------------------------------
public:
	enum Asura_GUIMenu_Inherit_Flag_Widget_Base_Type
	{
		ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_NAVID_UP			= (1<<(ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_START+0)),
		ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_NAVID_DOWN			= (1<<(ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_START+1)),
		ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_NAVID_LEFT			= (1<<(ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_START+2)),
		ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_NAVID_RIGHT		= (1<<(ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_START+3)),
		ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_SELECTABLE			= (1<<(ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_START+4)),
		ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_ONROLLIN_COMMAND	= (1<<(ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_START+5)),
		ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_ONROLLOUT_COMMAND	= (1<<(ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_START+6)),
		ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_ISALWAYSSELECTABLE	= (1<<(ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_START+7)),
		//ASURA_GUIMENU_ELEMENT_BASE_OVERIDE_MAX is here to stop another programmer adding past bit flag 15
		ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_MAX				= (1<<(ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_START+8))
	};


	Asura_GUIMenu_Widget_Base();
	virtual ~Asura_GUIMenu_Widget_Base();

	virtual bool				HandleMessage( const Asura_Message_GUIMenu_Notify* pxMessage);

	virtual void				Update( float fElapsedTime);//, u_int uButtons, POINT ptMousePos);
	virtual void 				Render( u_int uState);
	virtual void				Copy( const Asura_GUIMenu_Root* pxSource );

	virtual u_int				ProcessInputActivity( const Asura_GUIMenu_Input& xInput);

	virtual void				SetHiddenByConditionVar( bool bTF );

	// accessors
	bool						IsSelectable() const { return m_bIsAlwaysSelectable || (m_bSelectable && m_bCanBeSelectable); }
	void						SetSelectable(bool bTF) { m_bSelectable = bTF; }
	void						SetCanBeSelectable(bool bTF) {m_bCanBeSelectable = bTF;}
	void						SetIsAlwaysSelectable(bool bTF) {m_bIsAlwaysSelectable = bTF;}

	u_int						GetNavExitID( Asura_GUIMenu_Navigation_Exit uExit)  const;
	void						SetNavExitID( Asura_GUIMenu_Navigation_Exit uExit, u_int hashExitID);

	//Just gets the exit ID stored in this widget without any messing around recursing or checking that it corresponds
	//to a valid destination widget. RAR 18/06/2008
	u_int						GetNavExitID_Raw( Asura_GUIMenu_Navigation_Exit uExit)  const {return m_auHashNavID[uExit];}



	//Does a recursive search for a selectable widget at the given location
	virtual Asura_GUIMenu_Widget_Base*  FindSelectableWidgetAtPos(const Asura_Vector_2& xPos);


	// -- UI Message handler functions --

	// CW - Quick note, all return false as called from as result is returned from HandleMessage.

	virtual bool				OnInit( const Asura_Message_GUIMenu_Notify* pxMessage);//	{	return false;	}
	virtual bool				OnDeInit( const Asura_Message_GUIMenu_Notify* pxMessage) = 0;// most derived classes aren't calling it anyway.
	virtual bool				OnDataChange( const Asura_Message_GUIMenu_Notify* pxMessage)	{ return false;	}
	virtual bool				OnDataRequest( const Asura_Message_GUIMenu_Notify* pxMessage)	{ return false;	}
	virtual bool				OnClicked( const Asura_Message_GUIMenu_Notify* pxMessage)	{ return false;	}
	virtual bool				OnRollIn( const Asura_Message_GUIMenu_Notify* pxMessage)	{ GetOnRollInCommand()->Execute( NULL); return true; }
	virtual bool				OnRollOut( const Asura_Message_GUIMenu_Notify* pxMessage)	{ GetOnRollOutCommand()->Execute( NULL); return true; }
	virtual bool				OnEnable( const Asura_Message_GUIMenu_Notify* pxMessage)	{ return false;	}

	const Asura_GUIMenu_ConsoleCmd* GetOnRollInCommand() const { return &m_xOnRollInCommand; }
	const Asura_GUIMenu_ConsoleCmd* GetOnRollOutCommand() const { return &m_xOnRollOutCommand; }

	void						SetNavExitIDs( Asura_Hash_ID uHashUp, Asura_Hash_ID uHashDown, Asura_Hash_ID uHashLeft = ASURA_HASH_ID_UNSET, Asura_Hash_ID uHashRight = ASURA_HASH_ID_UNSET);

	virtual bool				Whisper( const Asura_Message_GUIMenu_Notify* pxNotify);

	Asura_GUIMenu_Widget_State	GetCurrentState( void)	{	return m_uCurrentState;	}
	void						SetCurrentState( Asura_GUIMenu_Widget_State eState)	{ m_uCurrentState = eState;	}

	bool						IsFocusedObject( void) const {	return m_bIsFocusedObject;	}
	void						SetAsFocusedObject( bool bIsFocusedObject)	{ m_bIsFocusedObject = bIsFocusedObject;	}

#ifdef ASURA_TOOLS
	virtual void				UpdateLocalDataFromStyle( void);

	virtual	void				WriteToChunkStream( Asura_Chunk_Stream& xStream) const;
	virtual void				ExportToXML(Tools_GUIMenu_XMLExporter* pxExporter) const;
#endif // ASURA_TOOLS

	virtual void				ReadFromChunkStream( Asura_Chunk_Stream& xStream, Asura_GUIMenu_Root* pxParentObject, u_int uChunkVersion);
protected:

	u_int						ProcessNavigationInput( u_int uButtonPresses);

	virtual void				SetupDefaultElements( void) = 0;

private:

	// GetNavExitID_Internal() allows for safe recursive calls.
	u_int						GetNavExitID_Internal( Asura_GUIMenu_Navigation_Exit uExit, Asura_Hash_ID* puHashIds, u_int uCount)  const;

	// -- Variables -----------------------------------------------------------------------
public:

protected:

	Asura_GUIMenu_ConsoleCmd				m_xOnRollInCommand;
	Asura_GUIMenu_ConsoleCmd				m_xOnRollOutCommand;

private:							
	bool									m_bSelectable;		// runtime flag, set based on condition var
	bool									m_bCanBeSelectable;	// can be set to false in Tools to prevent widget ever being highlighted item.
	bool									m_bIsAlwaysSelectable;
	bool									m_bIsFocusedObject;
	
	Asura_GUIMenu_Widget_State				m_uCurrentState;
	
	Asura_Hash_ID							m_auHashNavID[ASURA_GUIMENU_UI_NAV_EXIT_MAX];

	// ------------------------------------------------------------------------------------
	typedef Asura_GUIMenu_Root PARENT;
};
#endif // ASURA_USE_GUI_MENU_SYSTEM
#endif // __ASURA_GUIMENU_WIDGET_BASE_H__
