/*
 * $Id: guienvironment.h,v 1.5 2008-09-24 11:17:38 kybav1 Exp $
 *
 * Description  : One line description of file.
 * Author       : Vaclav Kyba <mail/Jabber: vaseo1@gmail.com>  <ICQ: 98576293>
 *
 * Purpose      :
 *     Long description of what the file is for.
 */


#ifndef __GUIENVIRONMENT_H__
#define __GUIENVIRONMENT_H__

#include "parameter.h"
#include <wx/aui/auibook.h>
#include <wx/spinctrl.h>
#include <wx/wx.h>
#include <wx/grid.h>
#include <wx/listctrl.h>
#include <wx/statbox.h>
//#include <wx/xrc/xmlres.h>
//#include "environment.h"
#include "wx/renderer.h"
#include "colourpicker.h"
#include "draganddrop.h"

#include <vector>


///Set module's GUI layout
#ifndef PARAM_GUI_SET_LAYOUT
#define PARAM_GUI_SET_LAYOUT(paramId, pName, value, pDescription) \
	{ \
		REGISTER_PARAM(paramId, pName, value, pDescription); \
		PostToKernel(GET_EVT_PARAM_GUI_SET_LAYOUT(paramId, value), true); \
	}
#endif // PARAM_GUI_SET_LAYOUT

#ifndef REGISTER_PARAM_GUI_PANEL
#define REGISTER_PARAM_GUI_PANEL(paramId, pName, value, pDescription) \
	{ REGISTER_PARAM(paramId, pName, value, pDescription);\
	  GUIEnvironment::GUIParamInfo guiPI(paramId, GUIEnvironment::GUIParamInfo::GUI_TYPE_PANEL); \
	  PostToKernel(GET_EVT_PARAM_GUIREGISTER(guiPI, value), true); }
#endif // REGISTER_PARAM_GUI_PANEL

#ifndef REGISTER_PARAM_GUI_LISTCONTROL
#define REGISTER_PARAM_GUI_LISTCONTROL(paramId, pName, value, possibilities, sceneID, pDescription) \
	{ REGISTER_PARAM(paramId, pName, value, pDescription); \
	  GUIEnvironment::GUIParamInfo guiPI(paramId, GUIEnvironment::GUIParamInfo::GUI_TYPE_LISTCONTROL); \
    guiPI.sceneID = sceneID;																				\
    guiPI.values = possibilities;																				\
	  PostToKernel(GET_EVT_PARAM_GUIREGISTER(guiPI, value), true); }
#endif // REGISTER_PARAM_GUI_LISTCONTROL

///Update GUI of module's parameter, keep current value
#ifndef CHANGE_PARAM_GUI_LISTCONTROL
#define CHANGE_PARAM_GUI_LISTCONTROL(paramId, anAction, aValues, aSceneID) \
	do { \
		GUIEnvironment::GUIParamInfo guiPI(paramId, GUIEnvironment::GUIParamInfo::GUI_TYPE_LISTCONTROL); \
		guiPI.action = anAction; \
		guiPI.values = aValues; \
		guiPI.sceneID = aSceneID; \
		wxString value = KERNEL->environment.GetParam(paramId); \
		PostToKernel(GET_EVT_PARAM_GUIREGISTER(guiPI, value), true); \
	} while (false)
#endif // CHANGE_PARAM_GUI_LISTCONTROL

#ifndef REGISTER_PARAM_GUI_BITMAP
#define REGISTER_PARAM_GUI_BITMAP(paramId, pName, value, pDescription) \
	{ REGISTER_PARAM(paramId, pName, value, pDescription);\
	  GUIEnvironment::GUIParamInfo guiPI(paramId, GUIEnvironment::GUIParamInfo::GUI_TYPE_BITMAP); \
	  PostToKernel(GET_EVT_PARAM_GUIREGISTER(guiPI, value), true); }
#endif // REGISTER_PARAM_GUI_BITMAP

///Register module's parameter with its default value using events and show in GUI, extended version
#ifndef REGISTER_PARAM_GUI_TEXTCONTROL
#define REGISTER_PARAM_GUI_TEXTCONTROL(paramId, pName, value, pDescription) \
	{ REGISTER_PARAM(paramId, pName, value, pDescription);\
	  GUIEnvironment::GUIParamInfo guiPI(paramId, GUIEnvironment::GUIParamInfo::GUI_TYPE_TEXTCONTROL); \
	  PostToKernel(GET_EVT_PARAM_GUIREGISTER(guiPI, value), true); }
#endif // REGISTER_PARAM_GUI_TEXTCONTROL

///Register module's parameter with its default value using events and show in GUI
#ifndef REGISTER_PARAM_GUI_CHECKBOX
#define REGISTER_PARAM_GUI_CHECKBOX(paramId, pName, value, pDescription) \
	{ wxString valueTmp(value?wxT("1"):wxT("0")); \
	  REGISTER_PARAM(paramId, pName, valueTmp, pDescription); \
	  value=isTrue(valueTmp);\
	  GUIEnvironment::GUIParamInfo guiPI(paramId, GUIEnvironment::GUIParamInfo::GUI_TYPE_CHECKBOX); \
	  PostToKernel(GET_EVT_PARAM_GUIREGISTER(guiPI, valueTmp), true); }
#endif // REGISTER_PARAM_GUI_CHECKBOX

///Register module's parameter with its default value using events and show in GUI
#ifndef REGISTER_PARAM_GUI_SLIDER
#define REGISTER_PARAM_GUI_SLIDER(paramId, pName, value, minValue, maxValue, pDescription) \
	{ REGISTER_PARAM(paramId, pName, value, pDescription); \
	  GUIEnvironment::GUIParamInfo guiPI(paramId, GUIEnvironment::GUIParamInfo::GUI_TYPE_SLIDER); \
	  guiPI.minval = minValue; \
	  guiPI.maxval = maxValue; \
	  PostToKernel(GET_EVT_PARAM_GUIREGISTER(guiPI, value), true); }
#endif // REGISTER_PARAM_GUI_SLIDER

///Register module's parameter with its default value using events and show in GUI
#ifndef REGISTER_PARAM_GUI_SPINCONTROL
#define REGISTER_PARAM_GUI_SPINCONTROL(paramId, pName, value, minValue, maxValue, pDescription) \
	{ REGISTER_PARAM(paramId, pName, value, pDescription); \
	  GUIEnvironment::GUIParamInfo guiPI(paramId, GUIEnvironment::GUIParamInfo::GUI_TYPE_SPINCONTROL); \
	  guiPI.minval = minValue; \
	  guiPI.maxval = maxValue; \
	  PostToKernel(GET_EVT_PARAM_GUIREGISTER(guiPI, value), true); }
#endif // REGISTER_PARAM_GUI_SPINCONTROL

///Register module's parameter with its default value using events and show in GUI
#ifndef REGISTER_PARAM_GUI_SPINCONTROL_DOUBLE
#define REGISTER_PARAM_GUI_SPINCONTROL_DOUBLE(paramId, pName, value, minValue, maxValue, increment, pDescription) \
	{ REGISTER_PARAM(paramId, pName, value, pDescription); \
	  GUIEnvironment::GUIParamInfo guiPI(paramId, GUIEnvironment::GUIParamInfo::GUI_TYPE_SPINCONTROL_DOUBLE); \
	  guiPI.minval = minValue; \
	  guiPI.maxval = maxValue; \
	  guiPI.step = increment; \
	  PostToKernel(GET_EVT_PARAM_GUIREGISTER(guiPI, value), true); }
#endif // REGISTER_PARAM_GUI_SPINCONTROL_DOUBLE

///Register module's parameter with its default value using events and show in GUI
#ifndef REGISTER_PARAM_GUI_COMBOBOX
#define REGISTER_PARAM_GUI_COMBOBOX(paramId, pName, value, possibilities, pDescription) \
	{ REGISTER_PARAM(paramId, pName, value, pDescription); \
	  GUIEnvironment::GUIParamInfo guiPI(paramId, GUIEnvironment::GUIParamInfo::GUI_TYPE_COMBOBOX); \
	  guiPI.values = possibilities; \
	  PostToKernel(GET_EVT_PARAM_GUIREGISTER(guiPI, value), true); }
#endif // REGISTER_PARAM_GUI_COMBOBOX

///Register module's parameter with its default value using events and show in GUI, extended version
#ifndef REGISTER_PARAM_GUI_BUTTON
#define REGISTER_PARAM_GUI_BUTTON(paramId, pName, pDescription) \
	{ wxString valueTmp; \
	  REGISTER_PARAM(paramId, pName, valueTmp, pDescription); \
	  GUIEnvironment::GUIParamInfo guiPI(paramId, GUIEnvironment::GUIParamInfo::GUI_TYPE_BUTTON); \
	  PostToKernel(GET_EVT_PARAM_GUIREGISTER(guiPI, valueTmp), true); }
#endif // REGISTER_PARAM_GUI_BUTTON

///Register module's parameter with its default value using events and show in GUI
#ifndef REGISTER_PARAM_GUI_TABLE
#define REGISTER_PARAM_GUI_TABLE(paramId, pName, definition, pDescription) \
	{ wxString valueTmp;\
	REGISTER_PARAM(paramId, pName, valueTmp, pDescription); \
	GUIEnvironment::GUIParamInfo guiPI(paramId, GUIEnvironment::GUIParamInfo::GUI_TYPE_TABLE); \
	guiPI.values = definition; \
	PostToKernel(GET_EVT_PARAM_GUIREGISTER(guiPI, valueTmp), true); }
#endif // REGISTER_PARAM_GUI_TABLE

///Register module's parameter with its default value using events and show in GUI, extended version
#ifndef REGISTER_PARAM_GUI_COLOURPICKER
#define REGISTER_PARAM_GUI_COLOURPICKER(paramId, pName, value, pDialogMode, pDescription) \
	{ REGISTER_PARAM(paramId, pName, value, pDescription); \
	GUIEnvironment::GUIParamInfo guiPI(paramId, GUIEnvironment::GUIParamInfo::GUI_TYPE_COLOURPICKER); \
	guiPI.dialogMode = pDialogMode; \
	PostToKernel(GET_EVT_PARAM_GUIREGISTER(guiPI, value), true); }
#endif // REGISTER_PARAM_GUI_COLOURPICKER

///Register module's parameter with its default value using events and show in GUI, extended version
#ifndef REGISTER_PARAM_GUI_SHORTCUTPICKER
#define REGISTER_PARAM_GUI_SHORTCUTPICKER(paramId, pName, value, pDescription) \
	{ REGISTER_PARAM(paramId, pName, value, pDescription); \
	GUIEnvironment::GUIParamInfo guiPI(paramId, GUIEnvironment::GUIParamInfo::GUI_TYPE_SHORTCUTPICKER); \
	PostToKernel(GET_EVT_PARAM_GUIREGISTER(guiPI, value), true); }
#endif // REGISTER_PARAM_GUI_SHORTCUTPICKER

///Register module's parameter with its default value using events and show in GUI, extended version
#ifndef REGISTER_PARAM_GUI_SCRIPTEDITOR
#define REGISTER_PARAM_GUI_SCRIPTEDITOR(paramId, pName, value, pDescription) \
	{ REGISTER_PARAM(paramId, pName, value, pDescription); \
	GUIEnvironment::GUIParamInfo guiPI(paramId, GUIEnvironment::GUIParamInfo::GUI_TYPE_SCRIPTEDITOR); \
	PostToKernel(GET_EVT_PARAM_GUIREGISTER(guiPI, value), true); }
#endif // REGISTER_PARAM_GUI_SCRIPTEDITOR

///Register module's parameter with its default value using events and show in GUI, extended version
#ifndef REGISTER_PARAM_GUI_FILECONTROL
#define REGISTER_PARAM_GUI_FILECONTROL(paramId, pName, value, pFileMode, pWildcard, pDescription) \
	{ REGISTER_PARAM(paramId, pName, value, pDescription);\
	GUIEnvironment::GUIParamInfo guiPI(paramId, GUIEnvironment::GUIParamInfo::GUI_TYPE_FILECONTROL); \
	guiPI.fileMode = pFileMode; \
	guiPI.wildcard = pWildcard; \
	PostToKernel(GET_EVT_PARAM_GUIREGISTER(guiPI, value), true); }
#endif // REGISTER_PARAM_GUI_TEXTCONTROL

///Register module's parameter with its default value using events and show in GUI
#ifndef REGISTER_PARAM_GUI_DROPSOURCE
#define REGISTER_PARAM_GUI_DROPSOURCE(paramId, pName, pDescription, pDataObject) \
	{ wxString valueTmp; \
	  REGISTER_PARAM(paramId, pName, valueTmp, pDescription); \
	  GUIEnvironment::GUIParamInfo guiPI(paramId, GUIEnvironment::GUIParamInfo::GUI_TYPE_DROPSOURCE); \
	  guiPI.dataObject = pDataObject; \
	  PostToKernel(GET_EVT_PARAM_GUIREGISTER(guiPI, valueTmp), true); }
#endif // REGISTER_PARAM_GUI_DROPSOURCE

#ifndef REGISTER_PARAM_GUI_SCENEID
#define REGISTER_PARAM_GUI_SCENEID(paramId, pName, value, pDescription) \
	{ wxString valueTmp(wxString::Format(wxT("%lu"), (unsigned long)value)); \
	REGISTER_PARAM(paramId, pName, valueTmp, pDescription); \
	int valueTmpI; \
	TextParser(valueTmp.utf8_str()).ParseInt(&valueTmpI); \
	value=valueTmpI; \
	GUIEnvironment::GUIParamInfo guiPI(paramId, GUIEnvironment::GUIParamInfo::GUI_TYPE_SCENEID); \
	PostToKernel(GET_EVT_PARAM_GUIREGISTER(guiPI, valueTmp), true); }
#endif // REGISTER_PARAM_GUI_SCENEID

///Note that only first registration will change filter (ie. nodeTypes)
#ifndef REGISTER_PARAM_GUI_NODEID
#define REGISTER_PARAM_GUI_NODEID(paramId, pName, value, sceneId, pNodeTypes, pDescription) \
	{ wxString valueTmp((value==NODE_ID_NONE-1)?wxT(""):wxString::Format(wxT("%lu"), (unsigned long)value)); \
	REGISTER_PARAM(paramId, pName, valueTmp, pDescription); \
	unsigned long valueTmpI; \
	TextParser(valueTmp.utf8_str()).ParseULong(&valueTmpI); \
	value=valueTmpI; \
	GUIEnvironment::GUIParamInfo guiPI(paramId, GUIEnvironment::GUIParamInfo::GUI_TYPE_NODEID); \
	guiPI.sceneID = sceneId; \
	guiPI.nodeTypes = pNodeTypes; \
	PostToKernel(GET_EVT_PARAM_GUIREGISTER(guiPI, valueTmp), true); }
#endif // REGISTER_PARAM_GUI_NODEID

///Register module's parameter with its default value using events and show in GUI
#ifndef REGISTER_PARAM_GUI_NUMBER_INPUT
#define REGISTER_PARAM_GUI_NUMBER_INPUT(paramId, pName, value, minValue, maxValue, increment, pFlags, pDescription) \
	{ REGISTER_PARAM(paramId, pName, value, pDescription); \
	  GUIEnvironment::GUIParamInfo guiPI(paramId, GUIEnvironment::GUIParamInfo::GUI_TYPE_NUMBER_INPUT); \
	  guiPI.minval = minValue; \
	  guiPI.maxval = maxValue; \
	  guiPI.step = increment; \
	  guiPI.flags = pFlags; \
	  PostToKernel(GET_EVT_PARAM_GUIREGISTER(guiPI, value), true); }
#endif // REGISTER_PARAM_GUI_NUMBER_INPUT

///Register GUI group
#ifndef REGISTER_PARAM_GUI_BEGIN_GROUP
#define REGISTER_PARAM_GUI_BEGIN_GROUP(groupName) \
	{ GUIEnvironment::GUIParamGroup guiGroup(groupName, GetName(), wxString::Format(wxT("%lu"), (unsigned long)GetID().GetInstanceID()));\
	  PostToKernel(GET_EVT_PARAM_GUI_BEGIN_GROUP(guiGroup), true); }
#endif // REGISTER_PARAM_GUI_BEGIN_GROUP

///Disable module's parameter GUI control
#ifndef ENABLE_PARAM_GUI_CONTROL
#define ENABLE_PARAM_GUI_CONTROL(_paramId, value) \
	{ _paramId.poolName=VRUT::Module::GetName();\
	  _paramId.instName=wxString::Format(wxT("%lu"), (unsigned long)GetID().GetInstanceID());\
	  GUIEnvironment::GUIParamInfo guiPI; \
	  guiPI.paramID = _paramId; \
	  PostToKernel(GET_EVT_PARAM_GUIENABLE(guiPI, value), true); }
#endif // ENABLE_PARAM_GUI_CONTROL

///Show/hide module's parameter GUI control
#ifndef SHOW_PARAM_GUI_CONTROL
#define SHOW_PARAM_GUI_CONTROL(_paramId, value) \
	{ _paramId.poolName=VRUT::Module::GetName();\
	  _paramId.instName=wxString::Format(wxT("%lu"), (unsigned long)GetID().GetInstanceID());\
	  GUIEnvironment::GUIParamInfo guiPI; \
	  guiPI.paramID = _paramId; \
	  PostToKernel(GET_EVT_PARAM_GUISHOW(guiPI, value), true); }
#endif // SHOW_PARAM_GUI_CONTROL


#include <wx/statbmp.h>
#include <wx/dataobj.h>
#include <wx/dnd.h>
#include <wx/image.h>

namespace VRUT
{
	class CellButtonRenderer : public wxGridCellRenderer
	{
	public:
		// draw a check mark or nothing
		virtual void Draw(wxGrid& grid, wxGridCellAttr& attr, wxDC& dc, const wxRect& rect, int row, int col, bool isSelected)
		{
			wxGridCellRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
			wxRendererNative::Get().DrawPushButton( &grid, dc, rect, 0);
			wxFont font = grid.GetFont();
			dc.SetFont(font);
			int x = rect.x + 10;
			int y = rect.y + 1;
			dc.SetBackgroundMode(wxTRANSPARENT);
			dc.DrawText(grid.GetTable()->GetValue(row, col), x, y);
		}

		// return the checkmark size
		virtual wxSize GetBestSize(wxGrid& grid, wxGridCellAttr& attr, wxDC& dc, int row, int col)
		{
			dc.SetFont(attr.GetFont());
			wxSize size(dc.GetTextExtent(grid.GetCellValue(row, col)));
			size.IncBy(wxSize(15, 2));
			return size;
		}

		virtual wxGridCellRenderer *Clone() const
		{
			return new CellButtonRenderer;
		}
	};
	
    class ParametersWindow : public wxScrolledWindow
    {
    private:
        ParametersWindow(wxWindow * parent, wxWindowID id);
		virtual ~ParametersWindow()
		{
		}

        void beginGroup(const wxString & groupName);

		bool getHasLayout()
		{
			return m_hasLayout;
		}

		void setHasLayout(bool value)
		{
			m_hasLayout = value;
		}

		void setLayoutFile(const wxString & fileName)
		{
			m_layoutFileName = fileName;
		}

		wxWindow* getControlsParent()
		{
			return this;
		}
		wxFlexGridSizer* getGroupSizer()
		{
			return m_groupSizer;
		}

        wxBoxSizer * m_groupBox;
        wxFlexGridSizer * m_groupSizer;

		bool     m_hasLayout;
		wxString m_layoutFileName;

        friend class GUIEnvironment;
    };

	///GUI management for environment parameters
	class GUIEnvironment : public wxAuiNotebook
	{
	public:
		/// Origin identifier for Environment::SetParam()
		static const wxString setParamOriginId;

        struct GUIParamGroup
        {
            GUIParamGroup(const wxString & groupName, const wxString & poolName, const wxString & instanceName)
                :groupName(groupName), poolName(poolName), instanceName(instanceName) {}

            wxString groupName;
            wxString poolName;
            wxString instanceName;
        };

		///Identifier and GUI properties of a parameter
		struct GUIParamInfo
		{
			///Parameter identifier
			Parameter::ParameterIdentifier paramID;
			///GUI control type
			enum GUI_CONTROL_TYPE
			{
				GUI_TYPE_TEXTCONTROL,            ///<Single line text control
				GUI_TYPE_CHECKBOX,               ///<Checkbox control
				GUI_TYPE_SLIDER,                 ///<Slider control
				GUI_TYPE_SPINCONTROL,            ///<Spin control
				GUI_TYPE_SPINCONTROL_DOUBLE,     ///<Spin control for floating point values
				GUI_TYPE_COMBOBOX,               ///<Combobox control
				GUI_TYPE_BUTTON,                 ///<Button control (associated value is number of button pushes)
				GUI_TYPE_TABLE,                  ///<Table control
				GUI_TYPE_COLOURPICKER,			 ///<Colour picker control
				GUI_TYPE_FILECONTROL,			 ///<Single line text control with button opening file dialog
				GUI_TYPE_DROPSOURCE,			 ///<Icon that can be dragged and dropped
				GUI_TYPE_SCENEID,				 ///<SCENE_ID selection GUI element - ComboBox that automatically updates items on click
				GUI_TYPE_NODEID,				 ///<NODE_ID selection GUI element - filtering by type, name, etc. 
				GUI_TYPE_STATICTEXT,			 ///<Static text
				GUI_TYPE_BITMAP,				 ///<Static bitmap
				GUI_TYPE_LISTCONTROL,			 ///<List control
				GUI_TYPE_SHORTCUTPICKER,		 ///<Shortcut picker control
				GUI_TYPE_SCRIPTEDITOR,			 ///<Script editor control
				GUI_TYPE_PANEL,					 ///<Panel
				GUI_TYPE_NUMBER_INPUT,			 ///<Input field for floating-point number
			} type;
			///Action which shall be performed with data
			enum ACTION_TYPE
			{
				ACTION_DEFAULT,		///<Default action - create or override data
				ACTION_ADD_ROWS,	///<Add/append new rows
				ACTION_REMOVE_ROWS,	///<Remove rows
				ACTION_UPDATE_ROWS,	///<Update rows
			} action;
			///Min value (if applicable)
			double minval;
			///Max value (if applicable)
			double maxval;
			///Step value (if applicable)
			double step;
			///List of selectable values (if applicable)
			wxArrayString values;

			wxString fileMode;
			wxString wildcard;

			SCENE_ID sceneID;
			SceneNode::TypeMask nodeTypes;

			wxDataObjectSimple *dataObject;

			///Colour dialog mode (if applicable)
			ColourDialog::DialogMode dialogMode;

			/// Flags (if applicable)
			long flags;

			///Constructor
			GUIParamInfo() : paramID(), type(GUI_TYPE_TEXTCONTROL), action(ACTION_DEFAULT), minval(0.0), maxval(100.0), step(1.0), sceneID(SCENE_ID_NONE), nodeTypes(SceneNode::ALL_SCENE_TYPES_MASK), dataObject(NULL), dialogMode(ColourDialog::DialogMode::EE_COLOUR_DIALOG_ALPHA), flags(0) {}
			///Constructor
			GUIParamInfo(const Parameter::ParameterIdentifier & _paramID, GUI_CONTROL_TYPE _type)
					: paramID(_paramID), type(_type), action(ACTION_DEFAULT), minval(0.0), maxval(100.0), step(1.0), sceneID(SCENE_ID_NONE), nodeTypes(SceneNode::ALL_SCENE_TYPES_MASK), dataObject(NULL), dialogMode(ColourDialog::DialogMode::EE_COLOUR_DIALOG_ALPHA), flags(0) {}
			///Copy constructor
			/*
			GUIParamInfo(const GUIParamInfo & guiPI) : paramID(guiPI.paramID), type(guiPI.type), step(guiPI.step), fileMode(fileMode), values(guiPI.values) {minval = guiPI.minval, maxval = guiPI.maxval;}*/
		};

	protected:
		///Hash map type mapping parameter fullname to GUI parameter info
		WX_DECLARE_STRING_HASH_MAP(GUIParamInfo, GUIInfoList);
		///Hash map mapping parameter fullname to GUI parameter info
		GUIInfoList controlsInfo;

		/// variable indicating whether we are inserting the controls in a batch mode
		/// in which no updates are computed until leaveBatchMode is called
		bool batchMode;

		std::vector<ParametersWindow *> undockedWindows;
		
		///Help function for preparing table control
		void FillGrid(wxGrid *control, const wxArrayString &values, bool updateExisting=false);

		ParametersWindow *getParametersWindow(const wxString &nameMask)
		{
			for (size_t pg = 0; pg < GetPageCount(); ++pg)
			{
				if (GetPageText(pg).IsSameAs(nameMask))
					return (ParametersWindow *)GetPage(pg);
			}
			for (size_t pg = 0; pg < undockedWindows.size() ; ++pg)
			{
				if (undockedWindows[pg]->GetParent()->GetLabel().IsSameAs(nameMask))
					return undockedWindows[pg];
			}
			return NULL;
		}

		ParametersWindow* createParametersWindow(const wxString& poolInstName, wxWindow* parent);

		///On command event
		void onCommandEvent(wxCommandEvent & evt);

		void onPageClose(wxAuiNotebookEvent & evt);
		void onUndock(wxAuiNotebookEvent & evt);
		void undock(int pageID)
		{
			if (pageID > 0)
			{
				wxString moduleName(GetPageText(pageID));
				wxWindow *page = GetPage(pageID);
				wxWindow *frame = new wxFrame(KERNEL->GetMainWindow(), wxID_ANY, moduleName);

				page->Reparent(frame);
				page->Show();
				RemovePage(pageID);
				undockedWindows.push_back((ParametersWindow *)page);
				size_t pos=moduleName.rfind(wxT('.'));
				if ((pos > 0) && (pos < moduleName.size()))
					moduleName = moduleName.substr(0, pos);
				KERNEL->WinPosSizeFromVRUTConfig(frame, wxT("/") + moduleName + wxT("/"), wxPoint(0, 0), wxSize(500, 400));
				frame->Show();
				frame->Connect(frame->GetId(), wxEVT_CLOSE_WINDOW, wxCloseEventHandler(GUIEnvironment::OnUndockedClose), (wxObject *)NULL, this);
			}
		}
		void OnUndockedClose(wxCloseEvent & evt);

	public:
		///Class constructor
		GUIEnvironment(wxWindow * parent);
		///Class destructor
		~GUIEnvironment()
		{
		}

		///Find GUI control for given parameter, \c NULL if not found
		wxWindow * GetControl(const Parameter::ParameterIdentifier & paramID);
		///Show matching previously registered parameters in GUI if hidden ('?' and '*' allowed)
		void ShowParams(const Parameter::ParameterIdentifier & paramID);
		///Hide matching pages with parameters if shown ('?' and '*' allowed, \c guiPI.paramName must be '*')
		///\param[in] paramID Parameter identifier (\c paramID.paramName has to be '*' or nothing happens)
		///\param[in] unregister If \c true parameter is unregistered and cannot be unhidden later
		void HideParams(const Parameter::ParameterIdentifier & paramID, bool unregister = false);
		///Register new parameter into GUI or show if already registered
		///\param[in] paramInfo Parameter full identifier and GUI properties
		///\param[in] value Initial value
		///\return \c true if successful
		bool RegisterGUIParam(const GUIParamInfo & paramInfo, const wxString & value);
		///Enable or disable a GUI control
		///\param[in] paramInfo Parameter full identifier and GUI properties
		///\param[in] value Initial value
		///\return \c true if successful
		bool EnableGUIControl(const GUIParamInfo & paramInfo, const bool enable);
		///Show or hide a GUI control
		///\param[in] paramInfo Parameter full identifier and GUI properties
		///\param[in] value Initial value
		///\return \c true if successful
		bool ShowGUIControl(const GUIParamInfo & paramInfo, const bool show);
		///Change GUI parameter properties
		///\param[in] paramInfo Parameter full identifier and GUI properties
		///\param[in] value Initial value
		///\return \c true if successful
		bool ChangeGUIParam(const GUIParamInfo & paramInfo, const wxString & value);
		///Set parameter's value in its GUI control
		void SetParam(const Parameter::ParameterIdentifier & paramID, const wxString & value);

		/// in batch mode no updates are computed until leaveBatchMode is called
		void EnterBatchMode();
		void LeaveBatchMode();

        void BeginGUIParamGroup(const GUIParamGroup & groupInfo);
		void SetLayout(const Parameter::ParameterIdentifier & paramID, const wxString & layoutFileName);

		void StoreUserPerspective();
		void DockAll();
	};

	class Grid : public wxGrid
	{
	public:
		Grid(wxWindow *parent, wxWindowID id, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize, long style = 262144L, const wxString &name = wxGridNameStr) : wxGrid(parent, id, pos, size, style, name)
		{}

		bool SetCurrentCell(int row, int col)
		{
#if wxCHECK_VERSION(2, 9, 1)
			return wxGrid::SetCurrentCell(row, col);
#else
			wxGrid::SetCurrentCell(row, col);
			return true;
#endif
		}
	};

}

#endif
