/*
 * DeltaTime.cpp
 *
 *  Created on: 2009-07-07
 *      Author: wasyl
 */

#include "DeltaTime.h"

/*********************************************************************/

const DeltaInterval DeltaInterval::NONE(0.0, false);

/*********************************************************************/

DeltaTime::DeltaTime(double minDT, double maxDT, int maxFS)
	: minDT(minDT), maxDT(maxDT), maxFS(maxFS)
{
	running = false;
	halfAvgSleepTime = minDT * 0.5;
}

/*********************************************************************/

DeltaTime::DeltaTime()
	: minDT(0.017), maxDT(0.05), maxFS(3)
{
	running = false;
	halfAvgSleepTime = minDT * 0.5;
}

/*********************************************************************/

void DeltaTime::start()
{
	if (running) return;

	spareTime = 0.0;
	referenceTime = al_current_time();

	running = true;
}

/*********************************************************************/

void DeltaTime::stop()
{
	running = false;
}

/*********************************************************************/

void DeltaTime::restart()
{
	stop(); start();
}

/*********************************************************************/

double DeltaTime::getRawDT()
{
	double now = al_current_time();
	double dt = now - referenceTime;
	referenceTime = now;
	return dt;
}

/*********************************************************************/

DeltaInterval DeltaTime::delta()
{
	if (!running)
		return DeltaInterval::NONE;

	if (!pendingIntervals.empty())
	{
		DeltaInterval result = pendingIntervals.back();
		pendingIntervals.pop_back();
		return result;
	}

	double rawDT = this->getRawDT();

	double actualDT;

	if (rawDT < minDT)
	{
		actualDT = minDT;
		spareTime += actualDT - rawDT;

		while (spareTime > halfAvgSleepTime)
		{
			al_rest(minDT * 0.5);
			double yieldedTime = this->getRawDT();
			spareTime -= yieldedTime;

			halfAvgSleepTime = (4.0f * halfAvgSleepTime + yieldedTime * 0.5f) * 0.2f;
		}
	}
	else
		actualDT = rawDT;

	if (actualDT <= maxDT)
	{
		DeltaInterval interval(actualDT, false);
		return interval;
	}
	else
	{
		if (actualDT >= maxDT * maxFS)
			actualDT = maxDT * maxFS;

		double framesRatio = actualDT / maxDT;
		DeltaInterval maxInterval(maxDT, true);
		while (framesRatio > 1.0)
		{
			pendingIntervals.push_back(maxInterval);
			framesRatio -= 1.0;
		}

		DeltaInterval leftOver(maxDT * framesRatio, false);
		return leftOver;
	}
}
