#ifndef TIMER_H
#define TIMER_H

#ifndef LOG_H
#include "Log.h"
#endif

#include <iostream>

#ifdef WIN32
#pragma warning(disable : 4005)
#endif

//#define TIME \
//{ \
//    double t = MM::timer().elapsed(); \
//    std::cout << t << "\t" << __FILE__ << "\t" << __LINE__ << std::endl; \
//    MM::timer().restart(); \
//};

#define TIME(ref) \
{ \
    double t = MM::timer().elapsed(); \
    Text text; \
    text += Text (t, 2); \
    text += " "; \
    text += ref; \
    text += " "; \
    text += __FILE__; \
    text += " "; \
    text += __LINE__; \
    text += "\n"; \
    log() <<  text;  \
    MM::timer().restart(); \
};


#ifdef MM_WIN32

    //#ifndef INCLUDED_WINBASE_H
    //#include <winbase.h>
    //#define INCLUDED_WINBASE_H
    //#endif

    #ifndef INCLUDED_WINDOWS_H
    #include <Windows.h>
    #define INCLUDED_WINDOWS_H
    #endif

    //#ifndef FLAW_H
    //#include "Flaw.h"
    //#endif

#elif MM_UNIX

    #ifndef INCLUDED_SYS_TIME_H
    #include <sys/time.h>
    #define INCLUDED_SYS_TIME_H
    #endif

#else

    #ifndef INCLUDED_TIME_H
    #include <time.h>
    #define INCLUDED_TIME_H
    #endif

#endif

namespace MM
{

#ifdef MM_WIN32

class Timer
{
public:
    Timer   ()
    {
        restart();
        QueryPerformanceFrequency (&frequency_);
        if (frequency_.QuadPart == 0)
            //FLAW ("Does not support a high-resolution performance counter.");
            throw "Does not support a high-resolution performance counter.";
    }

    void    restart () {QueryPerformanceCounter (&start_);}
    double  elapsed () const
    {
        LARGE_INTEGER   finish_;
        QueryPerformanceCounter (&finish_);
        return double(finish_.QuadPart - start_.QuadPart) / frequency_.QuadPart;
    }

private:
    LARGE_INTEGER       start_;
    LARGE_INTEGER       frequency_;
};



#elif MM_UNIX 

class Timer
{
public:
            Timer   () {restart();}
    void    restart () {gettimeofday (&start_, 0);}

    double  elapsed () const 
    {
        struct timeval  finish_;
        gettimeofday (&finish_, 0);
        return  (finish_.tv_sec  - start_.tv_sec)  
              + (finish_.tv_usec - start_.tv_usec) * 0.000001;
    }

private:
    struct timeval      start_;
};



#else

class Timer
{
public:
            Timer   () {restart();}
    void    restart () {start_ = clock();}
    double  elapsed () const {return double(clock() - start_) / CLOCKS_PER_SEC;}

private:
    clock_t             start_;
};

#endif

inline Timer & timer ()
{
    static Timer singleton;
    return singleton;
}

}//MM

#endif //TIMER_H
