#include <windows.h>

#include ".\timer.h"

#pragma comment( lib, "winmm.lib" )

float CTimer::Time( eTimeFlags tfCommand )
{

  static BOOL       m_bTimerInitialized = FALSE;
  static BOOL       m_bUsingQPF         = FALSE;
  static LONGLONG   m_llQPFTicksPerSec  = 0;

  if ( tfCommand == TF_REINITIALIZE )
  {
    m_bTimerInitialized = FALSE;
  }

  // Initialize the timer
  if ( !m_bTimerInitialized )
  {
    m_bTimerInitialized = TRUE;

    // Use QueryPerformanceFrequency() to get frequency of timer.  If QPF is
    // not supported, we will timeGetTime() which returns milliseconds.
    LARGE_INTEGER qwTicksPerSec;
    m_bUsingQPF = QueryPerformanceFrequency( &qwTicksPerSec );
    if ( m_bUsingQPF )
    {
      m_llQPFTicksPerSec = qwTicksPerSec.QuadPart;
    }
  }

  if ( m_bUsingQPF )
  {
    static LONGLONG m_llStopTime        = 0;
    static LONGLONG m_llLastElapsedTime = 0;
    static LONGLONG m_llBaseTime        = 0;
    double fTime;
    double fElapsedTime;
    LARGE_INTEGER qwTime;
    
    // Get either the current time or the stop time, depending
    // on whether we're stopped and what command was sent
    if ( ( m_llStopTime != 0 )
    &&   ( tfCommand != TF_START )
    &&   ( tfCommand != TF_GETABSOLUTETIME ) )
    {
      qwTime.QuadPart = m_llStopTime;
    }
    else
    {
      QueryPerformanceCounter( &qwTime );
    }

    // Return the elapsed time
    if ( tfCommand == TF_GETELAPSEDTIME )
    {
      fElapsedTime = (double)( qwTime.QuadPart - m_llLastElapsedTime ) / (double)m_llQPFTicksPerSec;
      m_llLastElapsedTime = qwTime.QuadPart;
      return (float)fElapsedTime;
    }

    // Return the current time
    if ( tfCommand == TF_GETAPPTIME )
    {
      double fAppTime = (double)( qwTime.QuadPart - m_llBaseTime ) / (double)m_llQPFTicksPerSec;
      return (float)fAppTime;
    }

    // Reset the timer
    if ( tfCommand == TF_RESET )
    {
      m_llBaseTime        = qwTime.QuadPart;
      m_llLastElapsedTime = qwTime.QuadPart;
      return 0.0f;
    }

    // Start the timer
    if ( tfCommand == TF_START )
    {
      m_llBaseTime += qwTime.QuadPart - m_llStopTime;
      m_llStopTime = 0;
      m_llLastElapsedTime = qwTime.QuadPart;
      return 0.0f;
    }

    // Stop the timer
    if ( tfCommand == TF_STOP )
    {
      m_llStopTime = qwTime.QuadPart;
      m_llLastElapsedTime = qwTime.QuadPart;
      return 0.0f;
    }

    // Advance the timer by 1/10th second
    if ( tfCommand == TF_ADVANCE )
    {
      m_llStopTime += m_llQPFTicksPerSec / 10;
      return 0.0f;
    }

    if ( tfCommand == TF_GETABSOLUTETIME )
    {
      fTime = qwTime.QuadPart / (double)m_llQPFTicksPerSec;
      return (float)fTime;
    }
    // Invalid command specified
    return -1.0f;   
  }
  else
  {
    // Get the time using timeGetTime()
    static double m_fLastElapsedTime  = 0.0;
    static double m_fBaseTime         = 0.0;
    static double m_fStopTime         = 0.0;
    double fTime;
    double fElapsedTime;
    
    // Get either the current time or the stop time, depending
    // on whether we're stopped and what command was sent
    if ( ( m_fStopTime != 0.0 )
    &&   ( tfCommand != TF_START )
    &&   ( tfCommand != TF_GETABSOLUTETIME ) )
    {
      fTime = m_fStopTime;
    }
    else
    {
      fTime = timeGetTime() * 0.001;
    }

    // Return the elapsed time
    if ( tfCommand == TF_GETELAPSEDTIME )
    {   
      fElapsedTime = (double)( fTime - m_fLastElapsedTime );
      m_fLastElapsedTime = fTime;
      return (float)fElapsedTime;
    }

    // Return the current time
    if ( tfCommand == TF_GETAPPTIME )
    {
      return (float)( fTime - m_fBaseTime );
    }

    // Reset the timer
    if ( tfCommand == TF_RESET )
    {
      m_fBaseTime         = fTime;
      m_fLastElapsedTime  = fTime;
      return 0.0f;
    }

    // Start the timer
    if ( tfCommand == TF_START )
    {
      m_fBaseTime += fTime - m_fStopTime;
      m_fStopTime = 0.0f;
      m_fLastElapsedTime  = fTime;
      return 0.0f;
    }

    // Stop the timer
    if ( tfCommand == TF_STOP )
    {
      m_fStopTime = fTime;
      return 0.0f;
    }

    // Advance the timer by 1/10th second
    if ( tfCommand == TF_ADVANCE )
    {
      m_fStopTime += 0.1f;
      return 0.0f;
    }

    if ( tfCommand == TF_GETABSOLUTETIME )
    {
      return (float)fTime;
    }

    // Invalid command specified
    return -1.0f;
  }

}



