//////////////////////////////////////////////////////////////////////////////
//
// Asura_GUIMenu_CommandConsole.h
//
// Copyright (c) 2007 Rebellion. All rights reserved.
//
// Description:
//
//     interface to the command console for the GUIMenu code for setting
//     variables and executing commands
//
//////////////////////////////////////////////////////////////////////////////

// B E G I N   F I L E   W R A P P E R ///////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef ASURA_GUIMENU_COMMANDCONSOLE_H___
#define ASURA_GUIMENU_COMMANDCONSOLE_H___ 1

#ifdef ASURA_USE_GUI_MENU_SYSTEM
#include "Core/Asura_String.h"

#include "Interface/Asura_CommandConsole.h"

#ifdef ASURA_TOOLS
#include "Misc/list_tem.hpp"
#endif // ASURA_TOOLS

// F O R W A R D   D E C L A R A T I O N S ///////////////////////////////////
class Asura_Chunk_Stream;
class Asura_Dialog;
class Tools_GUIMenu_XMLExporter;

// D E F I N E S /////////////////////////////////////////////////////////////
#define ASURA_GUIMENU_CONSOLEVAR_NONE (" *None* ")

// C L A S S E S /////////////////////////////////////////////////////////////
class Asura_GUIMenu_ConsoleCmd
{
public:

	bool Execute(const char* szArgumentOverride, void (*pfnOutputCallback)(const Asura_UnicodeChar*) = NULL) const;
	void Copy(const Asura_GUIMenu_ConsoleCmd* pxCmd);
	bool ReadFromChunkStream( Asura_Chunk_Stream& xStream );
#ifdef ASURA_TOOLS
	void WriteToChunkStream( Asura_Chunk_Stream& xStream ) const;
	virtual void ExportToXML(Tools_GUIMenu_XMLExporter* pxExporter) const;

	// When the optional List<Asura_Dialog*>* argument is != NULL all Asura_Dialog objects new'd in this method are appended to that List 
	void AddOverlayControls(class Asura_Overlay* pxOverlay,class Asura_Vector_2& xOffset, const char* szLabel, const char* szHelpText, bool bAllowArgs, bool* pbChanged, bool bEnable = true, List<Asura_Dialog*>* pxDialogList = NULL );	
#endif

	//returns true if the command name is blank ,or set to *None* while in tools
	bool IsBlank() const;
	
	inline Asura_String& GetName() { return m_xConsoleCmdName; }
	inline const Asura_String& GetName() const { return m_xConsoleCmdName; }

	// TODO: add function sig enum?
	// TODO: add option to take arg from a text/numerical/checkbox widget?
	Asura_String	m_xConsoleCmdName;
	Asura_String	m_xConsoleCmdArgs;
};

class Asura_GUIMenu_ConsoleVar 
{
public:
	Asura_GUIMenu_ConsoleVar();
	Asura_GUIMenu_ConsoleVar( const Asura_GUIMenu_ConsoleVar& xOther );
	Asura_GUIMenu_ConsoleVar( const Asura_String& xName );

	inline Asura_String& GetName() { return m_xConsoleVarName; }
	inline const Asura_String& GetName() const { return m_xConsoleVarName; }
	inline Asura_Hash_ID GetHash() const { return m_uConsoleVarNameHash; }
	inline Asura_CommandConsole_VarRepository::Var::TYPE GetType() const { return m_eConsoleVarType; }

	void SetName( const Asura_String& );

	// update the hash ID and console var type enum
	void Update();

	// GetXXXValue functions write the value if the var name is non-empty
	void GetBoolValue(bool& bValue) const;
	void GetFloatValue(float& fValue) const;
	void GetIntValue(int& iValue) const;
	void GetStringValue(Asura_UnicodeChar* wszValue, u_int uMaxLength) const;

	// SetXXXValue functions set the value if the var name is non-empty
	void SetBoolValue(bool bValue) const;
	void SetFloatValue(float fValue) const;
	void SetIntValue(int iValue) const;
	void SetStringValue(const Asura_UnicodeChar* wszValue) const;

	u_int GetStringBufferSize() const; // including NULL terminator.

	void Copy(const Asura_GUIMenu_ConsoleVar* pxVar);
	bool ReadFromChunkStream( Asura_Chunk_Stream& xStream );
	int  GetChunkSize() const;
	void WriteToChunkStream( Asura_Chunk_Stream& xStream ) const;

#ifdef ASURA_TOOLS

	void ExportToXML( Tools_GUIMenu_XMLExporter* pxExporter ) const;
	void AddOverlayControls(class Asura_Overlay* pxOverlay,class Asura_Vector_2& xOffset, const char*  szLabel, const char* szHelpText, int iType, bool* pbChanged,bool bEnable = true, List<Asura_Dialog*>* pxDialogList = NULL );

	// if the console var name matchs the first argument replace it with the second argument
	const bool FindAndReplaceConsoleVarName( const Asura_UnicodeChar* wszName,const Asura_UnicodeChar* wszReplacementName );
	const bool FindAndReplaceConsoleVarName( const Asura_Char* szName,const Asura_Char* szReplacementName );

	//Most console vars aren't edited/read directly while previewing in tools for safety.
	//Some however (GUIMenu.ActiveWidget) do need to be used for the preview to be of much use.
	//RAR  19/04/2007
	inline bool ShouldBeHandledByTools() const {return ShouldBeHandledByTools(m_xConsoleVarName.GetString());}
	static bool ShouldBeHandledByTools(const char* szVar) {return strncmp(szVar,"GUIMenu.",8) != 0;}

#endif

	//returns true if the var name is blank ,or set to *None* while in tools
	bool IsBlank() const;

private:
	Asura_CommandConsole_VarRepository::Var::TYPE m_eConsoleVarType;

	Asura_String	m_xConsoleVarName;
	Asura_Hash_ID	m_uConsoleVarNameHash;
};

// Asura_GUIMenu_Display_Condition are saved out in chunk data, so don't reorder or
// remove them. Tools_GUIMenu_CommandConsole.cpp has a list of strings for tools
// selection so add to that if any are added.
enum Asura_GUIMenu_Display_Condition
{
	ASURA_GUIMENU_CONDITION_NONE			= 0,
	ASURA_GUIMENU_CONDITION_EQUAL			= 1,
	ASURA_GUIMENU_CONDITION_GREATER			= 2,
	ASURA_GUIMENU_CONDITION_GREATER_EQUAL	= 3,
	ASURA_GUIMENU_CONDITION_LESS			= 4,
	ASURA_GUIMENU_CONDITION_LESS_EQUAL		= 5,
	ASURA_GUIMENU_CONDITION_NOT_EQUAL		= 6,
	NUM_ASURA_GUIMENU_CONDITIONS
};


enum Asura_GUIMenu_LogicalOperator
{
	ASURA_GUIMENU_LOGIC_AND		= 0,
	ASURA_GUIMENU_LOGIC_OR		= 1,
	ASURA_GUIMENU_LOGIC_XOR		= 2,
	ASURA_GUIMENU_LOGIC_NUMTYPES,
};

struct Asura_GUIMenu_Display_Condition_Params
{
	int								m_iDisplayConditionThreshold;
	Asura_GUIMenu_Display_Condition	m_eConditionCompare;
};


// Asura_GUIMenu_ConditionVar is declared here to be included in Asura_GUIMenu_Root.
// It's implementation is in Asura_GUIMenu_CommandConsole.cpp.
class Asura_GUIMenu_ConditionVar
{
public:

	Asura_GUIMenu_ConditionVar();

	const Asura_String& GetName() const { return (IsVarBlank() ? GetCmdName() : GetVarName()); }
	const Asura_String& GetVarName() const { return m_xVar.GetName(); }
	const Asura_String& GetCmdName() const { return m_xCmd.GetName(); }
	Asura_GUIMenu_Display_Condition GetCondition() const { return m_eCondition; }

	void SetCondition( const Asura_GUIMenu_Display_Condition eCondition ) { m_eCondition = eCondition; }

	bool IsConditionMet() const;
	template<class T> bool IsConditionMet( T tVarVal, T tCompVal) const;

	inline bool IsCmdBlank() const { return m_xCmd.IsBlank(); }
	inline bool IsVarBlank() const { return m_xVar.IsBlank(); }
	inline bool IsValueBlank() const { return m_xValue.IsBlank(); }
	inline bool IsConditionBlank() const { return m_eCondition == ASURA_GUIMENU_CONDITION_NONE; }

	// functions
	void Copy(const Asura_GUIMenu_ConditionVar* pxCondVar);
	bool ReadFromChunkStream( Asura_Chunk_Stream& xStream );

	static void CommandCallback(const Asura_UnicodeChar*);

#ifdef ASURA_TOOLS
	void WriteToChunkStream( Asura_Chunk_Stream& xStream ) const;
	void ExportToXML( Tools_GUIMenu_XMLExporter* pxExporter ) const;
	void AddOverlayControls(Asura_Overlay* pxOverlay,class Asura_Vector_2& xOffset, bool* pbChanged, bool bEnable, List<Asura_Dialog*>* pxDialogList = NULL  );

	void SetName( const Asura_String& xName ) { m_xVar.SetName(xName); }

	// if the console var name matchs the first argument replace it with the second argument
	inline const bool FindAndReplaceConsoleVarName( const Asura_UnicodeChar* wszName,const Asura_UnicodeChar* wszReplacementName ) { return m_xVar.FindAndReplaceConsoleVarName( wszName,wszReplacementName ); }
	inline const bool FindAndReplaceConsoleVarName( const Asura_Char* szName,const Asura_Char* szReplacementName ) { return m_xVar.FindAndReplaceConsoleVarName( szName,szReplacementName ); }

	static bool IsConsoleVarSelected(int iThis);
	static bool IsWidgetOrPageHashConsoleVar(int iThis) { return !IsNotWidgetHashConsoleVar(iThis) || !IsNotPageHashConsoleVar(iThis); }
	static bool IsNotWidgetHashConsoleVar(int iThis);
	static bool IsNotPageHashConsoleVar(int iThis);

	const char* GetValue( void )			const	{ return( m_xValue.GetString() ); }
	void SetValue( const char* szValue )			{ m_xValue = szValue; }
#endif

private:
	// data
	Asura_GUIMenu_ConsoleCmd		m_xCmd;
	Asura_GUIMenu_ConsoleVar		m_xVar;
	Asura_String					m_xValue;
	Asura_GUIMenu_Display_Condition	m_eCondition;

	static Asura_UnicodeChar s_awszCmdOutput[256];
};

//class for holding multiple condition vars
class Asura_GUIMenu_ConditionVarManager
{
public :
	Asura_GUIMenu_ConditionVarManager();
	~Asura_GUIMenu_ConditionVarManager();

	bool IsConditionMet() const;
	void SetForceHidden( bool bForceHidden ) { m_bForcedHidden = bForceHidden; }

	// functions
	void Copy(const Asura_GUIMenu_ConditionVarManager* pxCondVar);
	bool ReadFromChunkStream( Asura_Chunk_Stream& xStream );

#ifdef ASURA_TOOLS
	void WriteToChunkStream( Asura_Chunk_Stream& xStream ) const;
	void ExportToXML( Tools_GUIMenu_XMLExporter* pxExporter ) const;
	
	// replace all console var names that match the first argument with the second argument
	const bool FindAndReplaceConsoleVarName( const Asura_UnicodeChar* wszName,const Asura_UnicodeChar* wszReplacementName );
	const bool FindAndReplaceConsoleVarName( const Asura_Char* szName,const Asura_Char* szReplacementName );
#endif

	// data
	u_int m_uNumConditionVars;
	Asura_GUIMenu_ConditionVar* m_pxConditionVars;
	Asura_GUIMenu_LogicalOperator m_eOperator;
	// runtime data
	bool m_bForcedHidden;
};


// E N D   F I L E   W R A P P E R ///////////////////////////////////////////
#endif // ASURA_USE_GUI_MENU_SYSTEM
#endif // #ifndef ASURA_GUIMENU_COMMANDCONSOLE_H___
