#include "cTiming.hpp"

/*** Custom Header Files ***/
#include "../UtilityEngine/cUtility.hpp"

using TimingEngine::cTiming;
using UtilityEngine::cUtility;

/*static*/ cTiming* cTiming::sp_inst = nullptr;

cTiming::cTiming( const unsigned long int ftp /*= 30*/ )
: m_ftp(ftp), m_rate(1000 / ftp), m_nextTime(0), m_start(SDL_GetTicks()), m_lastTime(0.0f), m_frameTime(0.0f)
{
	Setup();
}

cTiming::~cTiming()
{
	CleanUp();
}

cTiming& cTiming::operator=( const cTiming& copy )
{
	if (this != &copy)
		setFTP(copy.getFTP());

	return *this;
}

///Functions
/*static*/ cTiming& cTiming::Inst()
{
	if (sp_inst == nullptr)
	    sp_inst = new cTiming();
	return *sp_inst;
}

/*static*/ void cTiming::Delete()
{
	delete sp_inst;
	sp_inst = nullptr;
}

const bool cTiming::Initialize() const
{
	bool rtn = IsInit();

	if (rtn == false) {
		if(  SDL_Init( SDL_INIT_TIMER ) == 0  ) {
			cUtility::Inst().Message("Timer Initialized.");
			rtn = true;
		} else
			cUtility::Inst().Message("Could not initialize timer. SDL_Init(SDL_INIT_TIMER):", __AT__, cUtility::eTypeSDL::SDL);
	}

	return rtn;
}

void cTiming::Setup()
{
	m_nextTime = SDL_GetTicks();
	AddTimeandRate();
}

void cTiming::CleanUp()
{}

void cTiming::Time()
{
	SDL_Delay(TimeLeft());
	AddTimeandRate();
	m_frameTime = FrameTime();
	//m_start = SDL_GetTicks();
}

const float/*unsigned long int*/ cTiming::FrameTime()
{
	/*unsigned long int rtn = 0;
	unsigned long int end = SDL_GetTicks();

	rtn = end - m_start;

	m_start = end;

	return rtn;*/

	/* for keeping track of timing */
	unsigned long int thisTime = SDL_GetTicks();

	m_lastTime = (float)thisTime - 30;
	

	thisTime = SDL_GetTicks();
	return (float)(thisTime - m_lastTime) / m_ftp;
}

///Sets
void cTiming::setFTP( const unsigned long int ftp /*= 30*/ )
{
	m_ftp = ftp;
	m_rate = 1000 / m_ftp;
	Setup();
}

///Gets
const unsigned long int cTiming::getFTP() const
{
	return m_ftp;
}

const bool cTiming::IsInit() const
{
	bool rtn = false;

	if (SDL_WasInit(SDL_INIT_TIMER) != 0) {
		cUtility::Inst().Message("Timer is initialized");
		rtn = true;
	} else
		cUtility::Inst().Message("Timer is not initialized.");

	return rtn;
}

const float cTiming::getFrameTime() const
{
	return m_frameTime;
}

///Private
///Functions
const unsigned long int cTiming::TimeLeft()
{
	unsigned long int now = SDL_GetTicks();

	if(m_nextTime <= now)
		return 0;
	else
		return m_nextTime - now;
}

void cTiming::AddTimeandRate()
{
	m_nextTime += m_rate;
}
