#include "Time.h"
namespace gln {
#ifdef _WIN32

#define MEAN_AND_LEAN
#include <windows.h>

static bool _hasPerformanceCounter;
static unsigned int _t0_32;
static __int64 _t0_64;
static double _resolution = 0.0;
static bool _initialized = false;

static void _init() {

	__int64 freq;

	// Check if we have a performance counter
	if( QueryPerformanceFrequency( (LARGE_INTEGER *)&freq ) )
	{
		// Performance counter is available => use it!
		_hasPerformanceCounter = true;

		// Counter resolution is 1 / counter frequency
		_resolution = 1.0 / (double)freq;

		// Set start time for timer
		QueryPerformanceCounter( (LARGE_INTEGER *)&_t0_64 );
	}
	else
	{
		// No performace counter available => use the tick counter
		_hasPerformanceCounter = 0;

		// Counter resolution is 1 ms
		_resolution = 0.001;

		// Set start time for timer
		_t0_32 = timeGetTime();
	}

	_initialized = true;
}

double PerformanceTimer::get() {
	if (_initialized == false)
	_init();
	double t;
	__int64 t_64;

	if( _hasPerformanceCounter ) {
		QueryPerformanceCounter( (LARGE_INTEGER *)&t_64 );
		t = (double)(t_64 - _t0_64);
	}
	else
	{
		t = (double)(timeGetTime() - _t0_32);
	}

	// Calculate the current time in seconds
	return t * _resolution;
}

void PerformanceTimer::set(double t) {
	if (_initialized == false)
	_init();
	__int64 t_64;

	if( _hasPerformanceCounter )
	{
		QueryPerformanceCounter( (LARGE_INTEGER *)&t_64 );
		_t0_64 = t_64 - (__int64)(t/_resolution);
	}
	else
	{
		_t0_32 = timeGetTime() - (int)(t*1000.0);
	}
}

#else

#include <sys/time.h>

static double _resolution = 0.0;
static long long _t0 = 0;
static bool _initialized = false;

static void _init() {
	// "Resolution" is 1 us
	_resolution = 1e-6;

	// Set start-time for timer
	struct timeval tv;
	gettimeofday(&tv, 0);
	_t0 = (long long) tv.tv_sec * (long long) 1000000 + (long long) tv.tv_usec;

	_initialized = true;
}

double PerformanceTimer::get() {
	if (_initialized == false)
		_init();
	struct timeval tv;
	gettimeofday(&tv, 0);
	long long t = (long long) tv.tv_sec * (long long) 1000000
			+ (long long) tv.tv_usec;
	return (double) (t - _t0) * _resolution;
}

void PerformanceTimer::set(double t) {
	if (_initialized == false)
		_init();
	long long t1;
	struct timeval tv;

	gettimeofday(&tv, 0);
	t1 = (long long) tv.tv_sec * (long long) 1000000 + (long long) tv.tv_usec;

	// Calulate new starting time
	_t0 = t1 - (long long) (t / _resolution);
}

#endif // else _WIN32
} // namespace grln
