// ------------------------------------------------------------------------
/*
	\author: Jaap Suter
   
	Copyright (C) Electronic Arts Canada Inc. 2002.  All rights reserved.	
*/
// ------------------------------------------------------------------------

/*! \file */

#ifndef REVEAL_WIDGET_H
#define REVEAL_WIDGET_H

#include <string.h>
#include <ctype.h>
#include "reveal/stdint.h"

#if defined _MSC_VER
#pragma warning( disable : 4100 ) // warning C4100: '*' : unreferenced formal parameter
#endif

namespace Reveal {

	class Renderer;
	class InputState;	
	struct GuiColors;

	namespace Impl {

		class Tree;
		class Menu;

// ------------------------------------------------------------------------
/*!
	\brief Base class for all renderable entities in the GUI;
*/
// ------------------------------------------------------------------------
class Widget
{

public:

	//! \todo: Explain custom new;
	static void* operator new( size_t size );

	//! \todo: Explain custom delete;
	static void operator delete( void* ptr );

	/*!
		\brief Class constants;
	*/
	enum 
	{ 
		MAX_NAME_STRING_LENGTH = 16,							//!< Maximum length of the name string;
		MAX_PATH_STRING_LENGTH = MAX_NAME_STRING_LENGTH * 10,	//!< Maximum length of a full path;
		MAX_NUM_REVEAL_ITEMS   = 128,							//!< Maximum number of items in the entire tweaker system;

		//! Maximum size necessary to store all information in the entire tweaker system;
		MAX_BUFFER_SIZE		   = MAX_NUM_REVEAL_ITEMS * (MAX_PATH_STRING_LENGTH + MAX_NAME_STRING_LENGTH + 32) // 32 is for the actual value, the qoutes and some slack;
	};

	//! Virtual destructor;
	virtual	~Widget();

	/*!
		\brief Sets menu the widget belongs to;
		\param menu Pointer to the parent menu, can be NULL if this widget has no parent;
	*/
	void SetParent( Menu* menu ) { mParent = menu; }

	/*!
		\brief Renders the widget
		
		The widget itself can ofcourse decided not to render itself, it it is invisible;
		
		\note  Calls the virtual \a DoRender which must be implemented by derived classes.
	*/
	void Render( const Renderer& renderer, const GuiColors& guiColors ) const;

	/*!
		\brief Gives the widget a chance to handle the given input;

		\return true if the widget handled the input, false otherwise
		\note Calls the virtual \a DoHandle which must be implemented by derived clases.
	*/
	virtual Widget* Handle( const InputState& inputState );
	
	int			 X()		   const { return mX; }			//!< Returns the current X position of the widget;
	int			 Y()		   const { return mY; }			//!< Returns the current Y position of the widget;
	const char*  Name()		   const { return mName; }		//!< Returns the name of the widget;
	bool		 IsVisible()   const { return mVisible; }	//!< Returns the visibility of the widget;
	virtual int  Width()	   const = 0;					//!< Pure virtual, returns the GUI space width of the widget, must be implemented by the derived class;
	virtual int  Height()	   const = 0;					//!< Pure virtual, returns the GUI space height of the widget, must be implemented by the derived class;

	//! Tells the widget to show itself at the specified location;
	void Show( int x, int y ) { mVisible = true; mX = x; mY = y; }	

	//! Tells the widget to hide itself;
	void Hide() { mVisible = false; }	

	/*! 
		\brief LoseFocuses the widget;
		\note  Calls the virtual \a DoLoseFocus which may or may not be implemented by derived classes;
	*/
	void LoseFocus();

	/*! 
		\brief Tells the widget it got the focus;
		\note  Calls the virtual \a DoGiveFocus which may or may not be implemented by derived classes;
	*/
	void GiveFocus();

	//!< Returns whether or not the widget has the focus;
	bool HasFocus() const;

	//!< Returns whether or not the mouse is currently over the widget;
	bool MouseOver( const InputState& inputState ) const;

	/*!
		\brief Outputs the full path, name and value to a string;
		
		\param path		Path up to here, through the parent, grandparents, etc.
		\param buffer	Buffer to fill with the string;
		\param size		Size of the given buffer;
		
		\return Number of characters written;
	*/
	size_t ToString( const char* path, char* buffer, size_t size ) const;

	//! Loads the full path, name and value from a string;
	void FromString( const char* data ) { DoFromString( data ); }

	//! \return The parent of this widget, can be NULL;
	Menu* Parent() const { return mParent; }

	//! Sets the help string for the menu item MUST BE A STATIC STRING
	void SetHelp (const char* help) { mHelp = help; }

	bool HasHelp () { return mHelp != NULL; }

	const char* GetHelp () { return mHelp; }

	virtual void	Update();

protected:

	//! Allows a derived class to set the horizontal position of the widget;
	void SetX( int x ) { mX = x; }
	
	//! Allows a derived class to set the vertical position of the widget;
	void SetY( int y ) { mY = y; }

	/*!
		\brief Constructor;
		\param name	Name of the widget;
		\param menu Parent menu this widget belongs to, can be NULL (which is the default value);
		\param tree Tree this widget belongs to;
	*/
	Widget( const char* name, Tree& tree, Menu* parent = NULL )
	:
		mX( 0 ),
		mY( 0 ),
		mVisible( false ),
		mParent( parent ),
		mTree( tree ),
		mHelp( NULL )
	{
		strncpy( mName, name, MAX_NAME_STRING_LENGTH );
		mName[ MAX_NAME_STRING_LENGTH - 1 ] = '\0';
		for ( size_t i = 0; i < MAX_NAME_STRING_LENGTH; ++i ) mName[ i ] = static_cast< char >( tolower( static_cast< unsigned char >( mName[ i ] ) ) );	
	}

	//! Default empty base implementation for virtual LoseFocusing;
	virtual void DoLoseFocus() { /* Empty default */ }

	//! Default empty base implementation for virtual GiveFocusing;
	virtual void DoGiveFocus() { /* Empty default */ }

	//! \return Tree this widget belongs to;
	Tree& GetTree() { return mTree; }
	
	//! \return Const qualified tweaker this widget belongs to;
	const Tree& GetTree() const { return mTree; }

	/*!
		\brief Requests the parent menu of this widget to make itself the most recently used one;
		\note  If this widget has no parent, nothing happens. 
	*/
public:   // STUBIFICATION - Moved to public scope
	//! Gives the focus over to the parent;
	//! \return the parent if the focus succesfully transfered, otherwise the this ptr;
	Widget* GiveFocusToParent();

	void MakeParentMostRecentlyUsed();

	size_t PathAndNameToString( const char* path, char* buffer, size_t size ) const;

	// Draws the border around the widget;
	void DrawBorder( const Renderer& renderer, const GuiColors& guiColors ) const;

private:

	virtual void	DoRender( const Renderer& renderer, const GuiColors& guiColors ) const = 0;
	virtual Widget* DoHandle(   const InputState& inputState ) = 0;
	virtual size_t  DoToString( const char* path, char* buffer, size_t size ) const = 0;
	virtual void    DoFromString( const char* data ) { /* \todo make pure */ }

	Widget( const Widget& );			  //!< Not implemented;
	Widget& operator = ( const Widget& ); //!< Not implemented;

	char	 mName[ MAX_NAME_STRING_LENGTH ];
	int		 mX;
	int		 mY;
	bool	 mVisible;
	
	Menu*    mParent;
	Tree&    mTree;			//!< The tree this widget belongs to;

	const char* mHelp;
};



	} // Namespace Impl;
} // Namespace Reveal;

#endif
