// ElapsedTime.cpp: implementation of the CElapsedTime class.
//
//////////////////////////////////////////////////////////////////////

#include <afxwin.h>         // MFC core and standard components
#include "ElapsedTime.h"

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

CElapsedTime::CElapsedTime()
{
	m_i64Maxi64Int = 0xffffffffffffffff;
	// check on available timers here
	// check for multimedia timer
	m_bMultimedia = TRUE;
	UINT uiCapSize = sizeof(TIMECAPS);
	MMRESULT mmresultTest = timeGetDevCaps(&m_tcMMTimerCapability,uiCapSize);
	if((timeGetDevCaps(&m_tcMMTimerCapability,uiCapSize)==TIMERR_STRUCT)||(m_tcMMTimerCapability.wPeriodMax <= 0))	// (ptc.wPeriodMax <= 0) is a guess
	{
		m_bMultimedia = FALSE;
	}

	QueryPerformanceFrequency((LARGE_INTEGER*)&m_i64Frequency);
	LARGE_INTEGER lrgiTest;	//test variable
	if((QueryPerformanceCounter(&lrgiTest))&&(m_i64Frequency!=0))
	{
		timerElapsedTypeAvailable = typHighPerformance;
	}
	else if(m_bMultimedia)	// check for multimedia timer
	{
		timerElapsedTypeAvailable = typMultimedia;
	}
	else
	{
		timerElapsedTypeAvailable = typeStandard;	// assume standard unless find out otherwise
	}
	if(m_bMultimedia)
	{
		timeBeginPeriod(m_tcMMTimerCapability.wPeriodMin);	// multimedia timer minimum resolution
	}
}

CElapsedTime::~CElapsedTime()
{
	if(m_bMultimedia)
	{
		timeEndPeriod(m_tcMMTimerCapability.wPeriodMin);	// multimedia timer minimum resolution
	}
}

int CElapsedTime::iStartElapsedTimer()
{
	int iReturn = -1;
	DWORD  dwTimeTemp;
	__int64  i64TimeTemp;

	switch(timerElapsedTypeAvailable)
	{
	case typHighPerformance:
		if(QueryPerformanceCounter((LARGE_INTEGER*)&i64TimeTemp))
		{
			vi64TimeLast.push_back(i64TimeTemp);
			vi64TimeStart.push_back(i64TimeTemp);
			iReturn = vi64TimeLast.size()-1;
		}
		break;
	case typMultimedia:
		dwTimeTemp = timeGetTime();
		vdwTimeLast.push_back(dwTimeTemp);
		vdwTimeStart.push_back(dwTimeTemp);
		iReturn = vdwTimeLast.size()-1;
		break;
	default:
	case typeStandard:
		dwTimeTemp = GetTickCount();
		vdwTimeLast.push_back(dwTimeTemp);
		vdwTimeStart.push_back(dwTimeTemp);
		iReturn = vdwTimeLast.size()-1;
		break;
	}
	return(iReturn);
}

double CElapsedTime::dGetElapsedTimeSec(int iTimerIndex)
{	
	// returns the time elapsed since the last call to this function (for a particular timer)
	double dReturn = -1;
	DWORD  dwTimeTemp;
	__int64  i64TimeTemp;

	switch(timerElapsedTypeAvailable)
	{
	case typHighPerformance:
		if((iTimerIndex < vi64TimeLast.size())&&(QueryPerformanceCounter((LARGE_INTEGER*)&i64TimeTemp)))
		{
			if(vi64TimeLast[iTimerIndex] > i64TimeTemp)
			{
				dReturn = m_i64Maxi64Int - vi64TimeLast[iTimerIndex] + i64TimeTemp;
			}
			else
			{
				dReturn = (i64TimeTemp - vi64TimeLast[iTimerIndex]);
			}
			vi64TimeLast[iTimerIndex] = i64TimeTemp;
			dReturn /= m_i64Frequency;	// assume not zero
		}
		break;
	case typMultimedia:
		dwTimeTemp = timeGetTime();
		if(vdwTimeLast[iTimerIndex] > dwTimeTemp)
		{	// wrapped around
			dReturn = ULONG_MAX - vdwTimeLast[iTimerIndex] + dwTimeTemp;
		}
		else
		{
			dReturn = dwTimeTemp - vdwTimeLast[iTimerIndex];
		}
		vdwTimeLast[iTimerIndex] = dwTimeTemp;
		break;
	default:
	case typeStandard:
		dwTimeTemp = GetTickCount();
		if(vdwTimeLast[iTimerIndex] > dwTimeTemp)
		{	// wrapped around
			dReturn = ULONG_MAX - vdwTimeLast[iTimerIndex] + dwTimeTemp;
		}
		else
		{
			dReturn = dwTimeTemp - vdwTimeLast[iTimerIndex];
		}
		vdwTimeLast[iTimerIndex] = dwTimeTemp;
		break;
	}
	return(dReturn);
}



double CElapsedTime::dGetTimeSinceStartSec(int iTimerIndex)
{
	// the time since the start of this timer
	double dReturn = -1;
	DWORD  dwTimeTemp;
	__int64  i64TimeTemp;

	switch(timerElapsedTypeAvailable)
	{
	case typHighPerformance:
		if((iTimerIndex < vi64TimeStart.size())&&(QueryPerformanceCounter((LARGE_INTEGER*)&i64TimeTemp)))
		{
			if(vi64TimeStart[iTimerIndex] > i64TimeTemp)
			{
				dReturn = m_i64Maxi64Int - vi64TimeStart[iTimerIndex] + i64TimeTemp;
			}
			else
			{
				dReturn = (i64TimeTemp - vi64TimeStart[iTimerIndex]);
			}
			dReturn /= m_i64Frequency;	// assume not zero
		}
		break;
	case typMultimedia:
		dwTimeTemp = timeGetTime();
		if(vdwTimeStart[iTimerIndex] > dwTimeTemp)
		{	// wrapped around
			dReturn = ULONG_MAX - vdwTimeStart[iTimerIndex] + dwTimeTemp;
		}
		else
		{
			dReturn = dwTimeTemp - vdwTimeStart[iTimerIndex];
		}
		break;
	default:
	case typeStandard:
		dwTimeTemp = GetTickCount();
		if(vdwTimeStart[iTimerIndex] > dwTimeTemp)
		{	// wrapped around
			dReturn = ULONG_MAX - vdwTimeStart[iTimerIndex] + dwTimeTemp;
		}
		else
		{
			dReturn = dwTimeTemp - vdwTimeStart[iTimerIndex];
		}
		break;
	}
	return(dReturn);
}

