#ifndef __NUMBER_INPUT_H__
#define __NUMBER_INPUT_H__

#include <cmath>

#include <wx/popupwin.h>
#include <wx/window.h>
#include <wx/xrc/xmlres.h>
#include <wx/compositewin.h>

#include "kernel.h"

#ifdef USE_wxDEFINE_EVENT
wxDECLARE_EXPORTED_EVENT(VRUT_CORE_API, EVT_NUMBER_INPUT, wxCommandEvent);
#endif

namespace VRUT
{
	class SliderDouble;

	class NumberInputPopup : public wxPopupWindow
	{
	private:
		wxStaticText *staticText;
		wxBoxSizer *topSizer;
		wxPanel *panel;

	public:
		NumberInputPopup(wxWindow *parent, const wxString &text = wxEmptyString);
		void SetText(const wxString &text);
	};

	class VRUT_CORE_API NumberInput : public wxCompositeWindow<wxWindow>
	{
		// Public types
	public:
		typedef double NumberType;

		// Flags for customization of NumberInput
		enum {
			FLAG_SLIDER_LINEAR = 1 << 0,
		};

		// Data members
	private:
		wxBoxSizer *m_sizer;
		wxStaticText *m_staticText;
		wxTextCtrl *m_textCtrl;
		SliderDouble *m_slider;
		NumberInputPopup *m_popup;

		NumberType m_minValue;
		NumberType m_maxValue;
		NumberType m_value;
		
		NumberType m_valueIncrement;

		NumberType m_dragStartValue;
		int m_dragStartX;
		bool m_isDragging;

		long m_flags;

		// Public Methods
	public:
		
		NumberInput();
		
		NumberInput(wxWindow *parent, wxWindowID id, const wxString &title = wxEmptyString, NumberType minValue = std::numeric_limits<NumberType>::lowest(), NumberType maxValue = std::numeric_limits<NumberType>::max(), NumberType value = 0.0, NumberType valueIncrement = 1.0, long flags = 0, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0, const wxString& name = wxEmptyString);

		bool Create(wxWindow *parent, wxWindowID id, const wxString &title = wxEmptyString, NumberType minValue = std::numeric_limits<NumberType>::lowest(), NumberType maxValue = std::numeric_limits<NumberType>::max(), NumberType value = 0.0, NumberType valueIncrement = 1.0, long flags = 0, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0, const wxString& name = wxEmptyString);

		NumberType GetValue() const;

		wxString GetTextValue() const;

		void SetValue(NumberType value);

		void SetValue(const wxString &textValue);

		void SetRange(NumberType minValue, NumberType maxValue);

		void SetIncrement(NumberType valueIncrement);

		long GetFlags() const;

		void SetFlags(long flags);

		void SetSliderWidth(int width);

		// Private methods
	private:

		void InitEmpty();
		void Init(const wxString &title = wxEmptyString, NumberType minValue = std::numeric_limits<NumberType>::lowest(), NumberType maxValue = std::numeric_limits<NumberType>::max(), NumberType value = 0.0, NumberType valueIncrement = 1.0, long flags = 0);

		void SetValueWithEvent(NumberType value, bool sendEvent = true);
		void UpdateValueFromTextCtrl();
		void UpdateGui();
		void UpdateFlags();

		wxString ValueToText(NumberType value) const;
		bool TextToValue(const wxString &text, NumberType &value) const;

		// Truncate value to the range
		NumberType ValidateValue(NumberType value) const;

		// Calculates new value for step.
		NumberType NewValue(NumberType value, NumberType step) const;
		NumberType NewValueIncrement(NumberType valueIncrement, int change) const;

		// Popup methods
		void ShowIncrementPopup();
		void ShowPopup(const wxString &text);
		void HidePopup();

		// Event handlers
		void OnTextChange(wxCommandEvent &evt);
		void OnMouseWheel(wxMouseEvent &evt);
		void OnMouseMove(wxMouseEvent &evt);
		void OnMouseButton(wxMouseEvent &evt);
		void OnMouseCaptureLost(wxMouseCaptureLostEvent &evt);
		void OnKeyDown(wxKeyEvent &evt);
		void OnKeyUp(wxKeyEvent &evt);
		void OnKillFocus(wxFocusEvent &evt);
		void OnSlider(wxCommandEvent &evt);

		// wxCompositeWindow override methods
		virtual wxWindowList GetCompositeWindowParts() const;

		wxDECLARE_DYNAMIC_CLASS(NumberInput);
	};

	class NumberInputXmlHandler : public wxXmlResourceHandler
	{
	public:
		NumberInputXmlHandler();
		virtual wxObject *DoCreateResource();
		virtual bool CanHandle(wxXmlNode *node);

		wxDECLARE_DYNAMIC_CLASS(NumberInputXmlHandler);
	};

}

#endif /* __NUMBER_INPUT_H__ */
