#pragma once

#include "scalar.h"

class Time;

//##########################################################################
//########################    System Clock    ##############################
//##########################################################################

class SystemClock SIGNATURED
{
	friend class Time;

public:
	friend float Get_Frame_Percent_Used();
	friend volatile Time& Now();
	friend double HiResNow();
	friend __int64 HiResNowTicks();
	friend __int64 HiResCounterFreq();
	static void TogglePause();

	SystemClock();
	~SystemClock()		{ Shutdown(); }
	static SystemClock timer;
	void Shutdown();
	static long GetTicksPerSecond()	{ return ticksPerSecond; }

protected:
	long pauseStart;
	long pauseTime;
	static long ticksPerSecond;
	static __int64 perfCounterFreq;

	static long GetRTC();
	static double GetHiRes();
	static __int64 GetHiResTicks();
};

//##########################################################################
//############################    Time    ##################################
//##########################################################################

class Time
{
public:
	long ticks;
	static Time Null;

	#if defined(USE_SIGNATURE)
		friend int Is_Signature_Bad(const volatile Time *p);
	#endif

	Time()	{}
	Time(const volatile Time &t) : ticks(t.ticks)	{}
	Time(const Time &t) : ticks(t.ticks) {}
	Time(SystemClock&) : ticks(0)	{}

	Time& operator=(const volatile Time &t)
	{
		Check_Pointer(this);
		Check(&t);
		ticks = t.ticks;
		return *this;
	}
	Time& operator=(long t)
	{
		Check_Pointer(this);
		ticks = t;
		return *this;
	}
	Time& operator=(Scalar t)
	{
		Check_Pointer(this);
		ticks = Float_To_Time(t);
		return *this;
	}

	operator Scalar() const volatile
	{
		Check(this);
		return Time_To_Float(ticks);
	}
	operator long() const volatile
	{
		Check(this);
		return ticks;
	}

	Scalar operator-(const volatile Time &t) const volatile
	{
		Check(this);
		Check(&t);
		return Time_To_Float(ticks - t.ticks);
	}

	Time& operator+=(const volatile Time &t)
	{
		Check(this);
		Check(&t);
		ticks += t.ticks;
		return *this;
	}
	Time& operator+=(Scalar t)
	{
		Check(this);
		ticks += Float_To_Time(t);
		return *this;
	}
   Time& operator+=(long t)
   {
      Check(this);
      ticks += t;
      return *this;
   }
	Time& operator-=(const volatile Time &t)
	{
		Check(this);
		Check(&t);
		ticks -= t.ticks;
		return *this;
	}
	Time& operator-=(Scalar t)
	{
		Check(this);
		ticks -= Float_To_Time(t);
		return *this;
	}

	Logical operator<(const volatile Time &t) const volatile
	{
		Check(this);
		Check(&t);
		return ticks < t.ticks;
	}
	Logical operator<=(const volatile Time &t) const volatile
	{
		Check(this);
		Check(&t);
		return ticks <= t.ticks;
	}
	Logical operator>(const volatile Time &t) const volatile
	{
		Check(this);
		Check(&t);
		return ticks > t.ticks;
	}
	Logical operator>=(const volatile Time &t) const volatile
	{
		Check(this);
		Check(&t);
		return ticks >= t.ticks;
	}

	friend std::ostream& operator <<(std::ostream& stream, const volatile Time& t)
	{
		Check(&t);
		return stream << t.ticks;
	}

	Logical TestInstance() const volatile;
	static Logical TestClass();

private:
	static long Float_To_Time(Scalar t)		{ return (long)(t * SystemClock::ticksPerSecond + 0.5f); }
	static Scalar Time_To_Float(long t)		{ return (Scalar)(t / (float)SystemClock::ticksPerSecond); }
};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Time functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

void Convert_From_Ascii(const char *str, Time *time);
