#include "gui/spinning_car.h"
#include "gui/image.h"

#include "vamosworld.h" //needed for texture based lighting
#include "globals.h"

using namespace VGUI;


SpinningCar::SpinningCar( 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 = false; //w->GetWidthAuto();
	height_auto = false; //w->GetHeightAuto();
	font_size = w->GetFontSize();
	color_r = w->GetColorR();
	color_g = w->GetColorG();
	color_b = w->GetColorB();
	last_t = 0.0;
	rotation = 0.0;
	fade_time = 0.6f;
	string skin_path = settings.GetSkinPath();
	sphere_reflection.Load( skin_path + "/textures/refmap.png", false );
	cur_option = 0;
	loaded = false;
	car_out = false;
	car_in = true;
	extra_clicks = false;
	car = NULL;
	wheel = NULL;
	settings.Get( "display.FOV", fov );
	colorwheel = true;
}

SpinningCar::~SpinningCar()
{
	ClearCar();
}

void SpinningCar::LoadCar()
{
	loaded = false;
	Widget * wgt;
	Location tmp_center;

	if( ( car != NULL ) || ( wheel != NULL ) )
		ClearCar();

	car = new Vamos_Body::Gl_Car( Vamos_Geometry::Three_Vector( 0.0, 0.0, 0.0 ) );

	car->read( settings.GetDataDir() + "/", filename_list[cur_option] );

	// create color selector wheel for this car
	int num_pjs = car->GetNumPaintjobs();

	wgt = new Widget();

	wgt->SetName( name + value_list[cur_option] + "Wheel" );
	wgt->SetType( "intwheel" );
	wgt->SetText( "Color" );
	wgt->SetFontSize( 6 );
	wgt->SetColor( 1.0, 1.0, 1.0 );
	tmp_center = Location( center.GetXPercent(), center.GetYPercent() - 0.15 );
	wgt->SetCenter( tmp_center );
	wgt->SetWidthAuto( true );
	wgt->SetHeightAuto( true );
	wgt->SetEnabled( true );
	wgt->SetSelected( false );
	wgt->SetDefault( false );
	wgt->SetCancel( false );
	wgt->SetTip( _c("Select the car's color.") );

	wheel = new Wheel<int>( wgt );
	vector<string> whl_list;
	vector<int> val_list;

	for( int i = 0; i < num_pjs; i++ )
	{
		// it'd be nice to replace this with a color name rather than just a # - where to pust list?
		char tc[10];
		sprintf( tc, "Color %d", i+1 );
		string t = tc;
		whl_list.push_back( t );
		val_list.push_back( i );
	}
	wheel->SetOptionList( whl_list );
	wheel->SetValueList( val_list );
	//only set the settings string if this is the player car
	if( colorwheel ) wheel->SetSetting( "game.car_paint" );
	wheel->ResetValue();
	wheel->SetSpacing( 0.1 );

	car->SetPaint( wheel->GetValue() );

	car->SetReflectionTexture( &sphere_reflection, false );

	delete wgt;

	loaded = true;
}

void SpinningCar::ClearCar()
{
	if( car != NULL )
	{
		delete car;
		car = NULL;
	}
	if( wheel != NULL )
	{
		delete wheel;
		wheel = NULL;
	}
	loaded = false;
}

void SpinningCar::ResetValue()
{
	string default_val;
	settings.Get( setting, default_val );
	settings.Get( "display.FOV", fov );
	SetValue( default_val );
	LoadCar();
	car_in = true;
	car->SetPaint( 0 );
	wheel->SetValue( 0 );
	wheel->ResetValue();
	car->SetPaint( wheel->GetValue() );
	press_time = SDL_GetTicks();
	car->SetReflectionTexture( &sphere_reflection, false );
}

void SpinningCar::Save()
{
	if( loaded )
		wheel->Save();
	settings.Get( "display.FOV", fov );
}

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

void SpinningCar::Draw( float opacity )
{
	if( !loaded )
		LoadCar();

	if( colorwheel ) wheel->SetSelected( selected );

	float cur_opacity = 1.0;
	float elapsed_time = 0.0;
	GLint t = SDL_GetTicks();
	float time = (float)(t - last_t ) / 1000.0;
	if( last_t == 0.0 ) last_t = t;
	rotation += time;
	while (rotation > 2*3.141593)
		rotation -= 2*3.141593;
	last_t = t;

	QUATERNION rot;
	VERTEX pos;
	GLdouble temp_matrix[16];

	glPushMatrix();
	
	/*GLfloat LightAmbient[]  = { 0.1f, 0.1f, 0.1f, 1.0f };
	GLfloat LightDiffuse[]  = { 1.0f, 1.0f, 1.0f, 1.0f };
	GLfloat LightSpecular[]  = { 0.0f, 0.0f, 0.0f, 0.0f };
	GLfloat LightPosition[] = {0.0, 1.0, 0.0, 0.0f };
	glLightfv( GL_LIGHT1, GL_POSITION, LightPosition );
	glLightfv( GL_LIGHT1, GL_DIFFUSE, LightDiffuse );
	glLightfv( GL_LIGHT1, GL_SPECULAR, LightSpecular );
	glLightfv( GL_LIGHT1, GL_AMBIENT, LightAmbient );*/
	
	glMatrixMode( GL_MODELVIEW );
	glPushAttrib( GL_ALL_ATTRIB_BITS );
	glClear( GL_DEPTH_BUFFER_BIT );
	glLoadIdentity();

	glEnable(GL_LIGHTING);

	float adjusted_z = carpos[2] * tan(M_PI/8.0) / tan (fov * M_PI / 360.0);

	pos.Set( carpos[0], carpos[1], adjusted_z );
	//pos.Set( center.GetXPercent(), center.GetYPercent(), -15 );
	//pos.Set( -3.2,1.25,-15 );
	rot.Rotate( rotation, 0,0,1 );
	rot.Rotate( -3.1415/2.15, 1,0,0 );
	rot.Rotate( 0, 0,1,0 );
	rot.GetMat( temp_matrix );
	glTranslatef( pos.x, pos.y, pos.z );
	glMultMatrixd( temp_matrix );

	utility.SelectTU(0);

	if( car_out )
	{
		elapsed_time = ( (float)( SDL_GetTicks() - press_time ) / 1000.0 );
		if( elapsed_time <= fade_time )
		{
			cur_opacity = 1.0 - ( elapsed_time / fade_time );
		}
		else
		{
			car_out = false;
			cur_opacity = 0.0;
			LoadCar();
			press_time = SDL_GetTicks();
			car_in = true;
		}
	}
	else if( car_in )
	{
		extra_clicks = false;
		elapsed_time = ( (float)( SDL_GetTicks() - press_time ) / 1000.0 );
		if( elapsed_time <= fade_time )
		{
			cur_opacity = ( elapsed_time / fade_time );
		}
		else
		{
			car_in = false;
			cur_opacity = 1.0;
		}
	}
	
	glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
	
	// Put the textures on a shiny white surface so we can see shading.
	glColorMaterial (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
	glEnable (GL_COLOR_MATERIAL);
	glColor3f (1.0, 1.0, 1.0);
	GLfloat specular [] = { 0.0, 0.0, 0.0, 0.0 };
	glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, specular);
	GLfloat shininess [] = { 0.0 };
	glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS, shininess);

	bool cubelighting = world.StaticCubeLighting() || world.DynamicCubeLighting();
	//bool cubelighting = true;
	if (cubelighting)
	{
		world.ActivateTextureBasedLighting(false);
	}
	
	car->draw( false, cur_opacity * opacity );
	//car->draw( false, 0.5 );
	
	if (cubelighting)
	{
		world.DeactivateTextureBasedLighting();
	}

	glPopAttrib();
	glPopMatrix();

	// draw the car color wheel
	if( colorwheel ) wheel->Draw( cur_opacity * opacity );
}

void SpinningCar::HookIncValuePress()
{
	HookRelease();
	r_down = true;
}

void SpinningCar::HookIncValueRelease()
{
	HookRelease();
	if( cur_option < filename_list.size() - 1 )
	{
		press_time = SDL_GetTicks();
		cur_option++;
		car_out = true;
	}
}

void SpinningCar::HookDecValuePress()
{
		HookRelease();
		l_down = true;
		press_time = SDL_GetTicks();
}

void SpinningCar::HookDecValueRelease()
{
	HookRelease();
	if( cur_option > 0 )
	{
		press_time = SDL_GetTicks();
		cur_option--;
		car_out = true;
	}
}

void SpinningCar::HookRelease()
{
	r_down = l_down = false;
}

void SpinningCar::IncValuePress()
{
	if( loaded )
		wheel->IncValuePress();
}

void SpinningCar::IncValueRelease()
{
	if( loaded )
	{
		wheel->IncValueRelease();
		car->SetPaint( wheel->GetValue() );
	}
}

void SpinningCar::DecValuePress()
{
	if( loaded )
		wheel->DecValuePress();
}

void SpinningCar::DecValueRelease()
{
	if( loaded )
	{
		wheel->DecValueRelease();
		car->SetPaint( wheel->GetValue() );
	}
}

void SpinningCar::Release()
{
	if( loaded )
		wheel->Release();
}

bool SpinningCar::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 );
*/	
	bool result = false;
	if( loaded )
		result = wheel->MouseOver( x, y );

	return result;
}

string SpinningCar::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;
	}
*/
	string result = "";
	if( loaded )
		result = wheel->MousePress( x, y );

	return result;
}

string SpinningCar::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();
	}
*/
	string result = "";

	if( loaded )
	{
		result = wheel->MouseRelease( x, y );
		car->SetPaint( wheel->GetValue() );
	}

	return result;
}
