/*    Zonic the Hog.  A silly Sonic-like game written for Speedhack 2007
 *    Copyright (c) 2007 Steven Wallace / Chedda Cheeze
 *    email: steven.t.wallace @ gmail. com
 *
 *    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 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.,
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
 
// Timer.cpp: implementation of the Timer class.
//
//////////////////////////////////////////////////////////////////////


#include <allegro.h>
#ifdef WIN32
#include <winalleg.h>
#else
#include <unistd.h>
#include <sys/time.h>
#endif
#include "Timer.h"
#include <math.h>
#include <stdio.h>


volatile int speed_counter = 0;
void TimerUpdateFunction() {
	speed_counter++;
}
END_OF_FUNCTION(TimerUpdateFunction);



//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

Timer::Timer()
: mode(TIME_VARIABLE)
{
#ifdef WIN32
	// Windows code
	LARGE_INTEGER temp;
	
	QueryPerformanceFrequency(&temp);
	pcFrequency = temp.QuadPart;

	QueryPerformanceCounter(&temp);
	lastTime = temp.QuadPart;
#else
	// Unix code
	timeval tv;
	gettimeofday(&tv,NULL);

	lastTime = tv;
#endif

	refresh = get_refresh_rate();
	if(refresh > 0) refresh1 = 1.0f/refresh;
	else refresh1 = 0.0f;
}

Timer::~Timer()
{

}


// Returns the time elapsed as percentage of a second
// since the last call to this function
double Timer::TimeElapsed() {
	if(mode == TIME_CONST) {
		while(speed_counter == 0) rest(0);
		speed_counter = 0;
	}
	
#ifdef WIN32
	// Windows code
	LARGE_INTEGER temp;
	QueryPerformanceCounter(&temp);
	double ret = double(temp.QuadPart-lastTime)/pcFrequency;
	lastTime = temp.QuadPart;
#else
	// Unix code
	timeval tv;
	gettimeofday(&tv,NULL);

	long ds = tv.tv_sec - lastTime.tv_sec;
	long dus = tv.tv_usec - lastTime.tv_usec;

	lastTime = tv;
	long usecs = ds * 1000000 + dus;
	double ret = usecs / 1000000.0f;
#endif

	// If the user's system is lagging, don't penalize them with a ridiculous 
	// multiplier.
	if(ret > 0.25f) ret = 0.001f;

	// If we're running faster than the monitor refresh speed, then 
	// hold up briefly so that we don't waste too much time.
	//else if(ret < refresh1) rest((int)((refresh1 - ret) *1000));
	return ret;

}


// Ensures that your target FPS is a multiple of the screen's refresh rate.
// This function is currently not finished
void Timer::FixConstRate() {
	/*
	printf("Refresh: %d\n", refresh);
	printf("Requested: %d\n", targetFPS);
	refresh = 127;
	
	if(refresh <= 0) return;
	
	if(targetFPS % refresh != 0) {
		// Find closest multiple of refresh to targetFPS
		int i;
		int closest = 1;
		int olddiff, diff = fabs(refresh*1 - targetFPS);
		for(i=2; ;i++) {
			olddiff = diff;
			diff = fabs(i * refresh - targetFPS);
			if( diff <= fabs(i * closest)) closest = i;
			if(olddiff - diff <= 0) break;
		}
		
		if(closest == 0) return;
		else targetFPS = closest * refresh;
	}
	
	printf("Fixed: %d\n", targetFPS);*/
}

// Sets the timer to run at a constant rate.
// This means that TimeElapsed will block until that time has been reached, and
// will return the exact time since the last call to it.
void Timer::SetConstRate(int fps) {
	targetFPS = fps;
	mode = TIME_CONST;
	
	install_timer();
	LOCK_VARIABLE(speed_counter);
	LOCK_FUNCTION(TimerUpdateFunction);
	install_int_ex(TimerUpdateFunction, BPS_TO_TIMER(targetFPS));
}


// Sets the timer to run at a variable rate.
// This means that it runs as fast as possible, returning exactly how much time
// has elapsed since the last call to TimeElapsed().
void Timer::SetVariableRate() {
	mode = TIME_VARIABLE;
}



