#ifndef TIMER_H
#define TIMER_H

/*

Calculates framerate and frame deltas
Call StartFrame() at the beginning of each frame to update
Windows-only

Notes:
Designed for non-fixed framerate applications.
  Fixed/mixed timestep techniques:
    http://gafferongames.com/game-physics/fix-your-timestep
Time function (timeGetTime) is limited to milliseconds.
  Therefore, this timer does not allow 1000+ frames per second applications.
  More accurate Windows timer (QueryPerformanceCounter) has sketchy support on some CPUs.
  More information: http://www.geisswerks.com/ryan/FAQS/timing.html
Unsigned long limits the timer's usefulness to approximately 49 days before errors occur.

*/

#include <windows.h>

const float SECONDS_PER_MILLISECOND = 1 / 1000.0f; // Division to multiplication

class Timer
{
	public:
		Timer()
		{
			startTime = timeGetTime();
			currFrameTime = startTime;
			frameCount = 0;
			pastSecond = 0;
			framesInPreviousSecond = 0;
		}

		// MUST be called at the start of each new frame
		void StartFrame()
		{
			prevFrameTime = currFrameTime;

			// Force at least one millisecond to pass before continuing
			do
			{
				currFrameTime = timeGetTime();
			} while (currFrameTime == prevFrameTime);

			frameCount++;
			if ((unsigned long) ProgramTime() > pastSecond)
			{
				framesInPreviousSecond = frameCount;
				pastSecond = (unsigned long) ProgramTime();
				frameCount = 0;
			}
		}

		// Time in seconds since last frame (timed motion modifier)
		float TimeDelta()
		{
			return (currFrameTime - prevFrameTime) * SECONDS_PER_MILLISECOND;
		}

		// Framerate estimated per frame
		float InstantaneousFramerate()
		{
			return 1 / TimeDelta();
		}

		// Framerate estimated per second
		unsigned PreviousSecondFramerate()
		{
			return framesInPreviousSecond;
		}

		// Time in seconds since declared
		float ProgramTime()
		{
			return (currFrameTime - startTime) * SECONDS_PER_MILLISECOND;
		}

	private:
		unsigned long startTime;
		unsigned long prevFrameTime;
		unsigned long currFrameTime;
		unsigned frameCount;
		unsigned long pastSecond;
		unsigned framesInPreviousSecond;
};

#endif
