/* gui.cpp */

#include <iostream>
#include <iomanip>
#include <iterator>
#include <sstream>
#include <stdio.h>
#include "vamosworld.h"
#include "controls.h"
#include "mouse.h"
#include "utility.h"
#include "gui/widget.h"
#include "gui/page.h"
#include "gui/gui.h"
#include "gui/button.h"
#include "gui/calibrate.h"
#include "gui/controlgrab.h"
#include "gui/image.h"
#include "gui/label.h"
#include "gui/multi_image.h"
#include "gui/slider.h"
#include "gui/spinning_car.h"
#include "gui/textbox.h"
#include "gui/toggle.h"
#include "gui/wheel.h"

using namespace VGUI;

extern void Quit( int returnCode );
extern void MainPause();
extern void MainUnpause();
extern bool ReloadDisplay( bool test );
extern void ResetWorld( bool fullreset );
extern bool LoadWorld();
extern bool UnloadWorld();
extern bool verbose_output;



void Gui::Init()
{
	bool was_loaded = false;
	if( loaded )
	{
		DeInit();
		was_loaded = true;
	}

	string menu_path = settings.GetSkinPath() + "/menus";
	string full_menu_path = settings.GetDataDir() + "/" + menu_path;
	list<string> menu_list;
	utility.GetFolderIndex( full_menu_path, menu_list );

	if( verbose_output ) cout << "menu_path: " << menu_path << endl;
	list<string>::iterator menu;
	for( menu = menu_list.begin(); menu != menu_list.end(); ++menu )
	{
		pages[*menu] = new Page( settings.GetFullDataPath( menu_path + "/" + *menu ) );
	}

	Enable();
	if( !was_loaded ) cur_page = "Main";

	// get screen size
	settings.Get( "display.width", screen_width );
	settings.Get( "display.height", screen_height );

	// figure out dimensions of pointer in percentage of screen
	ptr_w = 0.0555;
	ptr_h = 0.0740;

	// load mouse pointer graphic
	mouse_pointer.Load( settings.GetSkinPath() + "/textures/mouse.png", false );
	is_locked = l=m=r=u=d=joy_l=joy_r=joy_u=joy_d=key_down=cancel_down = false;

	loaded = true;
	if( !settings.Get( "joystick.calibrated", calibrated ) )
	{
		calibrated = false;
		settings.Set( "joystick.calibrated", calibrated );
	}

#ifdef ENABLE_FORCE_FEEDBACK
	pages["JoystickOptions"]->GetWidget("FFGainSlider")->SetEnabled( true );
	pages["JoystickOptions"]->GetWidget("FFInvertToggle")->SetEnabled( true );
	pages["InGameJoystickOptions"]->GetWidget("InGameFFGainSlider")->SetEnabled( true );
	pages["InGameJoystickOptions"]->GetWidget("InGameFFInvertToggle")->SetEnabled( true );
#endif
}

void Gui::ReInit()
{
	if( !loaded )
		return;

	Init();
	Enable();
}

void Gui::DeInit()
{
	map<string,Page*>::iterator page;
	for( page = pages.begin(); page != pages.end(); ++page )
	{
		delete page->second;
	}

	pages.clear();

	Disable();

	loaded = false;
}

void Gui::UpdateScreenSize()
{
	// get screen size
	settings.Get( "display.width", screen_width );
	settings.Get( "display.height", screen_height );
}

void Gui::Draw()
{
	float x, y;
	float last_page_opacity = 0.0;
	float this_page_opacity = 1.0;

	glDisable(GL_LIGHTING);
	
	// is the menu on right now?
	if( !menu_enabled )
		return;

	MouseUpdate();

	// convert mouse position to screen percentage
	x = (float)mouse_x / (float)screen_width;
	y = (float)mouse_y / (float)screen_height;

	// update selection from mouse movements
	if( !is_locked )
		pages[cur_page]->MouseSelect( x, y );

	if( last_page != "" )
	{
		float elapsed_switch_time = (float)( SDL_GetTicks() - page_switch_time ) / 1000.0;
		if( elapsed_switch_time <= 0.3 )
		{
			// this will crossfade the menus in 3 tenths of a second
			this_page_opacity = ( elapsed_switch_time / 0.3 );
			last_page_opacity = 1.0 - this_page_opacity;
			pages[last_page]->Draw( last_page_opacity );
		}
		else
		{
			last_page = "";
		}
	}

	// draw the current page
	pages[cur_page]->Draw( this_page_opacity );

	// draw the mouse pointer
	if( is_locked == false )
	{
		utility.Draw2D( x, y, x + ptr_w, y + ptr_h, &mouse_pointer, 0.0, 64, 1.0 );
	}
}

void Gui::KeyPress( SDLKey key )
{

	// is the menu on right now?
	if( !menu_enabled )
	{
		return;
	}

	if( is_locked == true )
	{
		pages[cur_page]->ControlGrabKey( key );
		is_locked = false;
	}
	else
	{
		if( key == SDLK_UP )
		{
			pages[cur_page]->UpWidget();
		}
		else if( key == SDLK_DOWN )
		{
			pages[cur_page]->DownWidget();
		}
		else if( key == SDLK_LEFT )
		{
			pages[cur_page]->LeftWidgetPress();
		}
		else if( key == SDLK_RIGHT )
		{
			pages[cur_page]->RightWidgetPress();
		}
		else if( key == SDLK_BACKSPACE )
		{
			pages[cur_page]->BackspacePress();
		}
		else if( key == SDLK_DELETE )
		{
			pages[cur_page]->DeletePress();
		}
		else if( ( key == SDLK_RETURN ) ||
				 ( key == SDLK_SPACE ) )
		{
			pages[cur_page]->KeyPress();
		}
		else if( key == SDLK_ESCAPE )
		{
			pages[cur_page]->CancelPress();
		}
		else
		{
			pages[cur_page]->Type( key );
		}
	}
}

void Gui::KeyRelease( SDLKey key )
{
	string action = "";

	// is the menu on right now?
	if( !menu_enabled )
		return;

	if( is_locked == true )
		return;

	if( ( key == SDLK_RETURN ) ||
	    ( key == SDLK_SPACE ) )
	{
		action = pages[cur_page]->KeyRelease();
	}
	else if( key == SDLK_ESCAPE )
	{
		action = pages[cur_page]->CancelRelease();
	}
	else if( key == SDLK_LEFT )
	{
		pages[cur_page]->LeftWidgetRelease();
	}
	else if( key == SDLK_RIGHT )
	{
		pages[cur_page]->RightWidgetRelease();
	}
	else if( key == SDLK_BACKSPACE )
	{
		pages[cur_page]->BackspaceRelease();
	}
	else if( key == SDLK_DELETE )
	{
		pages[cur_page]->DeleteRelease();
	}

	ProcessAction( action );
}

void Gui::MousePress()
{
	float x, y;

	// is the menu on right now?
	if( !menu_enabled )
		return;

	// get mouse buttons status
	mouse.GetMouseButtons( l, m, r, u, d );
	// get mouse position 
	mouse.GetMousePos( mouse_x, mouse_y );
	// convert to screen percentage
	x = (float)mouse_x / (float)screen_width;
	y = (float)mouse_y / (float)screen_height;

	if( is_locked == true )
	{
		int button_idx = 0;
		for( int i = 1; i <= 10; i++ )
		{
			if( mouse.IsPressed( i ) )
			{
				button_idx = i;
				break;
			}
		}
		if( button_idx == 0 )
		{
			cout << "Couldn't add button 0!" << endl;
		}
		else
		{
			pages[cur_page]->ControlGrabMouseButton( button_idx );
		}
		is_locked = false;
	}
	else
	{
		// update selection from mouse movements
		pages[cur_page]->MouseSelect( x, y );

		if( l && pages[cur_page]->MouseOver( x, y ) )
		{
			pages[cur_page]->MousePressWidget( x, y );
		}
	}
}

void Gui::MouseRelease()
{
	string action = "";
	float x, y;

	// is the menu on right now?
	if( !menu_enabled )
		return;

	if( is_locked == true )
		return;

	// get mouse position 
	mouse.GetMousePos( mouse_x, mouse_y );
	// convert to screen percentage
	x = (float)mouse_x / (float)screen_width;
	y = (float)mouse_y / (float)screen_height;

	// update selection from mouse movements
	pages[cur_page]->MouseSelect( x, y );

	if( l )
	{
		action = pages[cur_page]->MouseReleaseWidget( x, y );
		ProcessAction( action );
	}

	// get mouse buttons status
	mouse.GetMouseButtons( l, m, r, u, d );
}

void Gui::MouseUpdate()
{
	// get mouse position 
	mouse.GetMousePos( mouse_x, mouse_y );

	if( is_locked == true )
	{
		float mouse_cur_x = mouse_x / (float)screen_width;
		float mouse_cur_y = mouse_y / (float)screen_height;
		float lock_x = mouse_lock_x / (float)screen_width;
		float lock_y = mouse_lock_y / (float)screen_height;
		float moved_x = mouse_cur_x - lock_x;
		float moved_y = mouse_cur_y - lock_y;
		float distance_x = moved_x > 0 ? moved_x : -moved_x;
		float distance_y = moved_y > 0 ? moved_y : -moved_y;

		// in which direction is there greater movement?
		if( distance_x > distance_y )
		{
			// see if distance is greater than threshold (about 100 pixels at 1280x1024)
			if( distance_x > 0.078 )
			{
				if( moved_x < 0 )
				{
					pages[cur_page]->ControlGrabMouseMove( "left" );
				}
				else
				{
					pages[cur_page]->ControlGrabMouseMove( "right" );
				}
				is_locked = false;
			}
		}
		else if( distance_y > distance_x )
		{
			if( distance_y > 0.097 )
			{
				if( moved_y < 0 )
				{
					pages[cur_page]->ControlGrabMouseMove( "up" );
				}
				else
				{
					pages[cur_page]->ControlGrabMouseMove( "down" );
				}
				is_locked = false;
			}
		}
	}
}

void Gui::MouseReturn()
{
	SDL_WarpMouse( mouse_x, mouse_y );
}

void Gui::JoyPress( Uint8 joy_idx, Uint8 joy_btn )
{
	if( !menu_enabled )
		return;

	if( !calibrated )
		return;

	if( is_locked == true )
	{
		pages[cur_page]->ControlGrabJoyButton( joy_idx, joy_btn );
		is_locked = false;
		return;
	}

	// for now, we're going to assume that buttons 0,1,2 are "OK" buttons and 3,4,5 are "Cancel" buttons.

	switch( joy_btn % 2 )
	{
	case 0:
		key_down = true;
		pages[cur_page]->KeyPress();
		break;
	case 1:
		cancel_down = true;
		pages[cur_page]->CancelPress();
		break;
	}
}

void Gui::JoyRelease( Uint8 joy_idx, Uint8 joy_btn )
{
	if( !menu_enabled )
		return;

	if( !calibrated )
		return;

	if( is_locked == true )
		return;

	// for now, we're going to assume that even buttons are "OK" buttons and odd ones are "Cancel" buttons.

	string action = "";

	switch( joy_btn % 2 )
	{
	case 0:
		if( key_down )
		{
			action = pages[cur_page]->KeyRelease();
			key_down = false;
		}
		break;
	case 1:
		if( cancel_down )
		{
			action = pages[cur_page]->CancelRelease();
			cancel_down = false;
		}
		break;
	}

	ProcessAction( action );
}

void Gui::JoyMove( Uint8 joy_idx, Uint8 joy_axis, float val )
{
	if( !menu_enabled )
		return;

	if( ( cur_page == "JoystickCalibrate" ) || ( cur_page == "InGameJoystickCalibrate" ) )
	{
		calibrated = false;
		pages[cur_page]->ControlGrabJoyMove( joy_idx, joy_axis, joy_positive, val );
	}

	if( !calibrated )
	{
		return;
	}

	joy_axis_value = val;
	last_axis = joy_axis;
	last_joy = joy_idx;

	if( is_locked == true )
	{
		if( joy_axis_value < -0.2 )
		{
			joy_press_time = SDL_GetTicks();
			joy_positive = false;
		}
		else if( joy_axis_value > 0.2 )
		{
			joy_press_time = SDL_GetTicks();
			joy_positive = true;
		}
	}

	// for now, we're going to assume that axis 0 is left(-)/right(+) motion and axis 1 is up(-)/down(+).

	switch( last_axis % 2 )
	{
	case 0:
		if( !joy_l && ( joy_axis_value < -0.2 ) )
		{
			joy_press_time = SDL_GetTicks();
			joy_l = true;
			if( !is_locked ) pages[cur_page]->LeftWidgetPress();
		}
		else if( !joy_r && ( joy_axis_value > 0.2 ) )
		{
			joy_press_time = SDL_GetTicks();
			joy_r = true;
			if( !is_locked ) pages[cur_page]->RightWidgetPress();
		}
		break;
	case 1:
		if( !joy_u && ( joy_axis_value < -0.2 ) )
		{
			joy_press_time = SDL_GetTicks();
			joy_u = true;
			if( !is_locked ) pages[cur_page]->UpWidget();
		}
		else if( !joy_d && ( joy_axis_value > 0.2 ) )
		{
			joy_press_time = SDL_GetTicks();
			joy_d = true;
			if( !is_locked ) pages[cur_page]->DownWidget();
		}
		break;
	}
}

void Gui::JoyUpdate()
{
	if( !calibrated )
		return;

	Uint32 time_since_joy_press = SDL_GetTicks() - joy_press_time;
	float sec_since_move = (float)( (float)time_since_joy_press / 1000.0 );

	// time delay for joystick axis movements is 3 tenths of a second
	if( sec_since_move >= 0.3 )
	{
		if( ( is_locked == true ) && ( joy_u || joy_d || joy_l || joy_r ) )
		{
			pages[cur_page]->ControlGrabJoyMove( last_joy, last_axis, joy_positive, joy_axis_value );
			is_locked = joy_u = joy_d = joy_l = joy_r = false;
			return;
		}

		if( joy_u )
		{
			joy_u = false;
		}

		if( joy_d )
		{
			joy_d = false;
		}

		if( joy_l )
		{
			pages[cur_page]->LeftWidgetRelease();
			joy_l = false;
		}

		if( joy_r )
		{
			pages[cur_page]->RightWidgetRelease();
			joy_r = false;
		}
	}
}

void Gui::EditControl( string setting, string return_page, string cg_name, int cg_cidx )
{
	editing_control = true;
	editing_finished = return_page;
	editing_cg_cidx = cg_cidx;
	editing_cg_name = cg_name;
	editing_cg = (ControlGrab*)pages[return_page]->GetWidget( cg_name );
	string type = editing_cg->GetControlSet( cg_cidx )->GetType();
	string name = editing_cg->GetControlSet( cg_cidx )->GetName();
	editing_page = "Edit" + type + "Control";
	Widget* control_label;
	Widget* ctrltype_label;
	if( pages.find( editing_page ) != pages.end() )
	{
//		cout << "getting control label" << endl;
		ctrltype_label = pages[editing_page]->GetWidget( "Edit" + type + "ControlLabel2" );
//		cout << "getting control type label" << endl;
		control_label = pages[editing_page]->GetWidget( "Edit" + type + "ControlLabel4" );
		ctrltype_label->SetText( name );
		control_label->SetText( setting );
	}
	else
	{
		cout << "couldn't find page " << editing_page << endl;
		return;
	}

//	cout << "Changing to page " << editing_page << endl;
	ChangePage( editing_page );

	if( type == "JoyAxis" )
	{
		// deadzone
		float deadzone = editing_cg->GetControlSet( cg_cidx )->GetControl().GetDeadzone();
		Slider* dz_slider = (Slider*)pages[editing_page]->GetWidget( "DeadzoneSlider" );
//		cout << "Setting deadzone slider at value " << deadzone << endl;
		dz_slider->SetAdjustedValue( deadzone );
		// gain
		float gain = editing_cg->GetControlSet( cg_cidx )->GetControl().GetGain();
		Slider* gain_slider = (Slider*)pages[editing_page]->GetWidget( "GainSlider" );
//		cout << "Setting gain slider at value " << gain << endl;
		gain_slider->SetAdjustedValue( gain );
		// exponent
		float exponent = editing_cg->GetControlSet( cg_cidx )->GetControl().GetExponent();
		Slider* exp_slider = (Slider*)pages[editing_page]->GetWidget( "ExponentSlider" );
//		cout << "Setting exponent slider at value " << exponent << endl;
		exp_slider->SetAdjustedValue( exponent );
	}
	else if( type == "JoyButton" )
	{
		// held/once
		Toggle* ho_toggle = (Toggle*)pages[editing_page]->GetWidget( "HeldOnceToggle" );
		ho_toggle->SetValue( editing_cg->GetControlSet( cg_cidx )->GetControl().GetOneTime() );
		// up/down
		Toggle* ud_toggle = (Toggle*)pages[editing_page]->GetWidget( "UpDownToggle" );
		ud_toggle->SetValue( editing_cg->GetControlSet( cg_cidx )->GetControl().GetJoyPushDown() );
	}
	else if( type == "Keyboard" )
	{
		// held/once
		Toggle* ho_toggle = (Toggle*)pages[editing_page]->GetWidget( "HeldOnceToggle" );
		ho_toggle->SetValue( editing_cg->GetControlSet( cg_cidx )->GetControl().GetOneTime() );
		// up/down
		Toggle* ud_toggle = (Toggle*)pages[editing_page]->GetWidget( "UpDownToggle" );
		ud_toggle->SetValue( editing_cg->GetControlSet( cg_cidx )->GetControl().GetKeyPushDown() );
	}
	else if( type == "MouseButton" )
	{
		// held/once
		Toggle* ho_toggle = (Toggle*)pages[editing_page]->GetWidget( "HeldOnceToggle" );
		ho_toggle->SetValue( editing_cg->GetControlSet( cg_cidx )->GetControl().GetOneTime() );
		// up/down
		Toggle* ud_toggle = (Toggle*)pages[editing_page]->GetWidget( "UpDownToggle" );
		ud_toggle->SetValue( editing_cg->GetControlSet( cg_cidx )->GetControl().GetMousePushDown() );
	}
	else if( type == "MouseMotion" )
	{
		// deadzone
		float deadzone = editing_cg->GetControlSet( cg_cidx )->GetControl().GetDeadzone();
		Slider* dz_slider = (Slider*)pages[editing_page]->GetWidget( "DeadzoneSlider" );
//		cout << "Setting deadzone slider at value " << deadzone << endl;
		dz_slider->SetAdjustedValue( deadzone );
		// gain
		float gain = editing_cg->GetControlSet( cg_cidx )->GetControl().GetGain();
		Slider* gain_slider = (Slider*)pages[editing_page]->GetWidget( "GainSlider" );
//		cout << "Setting gain slider at value " << gain << endl;
		gain_slider->SetAdjustedValue( gain );
		// exponent
		float exponent = editing_cg->GetControlSet( cg_cidx )->GetControl().GetExponent();
		Slider* exp_slider = (Slider*)pages[editing_page]->GetWidget( "ExponentSlider" );
//		cout << "Setting exponent slider at value " << exponent << endl;
		exp_slider->SetAdjustedValue( exponent );
	}
}

void Gui::DoneEditingControl( bool save_changes )
{
	if( !editing_control )
	{
		cout << "Tried to finish editing control, but never started." << endl;
		return;
	}

	if( save_changes )
	{
		string type = editing_cg->GetControlSet( editing_cg_cidx )->GetType();
		//string name = editing_cg->GetControlSet( cg_cidx )->GetName();

		if( type == "JoyAxis" )
		{
			// deadzone
			Slider* dz_slider = (Slider*)pages[editing_page]->GetWidget( "DeadzoneSlider" );
			float deadzone = dz_slider->GetAdjustedValue();
//			cout << "Setting deadzone at value " << deadzone << endl;
			editing_cg->GetControlSet( editing_cg_cidx )->GetControl().SetDeadzone( deadzone );
			// gain
			Slider* gain_slider = (Slider*)pages[editing_page]->GetWidget( "GainSlider" );
			float gain = gain_slider->GetAdjustedValue();
//			cout << "Setting gain at value " << gain << endl;
			editing_cg->GetControlSet( editing_cg_cidx )->GetControl().SetGain( gain );
			// exponent
			Slider* exp_slider = (Slider*)pages[editing_page]->GetWidget( "ExponentSlider" );
			float exponent = exp_slider->GetAdjustedValue();
//			cout << "Setting exponent at value " << exponent << endl;
			editing_cg->GetControlSet( editing_cg_cidx )->GetControl().SetExponent( exponent );
		}
		else if( type == "JoyButton" )
		{
			// held/once
			Toggle* ho_toggle = (Toggle*)pages[editing_page]->GetWidget( "HeldOnceToggle" );
			bool one_time = ho_toggle->GetValue();
//			cout << "Setting one-time to " << one_time << endl;
			editing_cg->GetControlSet( editing_cg_cidx )->GetControl().SetOneTime( one_time );
			// up/down
			Toggle* ud_toggle = (Toggle*)pages[editing_page]->GetWidget( "UpDownToggle" );
			bool is_down = ud_toggle->GetValue();
//			cout << "Setting joy push down to " << is_down << endl;
			editing_cg->GetControlSet( editing_cg_cidx )->GetControl().SetJoyPushDown( is_down );
		}
		else if( type == "Keyboard" )
		{
			// held/once
			Toggle* ho_toggle = (Toggle*)pages[editing_page]->GetWidget( "HeldOnceToggle" );
			bool one_time = ho_toggle->GetValue();
//			cout << "Setting one-time to " << one_time << endl;
			editing_cg->GetControlSet( editing_cg_cidx )->GetControl().SetOneTime( one_time );
			// up/down
			Toggle* ud_toggle = (Toggle*)pages[editing_page]->GetWidget( "UpDownToggle" );
			bool is_down = ud_toggle->GetValue();
//			cout << "Setting key push down to " << is_down << endl;
			editing_cg->GetControlSet( editing_cg_cidx )->GetControl().SetKeyPushDown( is_down );
		}
		else if( type == "MouseButton" )
		{
			// held/once
			Toggle* ho_toggle = (Toggle*)pages[editing_page]->GetWidget( "HeldOnceToggle" );
			bool one_time = ho_toggle->GetValue();
//			cout << "Setting one-time to " << one_time << endl;
			editing_cg->GetControlSet( editing_cg_cidx )->GetControl().SetOneTime( one_time );
			// up/down
			Toggle* ud_toggle = (Toggle*)pages[editing_page]->GetWidget( "UpDownToggle" );
			bool is_down = ud_toggle->GetValue();
//			cout << "Setting mouse push down to " << is_down << endl;
			editing_cg->GetControlSet( editing_cg_cidx )->GetControl().SetMousePushDown( is_down );
		}
		else if( type == "MouseMotion" )
		{
			// deadzone
			Slider* dz_slider = (Slider*)pages[editing_page]->GetWidget( "DeadzoneSlider" );
			float deadzone = dz_slider->GetAdjustedValue();
//			cout << "Setting deadzone at value " << deadzone << endl;
			editing_cg->GetControlSet( editing_cg_cidx )->GetControl().SetDeadzone( deadzone );
			// gain
			Slider* gain_slider = (Slider*)pages[editing_page]->GetWidget( "GainSlider" );
			float gain = gain_slider->GetAdjustedValue();
//			cout << "Setting gain at value " << gain << endl;
			editing_cg->GetControlSet( editing_cg_cidx )->GetControl().SetGain( gain );
			// exponent
			Slider* exp_slider = (Slider*)pages[editing_page]->GetWidget( "ExponentSlider" );
			float exponent = exp_slider->GetAdjustedValue();
//			cout << "Setting exponent at value " << exponent << endl;
			editing_cg->GetControlSet( editing_cg_cidx )->GetControl().SetExponent( exponent );
		}
	}

	ChangePage( editing_finished );
	editing_control = false;
	editing_cg = NULL;
	editing_page = "";
	editing_finished = "";
}

void Gui::AddOpponent()
{
	Label* opponents_label = (Label*)pages["SingleRace"]->GetWidget( "OpponentsLabel" );
	Button* add_opponent_button = (Button*)pages["SingleRace"]->GetWidget( "AddOpponentButton" );
	string button_text = add_opponent_button->GetText();
	string cars = "";

	if( button_text == "Clear" )
	{
		opponents_label->SetText( "" );
		settings.Set( "game.opponents", "" );
		add_opponent_button->SetText( "Add" );
		return;
	}
	
	Wheel<string>* opponent_car_wheel = (Wheel<string>*)pages["SingleRace"]->GetWidget( "OpponentCarWheel" );
	string opponent = opponent_car_wheel->GetValue();
	string text = opponents_label->GetText();
	std::istringstream is;
	is.str( text );
	int count = 0;
	string car = "";
	is >> car;

	if( car == "" )
	{
		cars = opponent;
	}
	else if( car == "Opponents:" )
	{
		string prevcars = "";
		string oldcar = "";
		while( is )
		{
			is >> oldcar;
			if( oldcar != "" )
			{
				prevcars += oldcar + " ";
				count++;
				oldcar = "";
			}
		}

		cars = prevcars + opponent;
	}
	text = "Opponents: " + cars;

	settings.Set( "game.opponents", cars );
	opponents_label->SetText( text );

	if( count == 2 )
	{
		add_opponent_button->SetText( "Clear" );
	}
}

void Gui::ProcessAction( string action )
{
	if( action == "" )
	{
		return;
	}
	else if( action == "Quit" )
	{
		Quit(0);
	}
	else if( action == "Lock" )
	{
		// get the mouse position
		mouse_lock_x = mouse_x;
		mouse_lock_y = mouse_y;
		is_locked = true;
	}
	else if( action == "Unlock" )
	{
		is_locked = false;
	}
	else if( action == "ReloadDisplay" )
	{
#if defined(__APPLE__) || defined(WIN32)
		if (ReloadDisplay(true)) // we only tell users to restart if the display change really wouldn't work
#else // POSIX
		if (0)
#endif			
			ChangePage( "RestartForChanges" );
		else
		{
			ReloadDisplay(false);
			
			if( cur_page == "DisplayOptions" )
				ChangePage( "Options" );
			else if( cur_page == "InGameDisplayOptions" )
				ChangePage( "InGameOptions" );
			else if( cur_page == "DisplayOptionsAdvanced" )
				ChangePage( "DisplayOptions" );
			else if( cur_page == "InGameDisplayOptionsAdvanced" )
				ChangePage( "InGameDisplayOptions" );
			else
				ChangePage( "Main" );
		}
	}
	else if( action == "UpdateMouse" )
	{
		mouse.UpdateSettings();

		if( cur_page == "MouseOptions" )
			ChangePage( "ControlsOptions" );
		else if( cur_page == "InGameMouseOptions" )
			ChangePage( "InGameControlsOptions" );
	}
	else if( action == "UpdateJoystick" )
	{
		gamecontrols.UpdateSettings();

		if( cur_page == "JoystickOptions" )
			ChangePage( "ControlsOptions" );
		else if( cur_page == "InGameJoystickOptions" )
			ChangePage( "InGameControlsOptions" );
	}
	else if( action == "UpdateCalibrations" )
	{
		calibrated = true;
		settings.Set( "joystick.calibrated", calibrated );

		if( cur_page == "JoystickCalibrate" )
			ChangePage( "JoystickOptions" );
		else if( cur_page == "InGameJoystickCalibrate" )
			ChangePage( "InGameJoystickOptions" );
	}
	else if( action == "UpdateControls" )
	{
		gamecontrols.UpdateSettings();
		world.UpdateSettings();

		if( cur_page == "ControlsOptions" )
			ChangePage( "Options" );
		else if( cur_page == "InGameControlsOptions" )
			ChangePage( "InGameOptions" );
	}
	else if( action == "UpdateSound" )
	{
		sound.UpdateSettings();
		world.UpdateSettings();

		if( cur_page == "SoundOptions" )
			ChangePage( "Options" );
		else if( cur_page == "InGameSoundOptions" )
			ChangePage( "InGameOptions" );
	}
	else if( action == "KeyboardControlOK" )
	{
		DoneEditingControl( true );
	}
	else if( action == "KeyboardControlCancel" )
	{
		DoneEditingControl( false );
	}
	else if( action == "KeyboardControlDelete" )
	{
		editing_cg->DeleteControl( editing_cg_cidx );
		DoneEditingControl( false );
	}
	else if( action == "JoyAxisControlOK" )
	{
		DoneEditingControl( true );
	}
	else if( action == "JoyAxisControlCancel" )
	{
		DoneEditingControl( false );
	}
	else if( action == "JoyAxisControlDelete" )
	{
		editing_cg->DeleteControl( editing_cg_cidx );
		DoneEditingControl( false );
	}
	else if( action == "JoyButtonControlOK" )
	{
		DoneEditingControl( true );
	}
	else if( action == "JoyButtonControlCancel" )
	{
		DoneEditingControl( false );
	}
	else if( action == "JoyButtonControlDelete" )
	{
		editing_cg->DeleteControl( editing_cg_cidx );
		DoneEditingControl( false );
	}
	else if( action == "MouseButtonControlOK" )
	{
		DoneEditingControl( true );
	}
	else if( action == "MouseButtonControlCancel" )
	{
		DoneEditingControl( false );
	}
	else if( action == "MouseButtonControlDelete" )
	{
		editing_cg->DeleteControl( editing_cg_cidx );
		DoneEditingControl( false );
	}
	else if( action == "MouseMotionControlOK" )
	{
		DoneEditingControl( true );
	}
	else if( action == "MouseMotionControlCancel" )
	{
		DoneEditingControl( false );
	}
	else if( action == "MouseMotionControlDelete" )
	{
		editing_cg->DeleteControl( editing_cg_cidx );
		DoneEditingControl( false );
	}
	else if( action == "AddOpponent" )
	{
		AddOpponent();
	}
/*	else if( action == "SingleRace" )
	{
		// nevermind...not going to bother setting up support to reload the list of opponents for now.
		// will find a better way to list them later.
		string opponents = "";
		settings.Get( "game.opponents", opponents );
		pages["SingleRace"]->GetWidget("Label")->SetText( "Opponents: " + opponents );
		ChangePage( "SingleRace" );
	}*/
	else if( action == "StartPracticeGame" )
	{
		pages[cur_page]->SelectDefault();
		state.SetGameMode( MODE_FREEDRIVE );
		LoadWorld();
		state.SetGameState( STATE_STAGING );
		Disable();
		pages[cur_page]->StartGame();
		bool record_replay = false;
		if( settings.Get( "game.record", record_replay ) )
		{
			if( record_replay )
			{
				replay.Start();
			}
		}
		else
		{
			settings.Set( "game.record", false );
		}
	}
	else if( action == "StartRace" )
	{
		pages[cur_page]->SelectDefault();
		state.SetGameMode( MODE_SINGLERACE );
		LoadWorld();
		state.SetGameState( STATE_STAGING );
		Disable();
		pages[cur_page]->StartGame();
		bool record_replay = false;
		if( settings.Get( "game.record", record_replay ) )
		{
			if( record_replay )
			{
				replay.Start();
			}
		}
		else
		{
			settings.Set( "game.record", false );
		}
	}
	else if( action == "StartNetworkGame" )
	{
		pages[cur_page]->SelectDefault();
		state.SetGameMode( MODE_NETMULTIFREE );
		pages[cur_page]->StartGame();

		bool net_host, net_success;
		string net_ip;
		string port_num = "1234";
		settings.Get( "network.host_game", net_host );
		settings.Get( "network.server_ip", net_ip );
		settings.Get( "network.server_port", port_num );
		int port = 0;
		std::istringstream ss;
		ss.str( port_num );
		ss >> port;

		multiplay.Disconnect();
		
		if( !net_host )
		{
			net_success = multiplay.Connect( net_ip, port );
		}
		else
		{
			net_success = multiplay.Host( port );
			LoadWorld();
		}

		if( net_success )
		{
			Disable();
			state.SetGameState( STATE_STAGING );
		}
		else
		{
			ChangePage( "ConnectionError" );
		}
	}
	else if( action == "StartReplay" )
	{
		pages[cur_page]->SelectDefault();
		Disable();
		string replay_n;
		settings.Get( "game.selected_replay", replay_n );
		if( !replay.PlayStart( replay_n ) )
		{
			ChangePage( "ReplayStartError" );
			Enable();
		}
	}
	else if( action == "Pause" )
	{
		if( state.GetGameMode() == MODE_NETMULTIFREE )
		{
			ChangePage( "NetGameLeaveConfirm" );
		}
		else if( ( state.GetGameMode() == MODE_SINGLERACE ) && ( state.GetGameState() == STATE_ENDRACE ) )
		{
			ChangePage( "StopRaceConfirm" );
		}
		else
		{	
			ChangePage( "InGameMenu" );
		}
		last_page = "";
		pages[cur_page]->SelectDefault();
		Enable();
	}
	else if( action == "ReturnToGame" )
	{
		pages[cur_page]->SelectDefault();
		Disable();
		MainUnpause();
	}
	else if( action == "RestartGame" )
	{
		pages[cur_page]->SelectDefault();
		Disable();
		state.SetGameState( STATE_STAGING );
		MainUnpause();
		ResetWorld( true );
	}
	else if( action == "InGameLeaveConfirm" )
	{
		if( state.GetGameMode() == MODE_SINGLERACE )
		{
			ChangePage( "StopRaceConfirm" );
		}
		else
		{
			ChangePage( "InGameLeaveConfirm" );
		}
	}
	else if( action == "LeaveGame" )
	{
		StopGame( "Main" );
	}
	else if( action == "RaceResults" )
	{
		world.DisplayRaceResults();
		UpdateResultPage();
		StopGame( "RaceResults" );
	}
	else if( action == "SimError" )
	{
		StopGame( "SimulationError" );
	}
	else
	{
		pages[cur_page]->SelectDefault();
		// go to a menu
		ChangePage( action );
	}
}

void Gui::Disable()
{
	//mouse.GetMousePos( mouse_x, mouse_y );
	menu_enabled = false;
}

void Gui::Enable()
{
	//SDL_WarpMouse( mouse_x, mouse_y );
	menu_enabled = true;
}

void Gui::StopGame( string menu )
{
	MainPause();

	replay.Stop();
	replay.PlayStop();
	OPTION<string> o = settings.GetStringOption( "game", "selected_replay" );
	vector<string> vs;
	Wheel<string>* select_replay_wheel = (Wheel<string>*)pages["Replays"]->GetWidget( "SelectReplayWheel" );
	select_replay_wheel->SetValueList( o.GetValueList() ); // this is the replay selector widget
	select_replay_wheel->SetOptionList( o.GetOptionList() );

	MainUnpause();
	UnloadWorld();
	state.SetGameState( STATE_INITIALMENU );
	ChangePage( menu );
	last_page = "";
	pages[cur_page]->SelectDefault();
	Enable();
}


void Gui::ChangePage( string page_name )
{
	if( pages.find( page_name ) != pages.end() )
	{
		page_switch_time = SDL_GetTicks();
		last_page = cur_page;
		cur_page = page_name;
		pages[cur_page]->ClearSettings();
	}
	else
	{
		cout << "Page not found! name: " << page_name << endl;
	}
}

void Gui::UpdateResultPage()
{
	Page *resultpage = GetPage("RaceResults");
	std::vector<RACERESULT> result = state.GetRaceResult();
	Widget* wgt;
	int mins;
	float secs;
	int total_laps = 0;
	settings.Get( "game.number_of_laps", total_laps );

	for (unsigned int i=0; i<4; i++)
	{
		if (i < result.size())
		{
			stringstream wgtname, wgttext;

			wgtname<<"RacePosition"<<i+1;
			wgt = resultpage->GetWidget(wgtname.str());
			wgttext<<i+1;
			wgt->SetText(wgttext.str());

			wgtname.str("");
			wgtname<<"Car"<<i+1;
			wgt = resultpage->GetWidget(wgtname.str());
			wgttext.str("");
			wgttext<<result[i].carname;
			wgt->SetText(wgttext.str());

			wgtname.str("");
			wgtname<<"Time"<<i+1;
			wgt = resultpage->GetWidget(wgtname.str());
			wgttext.str("");
			if( result[i].done )
			{
				mins = int(result[i].totaltime) / 60;
				secs = result[i].totaltime - mins * 60;
				wgttext<<setfill('0')<<setw(2)<<mins<<":"<<setfill('0')<<setw(6)<<fixed<<setprecision(3)<<secs;
			}
			else
			{
				wgttext << "+" << ( total_laps - result[i].numlaps );
			}
			wgt->SetText(wgttext.str());

			wgtname.str("");
			wgtname<<"BestLap"<<i+1;
			wgt = resultpage->GetWidget(wgtname.str());
			mins = (int)result[i].bestlap / 60;
			secs = result[i].bestlap - mins * 60;
			wgttext.str("");
			wgttext<<setfill('0')<<setw(2)<<mins<<":"<<setfill('0')<<setw(6)<<fixed<<setprecision(3)<<secs;
			wgt->SetText(wgttext.str());
		}
		else
		{
			stringstream wgtname;

			wgtname<<"RacePosition"<<i+1;
			wgt = resultpage->GetWidget(wgtname.str());
			wgt->SetText("");

			wgtname.str("");
			wgtname<<"Car"<<i+1;
			wgt = resultpage->GetWidget(wgtname.str());
			wgt->SetText("");

			wgtname.str("");
			wgtname<<"Time"<<i+1;
			wgt = resultpage->GetWidget(wgtname.str());
			wgt->SetText("");

			wgtname.str("");
			wgtname<<"BestLap"<<i+1;
			wgt = resultpage->GetWidget(wgtname.str());
			wgt->SetText("");
		}
	}
}
