///////////////////////////////////////////////////////////////////////////////
/// @file deTimer.cpp
///
/// @brief 
///
/// @author trajar
///
/// This file is the intellectual property of Novus Delta, LLC.. Usage of the
/// contents of this file is subject to the Destiny3D Member License which
/// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
///
/// This file is distributed "AS IS" without warranty of any kind.  Novus
/// Delta, LLC. does not guarantee the fitness of the contents of this file
/// for any particular purpose.
///
/// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.
///
/// <hr>
///                                 Change History
/// <hr>
///
/// @date Jun 2002
/// @author trajar
/// @remarks Creation
///
///////////////////////////////////////////////////////////////////////////////

#include "deTimer.hpp"

// static 
//-----------------------------------------------------------------------------
bool	deTimer::sm_bInit				= false;
bool	deTimer::sm_bPerformanceCounter	= false;
__int64 deTimer::sm_i64Freq				= 0;

//-----------------------------------------------------------------------------
// deTimer()
//-----------------------------------------------------------------------------
deTimer::deTimer() : m_i64Start(0), m_i64Elapsed(0), m_bRunning(false)
{
	// ensure operations are thread-safe
	ENSURE_LOCK( this, &m_SynchObject );

	// if not already initialized
	if(false == sm_bInit)
	{
		// initializing some static variables dependent on the system just once
		LARGE_INTEGER liFreq;
		if(TRUE == QueryPerformanceFrequency(&liFreq))
		{
			// only if the system is supporting High Performance
			sm_i64Freq = ((__int64)liFreq.HighPart << 32) + (__int64)liFreq.LowPart;
			sm_bPerformanceCounter = true;
		}
		else
			sm_bPerformanceCounter = false;
		sm_bInit = true;
	}
}

//-----------------------------------------------------------------------------
// bool SupportsHighResCounter()
//-----------------------------------------------------------------------------
_inline bool deTimer::SupportsHighResCounter()
{
	// ensure operations are thread-safe
	ENSURE_LOCK( this, &m_SynchObject );

	return sm_bPerformanceCounter;
}

//-----------------------------------------------------------------------------
// void UpdateElapsed()
//-----------------------------------------------------------------------------
_inline void deTimer::UpdateElapsed()
{
	// ensure operations are thread-safe
	ENSURE_LOCK( this, &m_SynchObject );

	if(true == sm_bPerformanceCounter)
	{
		QueryPerformanceCounter(&m_liCount);
		m_i64Counts = ((__int64)m_liCount.HighPart << 32) + (__int64)m_liCount.LowPart;
		//Transform in microseconds
		(m_i64Counts *= 1000000) /= sm_i64Freq;
	}
	else
		//Transform milliseconds to microseconds
		m_i64Counts = (__int64)GetTickCount() * 1000;
	if(m_i64Counts > m_i64Start)
		m_i64Elapsed = m_i64Counts - m_i64Start;
	else
		//Eliminate possible number overflow (0x7fffffffffffffff is the maximal __int64 positive number)
		m_i64Elapsed = (0x7fffffffffffffff - m_i64Start) + m_i64Counts;
}

//-----------------------------------------------------------------------------
// void StartTimer()
//-----------------------------------------------------------------------------
void deTimer::StartTimer()
{
	// ensure operations are thread-safe
	ENSURE_LOCK( this, &m_SynchObject );

	if(true == sm_bPerformanceCounter)
	{
		QueryPerformanceCounter(&m_liCount);
		m_i64Start = ((__int64)m_liCount.HighPart << 32) + (__int64)m_liCount.LowPart;
		//Transform in microseconds
		(m_i64Start *= 1000000) /= sm_i64Freq;
	}
	else
		//Transform milliseconds to microseconds
		m_i64Start = (__int64)GetTickCount() * 1000;
	m_bRunning = true;
}

//-----------------------------------------------------------------------------
// void StopTimer()
//-----------------------------------------------------------------------------
void deTimer::StopTimer()
{
	// ensure operations are thread-safe
	ENSURE_LOCK( this, &m_SynchObject );

	UpdateElapsed();
	m_bRunning = false;
}

//-----------------------------------------------------------------------------
// __int64 GetTimer()
//-----------------------------------------------------------------------------
s64 deTimer::GetTime( void )
{
	// ensure operations are thread-safe
	ENSURE_LOCK( this, &m_SynchObject );

	if(true == m_bRunning)
		UpdateElapsed();
	return m_i64Elapsed;
}