/***************************************************************************
 *			timer.cpp
 *
 *  Wed Jun  1 21:31:45 2005
 *  Copyright  2005  Joe Venzon
 *  joe@venzon.net
 ****************************************************************************/

/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
 
#include "timer.h"

TIMER::TIMER()
{
	time.push_back(0.0);
	lastlap.push_back(0.0);
	bestlap.push_back(0.0);
	totaltime.push_back(0.0);
	num_laps.push_back(0);
	pretime = 0.0;
	
	/*lastlap = 0.0;
	bestlap = 0.0;
	
	ifstream blf;
	blf.open((settings.GetSettingsDir() + "/bestlap.txt").c_str());
	if (blf)
	{
		blf >> bestlap;
		blf.close();
	}*/
	
	loaded = false;
}

TIMER::~TIMER()
{
	//if (loaded)
		//glDeleteTextures(1, &timerbox);
	//textures.Delete(timerbox);
	//textures.Delete("hud/timerbox.png");
	timerbox.Unload();
	
	SaveRecords();

	time.clear();
	lastlap.clear();
	bestlap.clear();
	totaltime.clear();
	num_laps.clear();
}

void TIMER::SaveRecords()
{
	for (map <string, CONFIGFILE>::iterator i = trackrecords.begin(); i != trackrecords.end(); i++)
	{
		i->second.Write();
	}
}

//void TIMER::Lap(bool storelastlap)
void TIMER::Lap(const string & track, const string & carname, const int carid, const int prevsector, const int nextsector, const bool countit)
{
	//cout << "Lap: " << track << ", " << carname << ", " << carid << ", " << prevsector << ", " << nextsector << ", " << countit << endl;
	
	LoadCurrentTrackIfNotLoaded();
	
	CONFIGFILE & trackrecord = trackrecords[track];
	//lastlap = time;

	if (countit)
	{
		/*if (lastlap < bestlap || bestlap == 0.0)
		{
			bestlap = lastlap;
			ofstream blf;
			blf.open((settings.GetSettingsDir() + "/bestlap.txt").c_str());
			blf << bestlap << endl;
			blf.close();
		}*/
		
		if (carid == 0) //this is the player car
		{
			stringstream secstr;
			secstr << "sector " << nextsector;
			trackrecord.SetParam("last." + secstr.str(), (float) time[carid]);
			trackrecord.SetParam("last.car", carname);

			float prevbest;
			trackrecord.SuppressError(true);
			bool haveprevbest = trackrecord.GetParam(carname + "." + secstr.str(), prevbest);
			trackrecord.SuppressError(false);
			if (time[carid] < prevbest || !haveprevbest)
				trackrecord.SetParam(carname + "." + secstr.str(), (float) time[carid]);
		}

		if (nextsector == 0)
		{
			lastlap[carid] = time[carid];
			if (time[carid] < bestlap[carid] || bestlap[carid] == 0.0)
				bestlap[carid] = time[carid];
			num_laps[carid] = num_laps[carid] + 1;
		}
	}
	
	if (nextsector == 0)
	{
		totaltime[carid] += time[carid];
		time[carid] = 0.0;
		num_laps[carid] = 0;
	}
}

void TIMER::TickTimer(const float timefactor, const float fps)
{
	vector<double>::iterator i;

	if (state.GetGameState() == STATE_PLAYING)
	{
		for (i=time.begin(); i!=time.end(); i++)
		{
			(*i) += timefactor / fps;
		}

		if (pretime > 0.0) pretime += timefactor / fps;
		if (pretime > (STAGING_TIME + 1.0)) pretime = 0.0;
	}
	else if (state.GetGameState() == STATE_STAGING)
	{
		pretime += timefactor / fps;
		
		if (pretime > STAGING_TIME)
		{
			for (i=time.begin(); i!=time.end(); i++)
			{
				(*i) = 0.0;
			}
			//pretime = 0.0;
			state.SetGameState(STATE_PLAYING);
		}
	}
}

void TIMER::Draw()
{
	float boxx, boxy;
	
	boxx = 0.01;
	boxy = 0.01;
	
	float boxoffsety = -0.024;
	
	utility.Draw2D(boxx, boxy+boxoffsety, 0.5+boxx, 0.125+boxy+boxoffsety, &timerbox);
	
	char tempchar[256];
	
	float secs;
	int min;
	
	float r,g,b;
	r=g=b=0.0;
	
	float cx, cy;

	//cx = 0.03+boxx;
	//cy = 0.016+boxy;
	cx = 0.029+boxx;
	cy = 0.022+boxy;
	if (state.GetGameState() == STATE_STAGING)
	{
		SecsToSecsMin(STAGING_TIME - pretime, secs, min);
		sprintf(tempchar, "%02d:%06.3f", min, secs);
		font.Print(cx, cy, tempchar, 0, 6, 1,0,0);
		if (time.size() > 1) font.Print(cx, cy+0.04, tempchar, 0, 6, 1,0,0);
		if (secs < 1.0)
		{
			sprintf(tempchar, "READY!");
			int fontsize = 10;
			float sx = (1.0 - font.Width(tempchar, 1, fontsize)) / 2.0;
			float sy = (1.0 - font.Height(tempchar, 1, fontsize)) / 2.0;
			font.Print(sx, sy, tempchar, 1, fontsize, 1,1,0);
		}
		else
		{
			sprintf(tempchar, "%1.0f", secs);
			int fontsize = 11;
			float sx = (1.0 - font.Width(tempchar, 1, fontsize)) / 2.0;
			float sy = (1.0 - font.Height(tempchar, 1, fontsize)) / 2.0;
			font.Print(sx, sy, tempchar, 1, fontsize, 1,0,0);
		}
	}
	else
	{
		SecsToSecsMin(time[0], secs, min);
		sprintf(tempchar, "%02d:%06.3f", min, secs);
		font.Print(cx, cy, tempchar, 0, 6, r,g,b);
		if (time.size() > 1)
		{
			SecsToSecsMin(time[1], secs, min);
			sprintf(tempchar, "%02d:%06.3f", min, secs);
			font.Print(cx, cy+0.04, tempchar, 0, 6, 1,0,0);
		}

		SecsToSecsMin(pretime - STAGING_TIME, secs, min);
		if (secs > 0.0)
		{
			sprintf(tempchar, "GO!");
			int fontsize = 11;
			float sx = (1.0 - font.Width(tempchar, 1, fontsize)) / 2.0;
			float sy = (1.0 - font.Height(tempchar, 1, fontsize)) / 2.0;
			font.Print(sx, sy, tempchar, 1, fontsize, 0,1,0);
		}
	}
	//cy += vertspacing;
	
	CONFIGFILE & trackrecord = trackrecords[state.GetTrackName()]; //may insert a new CONFIGFILE.  therefore, this function can't be const
	string carname = state.GetCarName(0);
	trackrecord.SuppressError(true);
	{
		//cx = 0.195+boxx;
		cx = 0.193+boxx;
		float player_lastlap = 0;
		string lastcar;
		if (trackrecord.GetParam("last.car", lastcar))
		{
			if (lastcar == carname)
				if (!trackrecord.GetParam("last.sector 0", player_lastlap))
					player_lastlap = 0;
		}
		else
			player_lastlap = 0;
		SecsToSecsMin(player_lastlap, secs, min);
		if (player_lastlap != 0.0)
			sprintf(tempchar, "%02d:%06.3f", min, secs);
		else
			sprintf(tempchar, "--:--.---");
		font.Print(cx, cy, tempchar, 0, 6, r,g,b);
		//cy += vertspacing;
		if (lastlap.size() > 1)
		{
			SecsToSecsMin(lastlap[1], secs, min);
			if (lastlap[1] != 0.0)
				sprintf(tempchar, "%02d:%06.3f", min, secs);
			else
				sprintf(tempchar, "--:--.---");
			font.Print(cx, cy+0.04, tempchar, 0, 6, 1,0,0);
		}
	}
	
	{
		cx = 0.35+boxx;
		float player_bestlap = 0;
		if (!trackrecord.GetParam(carname + ".sector 0", player_bestlap))
			player_bestlap = 0;
		SecsToSecsMin(player_bestlap, secs, min);
		if (player_bestlap != 0.0)
			sprintf(tempchar, "%02d:%06.3f", min, secs);
		else
			sprintf(tempchar, "--:--.---");
		font.Print(cx, cy, tempchar, 0, 6, r,g,b);
		//cy += vertspacing;
		if (bestlap.size() > 1)
		{
			SecsToSecsMin(bestlap[1], secs, min);
			if (bestlap[1] != 0.0)
				sprintf(tempchar, "%02d:%06.3f", min, secs);
			else
				sprintf(tempchar, "--:--.---");
			font.Print(cx, cy+0.04, tempchar, 0, 6, 1,0,0);
		}
	}
	trackrecord.SuppressError(false);
	
	/*if (state.GetGameState() == STATE_STAGING)
	{
		cx = 0.03+boxx;
		cy = 0.0214+boxy;
		cy += 0.1;
		SecsToSecsMin(pretime, secs, min);
		sprintf(tempchar, "%02d:%06.3f", min, secs);
		font.Print(cx, cy, tempchar, 0, 6, 1,0,0);
	}*/
}

void TIMER::SecsToSecsMin(const double t, float & secs, int & min) const
{
	min = (int) t / 60;
	secs = t - min*60;
}

/*void TIMER::ResetBest()
{
	bestlap = 0.0;
	//bestlap = lastlap;
	ofstream blf;
	blf.open((settings.GetSettingsDir() + "bestlap.txt").c_str());
	blf << bestlap << endl;
	blf.close();
}

void TIMER::ResetLast()
{
	lastlap = 0.0;
}

void TIMER::Reset()
{
	time = 0.0;
	pretime = 0.0;
}*/

void TIMER::Load()
{
	//if (loaded)
		//glDeleteTextures(1, &timerbox);
	
	timerbox.Load("hud/timerbox.png", false);
	
	loaded = true;
}

void TIMER::LoadCurrentTrackIfNotLoaded()
{
	CONFIGFILE & trackrecord = trackrecords[state.GetTrackName()];
	if (trackrecord.LoadedFile().empty())
	{
		trackrecord.SuppressError(true);
		trackrecord.Load(settings.GetDataDir() + "/tracks/" + state.GetTrackName() + "/records.txt");
		trackrecord.SuppressError(false);
	}
}

void TIMER::Clear()
{
	vector<double>::iterator i;

	for (i=time.begin(); i!=time.end(); i++)
	{
		(*i) = 0.0;
	}
	for (i=lastlap.begin(); i!=lastlap.end(); i++)
	{
		(*i) = 0.0;
	}
	for (i=bestlap.begin(); i!=bestlap.end(); i++)
	{
		(*i) = 0.0;
	}
	for (i=totaltime.begin(); i!=totaltime.end(); i++)
	{
		(*i) = 0.0;
	}
	pretime = 0.0;
	SaveRecords();
	trackrecords.clear();
	LoadCurrentTrackIfNotLoaded();
}

void TIMER::InitOpponentTimer(int number_of_opponent)
{
	int i;
	time.clear();
	time.push_back(0.0);
	lastlap.clear();
	lastlap.push_back(0.0);
	bestlap.clear();
	bestlap.push_back(0.0);
	totaltime.clear();
	totaltime.push_back(0.0);

	if (number_of_opponent > 0)
	{
		for (i=0; i<number_of_opponent; i++)
		{
			time.push_back(0.0);
			lastlap.push_back(0.0);
			bestlap.push_back(0.0);
			totaltime.push_back(0.0);
		}
	}
}
