#include <sstream>
#include "utility.h"
#include "controls.h"
#include "globals.h"
#include "gui/calibrate.h"
using namespace VGUI;

Calibrate::Calibrate( Widget* w )
{
	//setting = "";
	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();

	int _w, _h;
	string skin_path = settings.GetSkinPath();
	joy_cal_box_tex.Load( skin_path + "/textures/widgets/joy_cal_box.png", false, _w, _h );
	axis_field_tex.Load( skin_path + "/textures/widgets/axis_field.png", false, _w, _h );
	joy_cursor_tex.Load( skin_path + "/textures/widgets/joy_cursor.png", false, _w, _h );

	field_width = 256.0f / 1600.0f;
	field_height = 256.0f / 1200.0f;
	cursor_width = 64.0f / 1600.0f;
	cursor_height = 64.0f / 1200.0f; 
	cur_joy_idx = 0;

/*
	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 = field_width + ( 4.0 / 1600.0 );
	}

	// height = button texture height
	if( height_auto )
	{
		rel_height = field_height + ( 4.0 / 1600.0 );
	}
}

Calibrate::~Calibrate()
{
	ResetValue();
}

void Calibrate::Save()
{
	map< int, map<int, CalSet*> >::iterator joy_idx_iter;
	map<int, CalSet*>::iterator joy_axis_iter;
	CalSet* joy_axis_cal;
	int joy_idx, joy_axis;

	gamecontrols.MinimizeCalibration();

	for( joy_idx_iter = calibrations.begin(); joy_idx_iter != calibrations.end(); ++joy_idx_iter )
	{
		joy_idx = joy_idx_iter->first;

		for( joy_axis_iter = joy_idx_iter->second.begin(); joy_axis_iter != joy_idx_iter->second.end(); ++joy_axis_iter )
		{
			joy_axis = joy_axis_iter->first;
			joy_axis_cal = joy_axis_iter->second;

			gamecontrols.SetCalibrationPoint( joy_idx, joy_axis, joy_axis_cal->GetUpperValue() );
			gamecontrols.SetCalibrationPoint( joy_idx, joy_axis, joy_axis_cal->GetLowerValue() );
		}
	}
	gamecontrols.WriteCalibration();
}

void Calibrate::ResetValue()
{
	map< int, map<int, CalSet*> >::iterator joy_idx_iter;
	map<int, CalSet*>::iterator joy_axis_iter;

	for( joy_idx_iter = calibrations.begin(); joy_idx_iter != calibrations.end(); ++joy_idx_iter )
	{
		for( joy_axis_iter = joy_idx_iter->second.begin(); joy_axis_iter != joy_idx_iter->second.end(); ++joy_axis_iter )
		{
			delete joy_axis_iter->second;
		}

		joy_idx_iter->second.clear();
	}

	calibrations.clear();

	cur_joy_idx = 0;
}

void Calibrate::Draw()
{
	Draw( 1.0 );
}

void Calibrate::Draw( float opacity )
{
//	map< int, map<int, CalSet*> >::iterator joy_idx_iter;
	map<int, CalSet*>::iterator joy_axis_iter;
	CalSet *tmp_cs;
	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 curs_width_half = cursor_width / 2.0f;
	float curs_height_half = cursor_height / 2.0f;
	float opacity_txt = selected ? 0.9 : enabled ? 0.75 : 0.4;
	float text_width_half = ( font.Width( "Axis 0", 1, 5 ) / 2.0f );
	float upper_val_1, lower_val_1, cur_val_1, upper_val_2, lower_val_2, cur_val_2;
	float cursor_x, cursor_y;
	float total_width, total_width_half, field_offset, increment;
	float cal_box_l_offset, cal_box_r_offset, cal_box_t_offset, cal_box_b_offset;
	int num_axes, num_fields, i;
	string axis_name_1, axis_name_2, joy_text;
	ostringstream axis_namer;

	joy_text = ( SDL_NumJoysticks() > 0 ) ? SDL_JoystickName( cur_joy_idx ) : "[No Joysticks...]";
	num_axes = calibrations[cur_joy_idx].size();
	num_fields = ( num_axes + 1 ) / 2;
	total_width = rel_width + ( (float)( 2 * ( num_fields - 1 ) ) * rel_width );
	total_width_half = total_width / 2.0f;
	increment = num_axes <= 2 ? 0 : ( total_width + rel_width ) / (float)num_fields;
	i = 0;

	font.Print( center_x - ( font.Width( joy_text.c_str(), 1, font_size ) / 2.0f ),
	            center_y - rel_height_half - ( 2.0f * cursor_height ),
	            joy_text.c_str(), 1, font_size, color_r, color_g, color_b, opacity_txt * opacity );

	for( joy_axis_iter = calibrations[cur_joy_idx].begin(); joy_axis_iter != calibrations[cur_joy_idx].end(); ++joy_axis_iter )
	{
		field_offset = (float)i * increment;

		tmp_cs = joy_axis_iter->second;
		upper_val_1 = tmp_cs->GetUpperValue();
		lower_val_1 = tmp_cs->GetLowerValue();
		cur_val_1 = tmp_cs->GetCurrentValue();

		axis_namer.str("");
		axis_namer << "Axis ";
		axis_namer << joy_axis_iter->first;
		axis_name_1 = axis_namer.str();

		++joy_axis_iter;

		if( joy_axis_iter != calibrations[cur_joy_idx].end() )
		{
			tmp_cs = joy_axis_iter->second;
			upper_val_2 = tmp_cs->GetUpperValue();
			lower_val_2 = tmp_cs->GetLowerValue();
			cur_val_2 = tmp_cs->GetCurrentValue();

			axis_namer.str("");
			axis_namer << "Axis ";
			axis_namer << joy_axis_iter->first;
			axis_name_2 = axis_namer.str();
		}
		else
		{
			upper_val_2 = lower_val_2 = cur_val_2 = 0.0;
			axis_name_2 = "";
		}

		// draw the background crosshair thingy
		utility.Draw2D( center_x - total_width_half + field_offset,
		                center_y - rel_height_half,
		                center_x - total_width_half + field_offset + rel_width,
	        	        center_y + rel_height_half,
		                &axis_field_tex );

		// draw the calibration area box
		cal_box_l_offset = ( 1.0 + lower_val_1 ) * rel_width_half;
		cal_box_r_offset = ( 1.0 - upper_val_1 ) * rel_width_half;
		cal_box_t_offset = ( 1.0 + lower_val_2 ) * rel_height_half;
		cal_box_b_offset = ( 1.0 - upper_val_2 ) * rel_height_half;

		utility.Draw2D( center_x - total_width_half + field_offset + cal_box_l_offset,
		                center_y - rel_height_half + cal_box_t_offset,
		                center_x - total_width_half + field_offset + rel_width - cal_box_r_offset,
	        	        center_y + rel_height_half - cal_box_b_offset,
		                &joy_cal_box_tex );

		cursor_x = center_x - total_width_half + field_offset + rel_width_half + ( ( field_width / 2.0 ) * cur_val_1 );
		cursor_y = center_y + ( ( field_height / 2.0 ) * cur_val_2 );

		// draw the joystick cursor
		utility.Draw2D( cursor_x - curs_width_half,
		                cursor_y - curs_height_half,
		                cursor_x + curs_width_half,
		                cursor_y + curs_height_half,
		                &joy_cursor_tex );

		// draw text
		font.Print( center_x - total_width_half + field_offset + rel_width_half - text_width_half,
		            center_y - rel_height_half - cursor_height,
		            axis_name_1.c_str(), 1, font_size, color_r, color_g, color_b, opacity_txt * opacity );

		if( joy_axis_iter == calibrations[cur_joy_idx].end() )
		{
			break;
		}
		else
		{
			font.Print( center_x - total_width_half + field_offset - ( text_width_half * 4.0f ),
			            center_y - curs_height_half,
			            axis_name_2.c_str(), 1, font_size, color_r, color_g, color_b, opacity_txt * opacity );
		}

		i++;
	}
}

void Calibrate::GrabJoyMove( Uint8 _joy_idx, Uint8 _joy_axis, bool joy_positive, float joy_value )
{
	int joy_idx = (int)_joy_idx;
	int joy_axis = (int)_joy_axis;
	if( calibrations[joy_idx][joy_axis] != NULL )
	{
		if( calibrations[joy_idx][joy_axis]->GetUpperValue() < joy_value )
		{
			calibrations[joy_idx][joy_axis]->SetUpperValue( joy_value );
		}
		else if( calibrations[joy_idx][joy_axis]->GetLowerValue() > joy_value )
		{
			calibrations[joy_idx][joy_axis]->SetLowerValue( joy_value );
		}
	}
	else
	{
		CalSet *new_cal;
		new_cal = new CalSet( 0.0, 0.0 );
		calibrations[joy_idx][joy_axis] = new_cal;
	}

	calibrations[joy_idx][joy_axis]->SetCurrentValue( joy_value );
}

void Calibrate::HookIncValueRelease()
{
	if( cur_joy_idx < SDL_NumJoysticks() - 1 )
	{
		cur_joy_idx++;
	}
}

void Calibrate::HookDecValueRelease()
{
	if( cur_joy_idx > 0 )
	{
		cur_joy_idx--;
	}
}
