/* vim: set noexpandtab shiftwidth=8 cino=: */
#ifndef _VGUI_WHEEL_H
#define _VGUI_WHEEL_H

/* slider.h */
#include "gui.h"

namespace VGUI
{
	template<class wheel_t>
	class Wheel : public Widget
	{
	private:
		TEXTURE_HANDLE l_arrow_up, r_arrow_up, l_arrow_down, r_arrow_down;
		string setting;
		string wgt_hook;
		vector<string> option_list;
		vector<wheel_t> value_list;
		unsigned int cur_option, default_option;
		bool l_down, r_down, saved;
		float tex_width, tex_height, spacing;

	public:
		Wheel() { }
		Wheel( Widget* w );
		~Wheel();
		void Draw();
		void Draw( float opacity );
		void Save();
		bool MouseOver( float x, float y );
		string MousePress( float x, float y );
		string MouseRelease( float x, float y );
		void ResetValue();

		vector<string> GetOptionList() { return option_list; }
		void GetValueList( vector<wheel_t> &vw ) { vw = value_list; }
		wheel_t GetValue() { return value_list[cur_option]; }
		wheel_t GetDefaultValue() { return value_list[default_option]; }
		string GetSetting() { return setting; }
		float GetSpacing() { return spacing; }
		string GetHook() { return wgt_hook; }
		bool GetSaved() { return saved; }
		void SetOptionList( vector<string> new_option_list ) { option_list = new_option_list; }
		void SetValueList( vector<wheel_t> new_value_list ) { value_list = new_value_list; }
		void SetValue( wheel_t new_value ) { for( unsigned int i = 0; i < value_list.size(); i++ ) if( value_list[i] == new_value ) cur_option = i; }
		void SetDefaultValue( wheel_t new_value ) { for( unsigned int i = 0; i < value_list.size(); i++ ) if( value_list[i] == new_value ) default_option = i; }
		void SetSetting( string new_setting ) { setting = new_setting; }
		void SetSpacing( float new_spacing );
		void SetHook( string new_hook ) { wgt_hook = new_hook; }
		void SetSaved( bool new_saved ) { saved = new_saved; }
		void IncValuePress();
		void DecValuePress();
		void IncValueRelease();
		void DecValueRelease();
		void Release();
	};

	template<class wheel_t1, class wheel_t2>
	class Wheel2 : public Widget
	{
	private:
		TEXTURE_HANDLE l_arrow_up, r_arrow_up, l_arrow_down, r_arrow_down;
		string setting_1, setting_2;
		vector<string> option_list;
		vector<wheel_t1> value_list_1;
		vector<wheel_t2> value_list_2;
		unsigned int cur_option, default_option;
		bool l_down, r_down;
		float tex_width, tex_height, spacing;

	public:
		Wheel2() { }
		Wheel2( Widget* w );
		~Wheel2();
		void Draw();
		void Draw( float opacity );
		void Save();
		bool MouseOver( float x, float y );
		string MousePress( float x, float y );
		string MouseRelease( float x, float y );
		void ResetValue();

		vector<string> GetOptionList() { return option_list; }
		vector<int> GetValueList1() { return value_list_1; }
		vector<int> GetValueList2() { return value_list_2; }
		wheel_t1 GetValue1() { return value_list_1[cur_option]; }
		wheel_t2 GetValue2() { return value_list_2[cur_option]; }
		wheel_t1 GetDefaultValue1() { return value_list_1[default_option]; }
		wheel_t2 GetDefaultValue2() { return value_list_2[default_option]; }
		string GetSetting1() { return setting_1; }
		string GetSetting2() { return setting_2; }
		float GetSpacing() { return spacing; }
		void SetOptionList( vector<string> new_option_list ) { option_list = new_option_list; }
		void SetValueList1( vector<wheel_t1> new_value_list ) { value_list_1 = new_value_list; }
		void SetValueList2( vector<wheel_t2> new_value_list ) { value_list_2 = new_value_list; }
		void SetValue1( wheel_t1 new_value ) { for( unsigned int i = 0; i < value_list_1.size(); i++ ) if( value_list_1[i] == new_value ) cur_option = i; }
		void SetValue2( wheel_t2 new_value ) { for( unsigned int i = 0; i < value_list_2.size(); i++ ) if( value_list_2[i] == new_value ) cur_option = i; }
		void SetDefaultValue1( wheel_t1 new_value ) { for( unsigned int i = 0; i < value_list_1.size(); i++ ) if( value_list_1[i] == new_value ) default_option = i; }
		void SetDefaultValue2( wheel_t2 new_value ) { for( unsigned int i = 0; i < value_list_2.size(); i++ ) if( value_list_2[i] == new_value ) default_option = i; }
		void SetSetting1( string new_setting ) { setting_1 = new_setting; }
		void SetSetting2( string new_setting ) { setting_2 = new_setting; }
		void SetSpacing( float new_spacing );
		void IncValuePress();
		void DecValuePress();
		void IncValueRelease();
		void DecValueRelease();
		void Release();
	};

	template<class wheel_t>
	Wheel<wheel_t>::Wheel( Widget* w )
	{
		setting = "";
		wgt_hook = "";
		cur_option = default_option = 0;
		center = w->GetCenter();
		name = w->GetName();
		text = w->GetText();
		type = w->GetType();
		tip = w->GetTip();
		rel_width = w->GetRelWidth();
		rel_height = w->GetRelHeight();
		enabled = w->GetEnabled();
		selected = w->GetSelected();
		is_default = w->GetDefault();
		is_cancel = w->GetCancel();
		has_icon = w->GetHasIcon();
		width_auto = w->GetWidthAuto();
		height_auto = w->GetHeightAuto();
		font_size = w->GetFontSize();
		color_r = w->GetColorR();
		color_g = w->GetColorG();
		color_b = w->GetColorB();
		l_down = false;
		r_down = false;
		spacing = 0.3;
		saved = true;

		string skin_path = settings.GetSkinPath();
		l_arrow_up.Load( skin_path + "/textures/widgets/wheel_up_l.png", false );
		l_arrow_down.Load( skin_path + "/textures/widgets/wheel_down_l.png", false );
		r_arrow_up.Load( skin_path + "/textures/widgets/wheel_up_r.png", false );
		r_arrow_down.Load( skin_path + "/textures/widgets/wheel_down_r.png", false );

		tex_width = 0.0277;
		tex_height = 0.0370;

		// width = dist from left of text to wheel + width of wheel + texture width
		if( width_auto )
		{
			rel_width = spacing + 0.15 + tex_width;
		}

		// height = button texture height
		if( height_auto )
		{
			rel_height = tex_height;
		}
	}

	template<class wheel_t>
	Wheel<wheel_t>::~Wheel()
	{
	}

	template<class wheel_t>
	void Wheel<wheel_t>::SetSpacing( float new_spacing )
	{
		spacing = new_spacing;
		rel_width = spacing + 0.15 + tex_width;
	}

	template<class wheel_t>
	void Wheel<wheel_t>::Save()
	{
		default_option = cur_option;
		if( value_list.size() == 0 )
		{
			cout << "No values, can't save setting: " << setting << endl;
			return;
		}
		if( saved )
			settings.Set( setting, value_list[cur_option] );
	}

	template<class wheel_t>
	void Wheel<wheel_t>::ResetValue()
	{
		wheel_t default_val;
		if( saved )
		{
			settings.Get( setting, default_val );
			SetValue( default_val );
		}
		else
		{
			cur_option = default_option;
		}
	}

	template<class wheel_t>
	void Wheel<wheel_t>::Draw()
	{
		Draw( 1.0 );
	}

	template<class wheel_t>
	void Wheel<wheel_t>::Draw( float opacity )
	{
		int wheel_font_size = font_size;
		float center_x = center.GetXPercent();
		float center_y = center.GetYPercent();
		float rel_width_half = rel_width / 2.0f;
		float rel_height_half = rel_height / 2.0f;
		float wheel_center = spacing + tex_width + ( ( 0.15 - tex_width ) / 2.0f );
		TEXTURE_HANDLE * t1 = l_down ? &l_arrow_down : &l_arrow_up;
		TEXTURE_HANDLE * t2 = r_down ? &r_arrow_down : &r_arrow_up;
		float l_opacity = ( !enabled || ( cur_option == 0 ) ) ? 0.4 : selected ? 0.9 : 0.75;
		float r_opacity = ( !enabled || ( cur_option == option_list.size() - 1 ) ) ? 0.4 : selected ? 0.9 : 0.75;
		string cur_option_txt = ( option_list.size() == 0 ) ? "" : _(option_list[cur_option]);

		// draw arrow images
		utility.Draw2D( center_x - rel_width_half + spacing,
				center_y - rel_height_half,
				center_x - rel_width_half + spacing + tex_width,
				center_y + rel_height_half,
				t1, 0.0, 0, l_opacity * opacity );
		utility.Draw2D( center_x - rel_width_half + spacing  + 0.15,
				center_y - rel_height_half,
				center_x - rel_width_half + spacing  + 0.15 + tex_width,
				center_y + rel_height_half,
				t2, 0.0, 0, r_opacity * opacity );

		// draw text
		float opacity_txt = selected ? 0.9 : enabled ? 0.75 : 0.4;

		font.Print( center_x - rel_width_half, center_y - ( font.Height( text.c_str(), 1, font_size ) / 2.0f ), text.c_str(), 1, font_size, color_r, color_g, color_b, opacity_txt * opacity );

		while( ( font.Width( cur_option_txt.c_str(), 1, wheel_font_size ) > ( 0.15 - tex_width ) ) && wheel_font_size > 3 )
			wheel_font_size--;

		font.Print( center_x - rel_width_half + wheel_center - ( font.Width( cur_option_txt.c_str(), 1, wheel_font_size ) / 2.0f ), center_y - ( font.Height( cur_option_txt.c_str(), 1, wheel_font_size ) / 2.0f ), cur_option_txt.c_str() , 1, wheel_font_size, color_r, color_g, color_b, opacity_txt * opacity );

		// draw tip
		if( selected && ( tip != "" ) )
			font.Print( 0.5 - ( font.Width( tip.c_str(), 1, 6 ) / 2.0f ), 0.90, tip.c_str(), 1, 6, 0.7, 0.7, 0.7, 0.9 * opacity );
	}

	template<class wheel_t>
	void Wheel<wheel_t>::IncValuePress()
	{
		Release();
		r_down = true;
	}

	template<class wheel_t>
	void Wheel<wheel_t>::IncValueRelease()
	{
		Release();
		if( cur_option < option_list.size() - 1 )
		{
			cur_option++;
		}
	}

	template<class wheel_t>
	void Wheel<wheel_t>::DecValuePress()
	{
		Release();
		l_down = true;
	}

	template<class wheel_t>
	void Wheel<wheel_t>::DecValueRelease()
	{
		Release();
		if( cur_option > 0 )
		{
			cur_option--;
		}
	}

	template<class wheel_t>
	void Wheel<wheel_t>::Release()
	{
		r_down = l_down = false;
	}

	template<class wheel_t>
	bool Wheel<wheel_t>::MouseOver( float x, float y )
	{
		float min_x, min_y, max_x, max_y;
		min_x = center.GetXPercent() - ( rel_width / 2.0f );
		min_y = center.GetYPercent() - ( rel_height / 2.0f );
		max_x = center.GetXPercent() + ( rel_width / 2.0f );
		max_y = center.GetYPercent() + ( rel_height / 2.0f );

		return ( x > min_x ) && ( x < max_x ) && ( y > min_y ) && ( y < max_y );
	}

	template<class wheel_t>
	string Wheel<wheel_t>::MousePress( float x, float y )
	{
		string action = "";
		float l_min_x, l_min_y, l_max_x, l_max_y;
		float r_min_x, r_min_y, r_max_x, r_max_y;
		l_min_x = center.GetXPercent() - ( rel_width / 2.0f ) + spacing;
		l_min_y = center.GetYPercent() - ( rel_height / 2.0f );
		l_max_x = center.GetXPercent() - ( rel_width / 2.0f ) + spacing + tex_width;
		l_max_y = center.GetYPercent() + ( rel_height / 2.0f );
		r_min_x = center.GetXPercent() - ( rel_width / 2.0f ) + spacing  + 0.15;
		r_min_y = center.GetYPercent() - ( rel_height / 2.0f );
		r_max_x = center.GetXPercent() - ( rel_width / 2.0f ) + spacing  + 0.15 + tex_width;
		r_max_y = center.GetYPercent() + ( rel_height / 2.0f );

		if( wgt_hook != "" )
		{
			if( l_down ) action = wgt_hook + "L";
			if( r_down ) action = wgt_hook + "R";
		}

		if( ( x > l_min_x ) && ( x < l_max_x ) && ( y > l_min_y ) && ( y < l_max_y ) )
		{
			l_down = true;
		}
		else if( ( x > r_min_x ) && ( x < r_max_x ) && ( y > r_min_y ) && ( y < r_max_y ) )
		{
			r_down = true;
		}

		return action;
	}

	template<class wheel_t>
	string Wheel<wheel_t>::MouseRelease( float x, float y )
	{
		string action = "";
		float l_min_x, l_min_y, l_max_x, l_max_y;
		float r_min_x, r_min_y, r_max_x, r_max_y;
		l_min_x = center.GetXPercent() - ( rel_width / 2.0f ) + spacing;
		l_min_y = center.GetYPercent() - ( rel_height / 2.0f );
		l_max_x = center.GetXPercent() - ( rel_width / 2.0f ) + spacing + tex_width;
		l_max_y = center.GetYPercent() + ( rel_height / 2.0f );
		r_min_x = center.GetXPercent() - ( rel_width / 2.0f ) + spacing  + 0.15;
		r_min_y = center.GetYPercent() - ( rel_height / 2.0f );
		r_max_x = center.GetXPercent() - ( rel_width / 2.0f ) + spacing  + 0.15 + tex_width;
		r_max_y = center.GetYPercent() + ( rel_height / 2.0f );

		if( wgt_hook != "" )
		{
			if( l_down ) action = wgt_hook + "L";
			if( r_down ) action = wgt_hook + "R";
		}

		if( ( x > l_min_x ) && ( x < l_max_x ) && ( y > l_min_y ) && ( y < l_max_y ) && l_down )
		{
			DecValueRelease();
		}
		else if( ( x > r_min_x ) && ( x < r_max_x ) && ( y > r_min_y ) && ( y < r_max_y ) && r_down )
		{
			IncValueRelease();
		}
		else
		{
			Release();
		}

		return action;
	}

	template<class wheel_t1, class wheel_t2>
	Wheel2<wheel_t1, wheel_t2>::Wheel2( Widget* w )
	{
		setting_1 = "";
		setting_2 = "";
		cur_option = default_option = 0;
		center = w->GetCenter();
		name = w->GetName();
		text = w->GetText();
		type = w->GetType();
		tip = w->GetTip();
		rel_width = w->GetRelWidth();
		rel_height = w->GetRelHeight();
		enabled = w->GetEnabled();
		selected = w->GetSelected();
		is_default = w->GetDefault();
		is_cancel = w->GetCancel();
		has_icon = w->GetHasIcon();
		width_auto = w->GetWidthAuto();
		height_auto = w->GetHeightAuto();
		font_size = w->GetFontSize();
		color_r = w->GetColorR();
		color_g = w->GetColorG();
		color_b = w->GetColorB();
		l_down = false;
		r_down = false;
		spacing = 0.3;

		string skin_path = settings.GetSkinPath();
		l_arrow_up.Load( skin_path + "/textures/widgets/wheel_up_l.png", false );
		l_arrow_down.Load( skin_path + "/textures/widgets/wheel_down_l.png", false );
		r_arrow_up.Load( skin_path + "/textures/widgets/wheel_up_r.png", false );
		r_arrow_down.Load( skin_path + "/textures/widgets/wheel_down_r.png", false );

		tex_width = 0.0277;
		tex_height = 0.0370;

		// width = dist from left of text to wheel + width of wheel + texture width
		if( width_auto )
		{
			rel_width = spacing + 0.15 + tex_width;
		}

		// height = button texture height
		if( height_auto )
		{
			rel_height = tex_height;
		}
	}

	template<class wheel_t1, class wheel_t2>
	Wheel2<wheel_t1, wheel_t2>::~Wheel2()
	{
	}

	template<class wheel_t1, class wheel_t2>
	void Wheel2<wheel_t1, wheel_t2>::SetSpacing( float new_spacing )
	{
		spacing = new_spacing;
		rel_width = spacing + 0.15 + tex_width;
	}

	template<class wheel_t1, class wheel_t2>
	void Wheel2<wheel_t1, wheel_t2>::Save()
	{
		default_option = cur_option;
		settings.Set( setting_1, value_list_1[cur_option] );
		settings.Set( setting_2, value_list_2[cur_option] );
	}

	template<class wheel_t1, class wheel_t2>
	void Wheel2<wheel_t1, wheel_t2>::ResetValue()
	{
		int default_val_1, default_val_2;
		settings.Get( setting_1, default_val_1 );
		settings.Get( setting_2, default_val_2 );
		SetValue1( default_val_1 );
		SetValue2( default_val_2 );
	}

	template<class wheel_t1, class wheel_t2>
	void Wheel2<wheel_t1, wheel_t2>::Draw()
	{
		Draw( 1.0 );
	}

	template<class wheel_t1, class wheel_t2>
	void Wheel2<wheel_t1, wheel_t2>::Draw( float opacity )
	{
		int wheel_font_size = font_size;
		float center_x = center.GetXPercent();
		float center_y = center.GetYPercent();
		float rel_width_half = rel_width / 2.0f;
		float rel_height_half = rel_height / 2.0f;
		float wheel_center = spacing + tex_width + ( ( 0.15 - tex_width ) / 2.0f );
		string cur_option_txt = option_list[cur_option];
		TEXTURE_HANDLE * t1 = l_down ? &l_arrow_down : &l_arrow_up;
		TEXTURE_HANDLE * t2 = r_down ? &r_arrow_down : &r_arrow_up;
		float l_opacity = ( !enabled || ( cur_option == 0 ) ) ? 0.4 : selected ? 0.9 : 0.75;
		float r_opacity = ( !enabled || ( cur_option == option_list.size() - 1 ) ) ? 0.4 : selected ? 0.9 : 0.75;

		// draw arrow images
		utility.Draw2D( center_x - rel_width_half + spacing,
				center_y - rel_height_half,
				center_x - rel_width_half + spacing + tex_width,
				center_y + rel_height_half,
				t1, 0.0, 0, l_opacity * opacity );
		utility.Draw2D( center_x - rel_width_half + spacing  + 0.15,
				center_y - rel_height_half,
				center_x - rel_width_half + spacing  + 0.15 + tex_width,
				center_y + rel_height_half,
				t2, 0.0, 0, r_opacity * opacity );

		// draw text
		float opacity_txt = selected ? 0.9 : enabled ? 0.75 : 0.4;

		font.Print( center_x - rel_width_half, center_y - ( font.Height( text.c_str(), 1, font_size ) / 2.0f ), text.c_str(), 1, font_size, color_r, color_g, color_b, opacity_txt * opacity );

		while( ( font.Width( cur_option_txt.c_str(), 1, wheel_font_size ) > ( 0.15 - tex_width ) ) && wheel_font_size > 3 )
			wheel_font_size--;

		font.Print( center_x - rel_width_half + wheel_center - ( font.Width( cur_option_txt.c_str(), 1, wheel_font_size ) / 2.0f ), center_y - ( font.Height( cur_option_txt.c_str(), 1, wheel_font_size ) / 2.0f ), cur_option_txt.c_str() , 1, wheel_font_size, color_r, color_g, color_b, opacity_txt * opacity );

		// draw tip
		if( selected && ( tip != "" ) )
			font.Print( 0.5 - ( font.Width( tip.c_str(), 1, 6 ) / 2.0f ), 0.90, tip.c_str(), 1, 6, 0.7, 0.7, 0.7, 0.9 * opacity );
	}

	template<class wheel_t1, class wheel_t2>
	void Wheel2<wheel_t1, wheel_t2>::IncValuePress()
	{
		Release();
		r_down = true;
	}

	template<class wheel_t1, class wheel_t2>
	void Wheel2<wheel_t1, wheel_t2>::IncValueRelease()
	{
		Release();
		if( cur_option < option_list.size() - 1 )
		{
			cur_option++;
		}
	}

	template<class wheel_t1, class wheel_t2>
	void Wheel2<wheel_t1, wheel_t2>::DecValuePress()
	{
		Release();
		l_down = true;
	}

	template<class wheel_t1, class wheel_t2>
	void Wheel2<wheel_t1, wheel_t2>::DecValueRelease()
	{
		Release();
		if( cur_option > 0 )
		{
			cur_option--;
		}
	}

	template<class wheel_t1, class wheel_t2>
	void Wheel2<wheel_t1, wheel_t2>::Release()
	{
		r_down = l_down = false;
	}

	template<class wheel_t1, class wheel_t2>
	bool Wheel2<wheel_t1, wheel_t2>::MouseOver( float x, float y )
	{
		float min_x, min_y, max_x, max_y;
		min_x = center.GetXPercent() - ( rel_width / 2.0f );
		min_y = center.GetYPercent() - ( rel_height / 2.0f );
		max_x = center.GetXPercent() + ( rel_width / 2.0f );
		max_y = center.GetYPercent() + ( rel_height / 2.0f );

		return ( x > min_x ) && ( x < max_x ) && ( y > min_y ) && ( y < max_y );
	}

	template<class wheel_t1, class wheel_t2>
	string Wheel2<wheel_t1, wheel_t2>::MousePress( float x, float y )
	{
		float l_min_x, l_min_y, l_max_x, l_max_y;
		float r_min_x, r_min_y, r_max_x, r_max_y;
		l_min_x = center.GetXPercent() - ( rel_width / 2.0f ) + spacing;
		l_min_y = center.GetYPercent() - ( rel_height / 2.0f );
		l_max_x = center.GetXPercent() - ( rel_width / 2.0f ) + spacing + tex_width;
		l_max_y = center.GetYPercent() + ( rel_height / 2.0f );
		r_min_x = center.GetXPercent() - ( rel_width / 2.0f ) + spacing  + 0.15;
		r_min_y = center.GetYPercent() - ( rel_height / 2.0f );
		r_max_x = center.GetXPercent() - ( rel_width / 2.0f ) + spacing  + 0.15 + tex_width;
		r_max_y = center.GetYPercent() + ( rel_height / 2.0f );


		if( ( x > l_min_x ) && ( x < l_max_x ) && ( y > l_min_y ) && ( y < l_max_y ) )
		{
			l_down = true;
		}
		else if( ( x > r_min_x ) && ( x < r_max_x ) && ( y > r_min_y ) && ( y < r_max_y ) )
		{
			r_down = true;
		}

		return "";
	}

	template<class wheel_t1, class wheel_t2>
	string Wheel2<wheel_t1, wheel_t2>::MouseRelease( float x, float y )
	{
		float l_min_x, l_min_y, l_max_x, l_max_y;
		float r_min_x, r_min_y, r_max_x, r_max_y;
		l_min_x = center.GetXPercent() - ( rel_width / 2.0f ) + spacing;
		l_min_y = center.GetYPercent() - ( rel_height / 2.0f );
		l_max_x = center.GetXPercent() - ( rel_width / 2.0f ) + spacing + tex_width;
		l_max_y = center.GetYPercent() + ( rel_height / 2.0f );
		r_min_x = center.GetXPercent() - ( rel_width / 2.0f ) + spacing  + 0.15;
		r_min_y = center.GetYPercent() - ( rel_height / 2.0f );
		r_max_x = center.GetXPercent() - ( rel_width / 2.0f ) + spacing  + 0.15 + tex_width;
		r_max_y = center.GetYPercent() + ( rel_height / 2.0f );


		if( ( x > l_min_x ) && ( x < l_max_x ) && ( y > l_min_y ) && ( y < l_max_y ) && l_down )
		{
			DecValueRelease();
		}
		else if( ( x > r_min_x ) && ( x < r_max_x ) && ( y > r_min_y ) && ( y < r_max_y ) && r_down )
		{
			IncValueRelease();
		}
		else
		{
			Release();
		}

		return "";
	}
}


#endif // _VGUI_WHEEL_H
