/*
 *  psychlops_widgets_prototype.h
 *  Psychlops Standard Library (Universal)
 *
 *  Last Modified 2009/02/15 by Kenchi HOSOKAWA
 *  (C) 2009 Kenchi HOSOKAWA, Kazushi MARUYA, Takao SATO
 */

#ifndef HEADER_PSYCHLOPS_WIDGET
#define HEADER_PSYCHLOPS_WIDGET

#include <string>
#include "../../../core/graphic/psychlops_g_module.h"
#include "../../../psychlops_core.h"
#include "../psychophysics/psychlops_exp_psychophysics.h"


namespace Psychlops {

	class Widget : public Figure {
	public:
		class Event {
		public:
		};
	};


namespace Widgets {

	struct Theme {
		static bool initialized__;
		static Image default_button, default_horiz_grad;
		enum TYPE_TAG { NORMAL, ALERT };
		public:
		Color normal_foreground[2], active_foreground[2];
		Color normal_background[2], active_background[2], over_background[2];
		Stroke normal_stroke[2], active_stroke[2];
		Image *button_back, *horiz_grad;

		static Theme current;
		static void initialize();
	};

	Point drawableMouse(Drawable &d);

	class WidgetDatum : public Widget {
	public:
		Point datum;
		WidgetDatum();
		~WidgetDatum();
		virtual const Point getDatum() const;
		virtual WidgetDatum& setDatum(const Point&);
		virtual WidgetDatum& centering(const Point&);
		using Figure::centering;
	};

	class WidgetRect : public Widget {
		protected:
		HumanInterfaceDevice::ButtonStateHolder mleft;
		bool pushed_;

		public:
		Theme *theme;
		Theme::TYPE_TAG theme_type;
		Rectangle area;
		Letters label;

		WidgetRect();
		virtual const Point getDatum() const;
		virtual WidgetRect& setDatum(const Point&);
		virtual WidgetRect& centering(const Point&);
		using Figure::centering;
		double getWidth() const;
		double getHeight() const;
		double getLeft() const;
		double getTop() const;
		double getRight() const;
		double getBottom() const;
		WidgetRect& alignLeft(const double lef);
		WidgetRect& alignTop(const double to_);
		WidgetRect& alignRight(const double rig);
		WidgetRect& alignBottom(const double bot);

		virtual WidgetRect& set(double wid, double hei);
		virtual WidgetRect& set(std::wstring name);
		virtual WidgetRect& set(std::wstring name, double hei);
		virtual WidgetRect& setLabel(std::wstring s);
		virtual WidgetRect& draw(Drawable &target = *Drawable::prime);
		bool pushed();
		WidgetRect& pushThis();
	};

	class StackPanel : public WidgetRect {
	protected:
		std::deque< WidgetRect* > content;
	public:
		enum Orientation { VERTICAL, HORIZONTAL };
		Orientation orientation;
		bool forceBase, forceAnother;

		double pitch;
		StackPanel();
		StackPanel& setWidth(double wid);
		StackPanel& setHeight(double hei);
		StackPanel& append(WidgetRect *target1, WidgetRect *target2=0, WidgetRect *target3=0, WidgetRect *target4=0, WidgetRect *target5=0);
		void align(Orientation ori = VERTICAL);
		virtual StackPanel& draw(Drawable &target = *Drawable::prime);
	};

	class TextBox : public WidgetRect {
	protected:
		void setBase();
		Letters cache;
		std::wstring content;
	public:
		TextBox();
		TextBox(std::wstring s);
		virtual TextBox& set(std::wstring s);
		virtual TextBox& draw(Drawable &target = *Drawable::prime);
		void setText(const std::wstring &str);
		std::wstring& getText();
	};

	class Button : public WidgetRect {
	protected:
		void (*onClick)();
		void (*onClickP)(void *);
		void setBase();
	public:
		void *arg;
		Button();
		Button(std::wstring s);
		Button(std::wstring s, double size);
		virtual Button& set(std::wstring s, double hei = Font::default_font.size);
		virtual Button& draw(Drawable &target = *Drawable::prime);
	};

	class ToggleButton : public Button {
	protected:
		bool checked_;
	public:
		ToggleButton();
		ToggleButton(std::wstring s);
		ToggleButton(std::wstring s, double size);
		bool toggle();
		bool toggle(bool on_off);
		bool isChecked();
		virtual ToggleButton& draw(Drawable &target = *Drawable::prime);
	};

	class ScreenShotButton : public Button {
	protected:
		static void shoot(void *fname);
		static Image buffer;
	public:
		std::string name;
		ScreenShotButton(char *name);
	};

	class Slider : public WidgetRect {
	protected:
		bool dragged;
		double local;
		ExperimentalMethods::Variable *var;
		bool changed_;
		void setBase();
	public:
		Rectangle internal;
		bool show_value;

		Slider();
		~Slider();
		Slider(double wid, double hei);
		template<typename T, typename S> Slider(T &item, Interval rng, S d_step = 0.125, S e_step = 10)
		{
			setBase();
			set(160,12);
			ExperimentalMethods::VariableInstance<T>* v = new ExperimentalMethods::VariableInstance<T>(&item);
			v->set("", rng, d_step, e_step);
			var = v;
		}
		virtual Slider& set(double wid, double hei);
		virtual Slider& set(std::wstring s, double hei = Font::default_font.size);
		virtual Slider& setLabel(std::wstring s);
		virtual Slider& draw(Drawable &target = *Drawable::prime);
		template<typename T, typename S> Slider& link(T &item, Interval rng, S d_step = 0.125, S e_step = 10)
		{
			ExperimentalMethods::VariableInstance<T>* v = new ExperimentalMethods::VariableInstance<T>(&item);
			v->set("", rng, d_step, e_step);
			var = v;
			return *this;
		}
		bool changed();
		operator double();
		double operator =(double v);
		void setByRatio(double ratio);
		double getRatio() const;
		Interval getInterval() const;
		Interval setInterval(const Interval &itvl);
		void increment(int modulation = 0);
		void decrement(int modulation = 0);
	};

	class Dial : public WidgetDatum {
	protected:
		Rectangle ext, internal;
		Letters let;
		double current_theta, former_theta, factor, local;
		double *var;
		bool pressed, dragged;
		bool changed_;
	public:
		Dial();
		Dial(double r);
		void setBase();
		Dial& label(std::wstring s);
		Dial& set(double r);
		Dial& draw(Drawable &target = *Drawable::prime);
		Dial& link(double &item, double fac = 1)
		{
			var = &item;
			factor = fac;
			let.align = Letters::TEXT_ALIGN_CENTER;
			return *this;
		}
		bool changed();
		operator double();
		double operator =(double v);
	};

	class SelectBox : public WidgetRect
	{
		protected:
		std::deque<Letters> item;
		int selected_;
		bool vertical_;
		Group holder_;
		void appendL(Letters &let);

		public:
		SelectBox();
		SelectBox(double hei);
		SelectBox& set(double hei);
		SelectBox& set(double wid, double hei);
		void makeVertical();
		template<class T> void append(T arg)
		{
			Letters let(arg);
			appendL(let);
		}
		int getSelected();
		void setSelected(int dd);
		void next();
		void retreat();
		void hid();
		virtual SelectBox& draw(Drawable &target = *Drawable::prime);
	};


	class CloseButton : public Button
	{
		protected:
		public:
		CloseButton();
		static void exitApp();
	};

	class MinimizeButton : public Button
	{
		protected:
		Canvas* window;
		public:
		MinimizeButton(Canvas &target);
		static void minimizeApp(void *hwnd);
	};

	class TitleBar : public WidgetDatum
	{
	public:
		static TitleBar *default_titlebar;

	protected:

		CloseButton close;
		MinimizeButton minimize;
		Rectangle area;
		HumanInterfaceDevice::ButtonStateHolder mleft;
		Point begin_m, begin_w, begin_w_size;

		bool dragged_;
		public:
		TitleBar(Canvas &target);
		TitleBar& draw(Drawable &target = *Drawable::prime);
	};



namespace Dialog {

	void alert(std::string message);
	void alert(std::wstring message);
	std::string getOpenFileName();

}	/*	<- namespace Dialog 	*/


}	/*	<- namespace Widgets 	*/
}	/*	<- namespace Psycholops 	*/


#endif
