#ifndef __PERFTIMR_HXX__
#define __PERFTIMR_HXX__

//+-------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1992 - 1992.
//
//  File:       perftimr.hxx
//
//  Contents:   Performance Timer class
//
//  Classes:    CPerfTimer
//
//  History:    31-Jan-94   PeterWi Created.
//
//  Notes:      -- the timer will assert if you don't call an End()
//              for each Start() [except for calling Reset() or the destructor]
//
//              -- change DECIMAL_PLACES to the number you want to print.
//              Operations will still be done internally with maximum precision.
//
//              -- maximum precision on intel seems to be 1/1,193,000
//              or 1 millisecond
//
//
//  Usage:
//
//      Say you want to time operations:
//              1) A
//              2) A and B
//              3) 3 repetitions of (A and B)
//
//      ...
//      cperftimer totaltimer;
//
//      for (3 reps)
//      {
//          CPerfTimer timer;
//
//          timer.Start();
//
//          operation A
//
//          timer.End().Add();
//
//          printf("time for A is %ws\n", timer.FormatElapsedTime());
//
//          timer.Start();
//
//          operation B
//
//          timer.End().Add();
//
//          printf("time for A+B is %ws\n", timer.FormatTotalTime());
//
//          totalTimer.Add(timer);
//      }
//
//      printf("time for 3 reps of A+B is %ws\n", totalTimer.FormatTotalTime());
//
// where the last printf() would print something like:
//
//      "time for 3 reps of A+B is 3.234s"
//
//--------------------------------------------------------------------------

#define DECIMAL_PLACES  5 // number of decimal places you want


class CPerfTimer
{
private:

    LONGLONG
    GetLowTickCount(void)
    {
        _nt = NtQueryPerformanceCounter(&_liConvert1, &_liConvert2);
        _liCount = _liConvert1.QuadPart;
        _liFreq = _liConvert2.QuadPart;
        return _liCount;
    }

    void
    _CheckState(void)
    {
        if ( _fStarted )
        {
            ASSERT(!"in middle of timing -- need to stop timer\n");
        }
    }


    WCHAR *
    _TimeToString(LONGLONG & liTime)
    {
        LONGLONG liSeconds;
        LONGLONG liRemainder;
        LONGLONG liBigRemainder;
        LONGLONG liDecimal;


        liSeconds = liTime / _liFreq;
        liRemainder = liTime % _liFreq;

        liBigRemainder = liRemainder * (LONGLONG) _ulMult;

        liDecimal = liBigRemainder / _liFreq;

        wsprintf(_wszTime, _wszFormat, (LONG)liSeconds, (LONG)liDecimal);

        return _wszTime;
    }


    LONGLONG            _liCount;
    LONGLONG            _liFreq;
    LONGLONG            _totalTime;
    LONGLONG            _startTime;
    LONGLONG            _endTime;
    LONGLONG            _elapsedTime;

    LARGE_INTEGER       _liConvert1;
    LARGE_INTEGER       _liConvert2;

    NTSTATUS            _nt;
    ULONG               _ulMult;

    BOOLEAN             _fStarted;
    WCHAR               _wszTime[20];// allow max of "time:99999.999s" and NULL
    WCHAR               _wszFormat[20];

public:

    CPerfTimer()
    {
        _ulMult = 1;

        for ( ULONG j = 0; j < DECIMAL_PLACES; j++ )
        {
            _ulMult *= 10;
        }
        
        wsprintf(_wszFormat, L"%ws%dlus", L"%lu.%0", DECIMAL_PLACES);

        Reset();
    }

    CPerfTimer &
    Reset(void)
    {
        _fStarted = FALSE;

        _totalTime = 0;
        _elapsedTime = 0;

        _endTime = _startTime = GetLowTickCount();

        return *this;
    }

    CPerfTimer &
    Start(void)
    {
        _CheckState();

        _fStarted = TRUE;
        _startTime = GetLowTickCount();

        return *this;
    }

    CPerfTimer &
    End(void)
    {
        _endTime = GetLowTickCount();

        if ( !_fStarted )
        {
            ASSERT(!"end without starting timer\n");
        }

        _fStarted = FALSE;

        _elapsedTime = _endTime - _startTime;

        return *this;
    }

    CPerfTimer &
    Add(void)
    {
        _CheckState();

        _totalTime = _totalTime + _elapsedTime;

        return *this;
    }

    CPerfTimer &
    Add(const CPerfTimer & timer)
    {
        _CheckState();

        _totalTime = _totalTime + timer.TotalTime();

        return *this;
    }

    LONGLONG
    TotalTime(void) const           { return _totalTime; }

    LONGLONG
    ElapsedTime(void) const         { return _elapsedTime; }

    LONGLONG
    TimeUnitsPerSecond(void) const  { return _liFreq; }

    WCHAR *
    FormatTotalTime(void)       { return _TimeToString(_totalTime); };

    WCHAR *
    FormatElapsedTime(void)     { return _TimeToString(_elapsedTime); };


}; // CPerfTimer

#endif // __PERFTIMR_HXX__