#ifndef __NODEIDCONTROL_H__
#define __NODEIDCONTROL_H__

#include <wx/wx.h>
#include <wx/combobox.h>
#include <wx/popupwin.h>
#include <wx/xrc/xmlres.h>

#include "kernel.h"
#include "scenemanager.h"
#include "eventhandler.h"


namespace VRUT
{
	class NodeIDControl;

	class NodeIDDetailPopup : public wxPopupTransientWindow
	{
	private:

		wxScrolledWindow *m_panel;
		std::vector<wxCheckBox *> typeFilters;

	public:

		NodeIDDetailPopup(wxWindow *parent, SceneNode::TypeMask nodeTypes, int controlMode) : wxPopupTransientWindow(parent, wxBORDER_NONE)
		{
			m_panel = new wxScrolledWindow(this, wxID_ANY);
			m_panel->SetBackgroundColour(*wxLIGHT_GREY);
			wxBoxSizer *topSizer = new wxBoxSizer(wxVERTICAL);
			const wxString typeFilterNames[] = {wxT("Assembly"), wxT("Root"), wxT("Camera"), wxT("Geometry"), wxT("Light"), wxT("LOD"), wxT("Switch"), wxT("Background"), wxT("SoundSource"), wxT("")};

			for (size_t i=0; !typeFilterNames[i].empty(); ++i)
			{
				typeFilters.push_back(new wxCheckBox(m_panel, wxID_ANY, typeFilterNames[i]));
				typeFilters[i]->SetValue(((1<<i) & nodeTypes)!=0);
				topSizer->Add(typeFilters[i], 0, wxALL, 5);
			}

			typeFilters.push_back(new wxCheckBox(m_panel, wxID_ANY, wxT("Auto from node")));
			typeFilters[typeFilters.size()-1]->SetValue(((1<<0) & controlMode)!=0);
			topSizer->Add(typeFilters[typeFilters.size()-1], 0, wxALL, 5);

			m_panel->SetSizer(topSizer);
			topSizer->Fit(m_panel);
			topSizer->Fit(this);
		}

		void OnDismiss();
	};

	class NodeIDControl : public wxComboBox
	{
	private:

		SCENE_ID sceneID;
		SceneNode::TypeMask nodeTypes;
		int controlMode;

		wxString formatChoice(NODE_ID nodeID, const wxString &nodeName)
		{
			return wxString::Format(wxT("%lu ("), (unsigned long)nodeID)+nodeName+wxT(")");
		}

		wxString formatChoice(NODE_ID nodeID)
		{
			smart_pointer_v2<Scene> scene;
			KERNEL->sceneManager->GetScene(scene, sceneID);
			if (scene)
			{
				smart_pointer<SceneNode> node;
				scene->GetNode(node, nodeID);
				if (node)
					return formatChoice(nodeID, node->GetName());
			}
			return formatChoice(nodeID, wxT("NoneNode"));
		}

		void OnLeftDown(wxMouseEvent &evt)
		{
			int selNodeID;
			if (GetStringSelection() != wxT(""))
				TextParser(GetStringSelection().utf8_str()).ParseInt(&selNodeID);
			else
				TextParser(GetValue().utf8_str()).ParseInt(&selNodeID);

			Clear();
			wxArrayString tmpList;
			tmpList.push_back(formatChoice(NODE_ID_NONE));
			int selection = 0;
			smart_pointer_v2<Scene> scene;
			KERNEL->sceneManager->GetScene(scene, sceneID);
			if (scene)
			{
				std::vector<smart_pointer<SceneNode> > nodes;
				scene->GetNodesByType(nodes, nodeTypes);
				for (size_t i = 0; i < nodes.size(); i++)
				{
					tmpList.push_back(formatChoice(nodes[i]->GetID(), nodes[i]->GetName()));
					if ((NODE_ID)selNodeID == nodes[i]->GetID())
						selection = i + 1;
				}
			}
			Append(tmpList);
			SetSelection(selection);
			evt.Skip();
		}

		void OnRightDown(wxMouseEvent &evt)
		{
			NodeIDDetailPopup *detailPopup = new NodeIDDetailPopup(this, nodeTypes, controlMode);
			wxWindow *btn = (wxWindow*) evt.GetEventObject();
			wxPoint pos = btn->ClientToScreen(wxPoint(0,0));
			wxSize sz = btn->GetSize();
			detailPopup->Position(pos, sz);
			detailPopup->Popup(this);
			evt.Skip();
		}

		void OnItemSelected(wxCommandEvent &evt)
		{
			wxWindow * win = dynamic_cast<wxWindow *>(evt.GetEventObject());
			Parameter::ParameterIdentifier pi = Parameter::ParameterIdentifier::FromParamName(win->GetName());
			//KERNEL->environment.SetParam(pi, evt.GetString());
			KERNEL->GetMessageSink()->PostEvent(GET_EVT_PARAM_SET(pi, evt.GetString()));
		}

		void LocalInit(void)
		{
			this->Connect(wxID_ANY, wxEVT_LEFT_DOWN, wxMouseEventHandler(NodeIDControl::OnLeftDown), NULL, this);
			this->Connect(wxID_ANY, wxEVT_RIGHT_DOWN, wxMouseEventHandler(NodeIDControl::OnRightDown), NULL, this);
			this->Connect(wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler(NodeIDControl::OnItemSelected), NULL, this);
			this->Connect(wxID_ANY, wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler(NodeIDControl::OnItemSelected), NULL, this);
			//this->SetSelection(0);
		}

	protected:

		void SetControlMode(int newControlMode);

	public:

		// Default constructor (required for two-step construction when loading from XRC => default contructor -> create)
		NodeIDControl() : wxComboBox(), sceneID(SCENE_ID_NONE), nodeTypes(SceneNode::ALL_SCENE_TYPES_MASK), controlMode(0) {}

		bool Create( wxWindow *parent, wxWindowID id, const wxString &	value, const wxPoint & pos,	const wxSize & size, const wxArrayString & choices, long style = 0, const wxValidator &	validator = wxDefaultValidator, const wxString & name = wxComboBoxNameStr )
		{
			 if ( !wxComboBox::Create(parent, id, value, pos, size, choices, style, validator, name) )
				return false;

			sceneID = SCENE_ID_NONE;
			nodeTypes = SceneNode::ALL_SCENE_TYPES_MASK;

			LocalInit();

			return true;
		}

		NodeIDControl(wxWindow *parent, wxWindowID id, const wxString &value, const wxPoint &pos, const wxSize &size, const wxArrayString &choices, long style=0, const wxValidator &validator=wxDefaultValidator,
			const wxString &name=wxComboBoxNameStr, SCENE_ID sceneID=SCENE_ID_NONE, int nodeTypes = SceneNode::ALL_SCENE_TYPES_MASK)
			: wxComboBox(parent, id, value, pos, size, choices, style, validator, name), sceneID(sceneID), nodeTypes(nodeTypes), controlMode(0)
		{
			LocalInit();
		}

		virtual void SetValue(const wxString& value)
		{
			if (value.empty())
				return;

			int valNodeID;
			TextParser(value.utf8_str()).ParseInt(&valNodeID);
			wxString nodeStr(formatChoice((NODE_ID)valNodeID));
			wxArrayString choices = GetStrings();

			for (size_t i = 0; i < choices.size(); i++)
			{
				int choiceNodeID;
				TextParser(choices[i].utf8_str()).ParseInt(&choiceNodeID);
				if (choiceNodeID == valNodeID)
				{
					if (choices[i] != nodeStr) //workaround for wxWidgets 3.0 and gtk
						wxComboBox::SetString(i, nodeStr);
					wxComboBox::SetSelection(i);
					//wxComboBox::SetValue(choices[i]);
					return;
				}
			}

			wxComboBox::Append(nodeStr);
			wxComboBox::SetValue(nodeStr);
		}

		void SetNodeTypes(SceneNode::TypeMask _nodeTypes)
		{
			nodeTypes = _nodeTypes;
		}

		void SetSceneID(SCENE_ID _sceneID)
		{
			sceneID = _sceneID;
		}

		friend class NodeIDDetailPopup;

		DECLARE_DYNAMIC_CLASS(NodeIDControl) 
	};

	class NodeIDControlXmlHandler : public wxXmlResourceHandler
	{
	public:
		// Constructor.
		NodeIDControlXmlHandler()
		{
			XRC_ADD_STYLE(wxCB_SIMPLE);
			XRC_ADD_STYLE(wxCB_SORT);
			XRC_ADD_STYLE(wxCB_READONLY);
			XRC_ADD_STYLE(wxCB_DROPDOWN);
			XRC_ADD_STYLE(wxTE_PROCESS_ENTER);

			AddWindowStyles();
		}

		// Creates the control and returns a pointer to it.
		virtual wxObject *DoCreateResource()
		{
			XRC_MAKE_INSTANCE(control, NodeIDControl)

			wxArrayString choices;

			control->Create( m_parentAsWindow,
				GetID(),
				GetText(wxT("value")),
				GetPosition(), GetSize(), 
				choices,
				GetStyle() | wxCB_READONLY, 
				wxDefaultValidator,
				GetName() );	

			// find the selection
			long selection = GetLong( wxT("selection"), -1 );
			if (selection != -1)
				control->SetSelection(selection);

			SetupWindow(control);

			return control;
		}

		// Returns true if we know how to create a control for the given node.
		virtual bool CanHandle(wxXmlNode *node)
		{
			return IsOfClass(node, wxT("NodeIDControl"));
		}

		// Register with wxWidgets' dynamic class subsystem.
		DECLARE_DYNAMIC_CLASS(NodeIDControlXmlHandler)
	};

}

#endif /* __NODEIDCONTROL_H__*/
