#ifndef TIME_UTIL_H
#define TIME_UTIL_H

#include <stdio.h>
#include <stdlib.h>
#include <string>

#ifdef WIN32
#pragma comment (lib, "winmm.lib")
#include <windows.h>
#include <mmsystem.h>
#else
#include <sys/time.h>
#endif

/*
	Ripatti Artem (c) 2011
	класс time_util содержит несколько функций
	для работы с таймером

	внимание! для корректной работы
	надо в начале прорисовки каждого фрейма
	вызывать функцию tick_frame()
*/

class time_util
{
	static int & last_frame()
	{
		static int _last_frame = timeGetTime();
		return _last_frame;
	}

	static float & really_fps()
	{
		static float _really_fps = 0.f;
		return _really_fps;
	}

	static int & fps()
	{
		static int _fps = 60;
		return _fps;
	}

	static int & last_fps_time()
	{
		static int _last_fps_time = timeGetTime();
		return _last_fps_time;
	}

	static int & frames()
	{
		static int _frames = 0;
		return _frames;
	}

#ifndef WIN32
	static int timeGetTime()
	{
		struct timeval now;
		gettimeofday(&now, NULL);
		long long tmp = (long long)now.tv_sec*1000 + now.tv_usec/1000;
		return (int)(tmp&((long long)(1<<32)-1));
	}
#endif

	time_util(){}
public:
	// эту цункцию надо вызывать чтобы все работало
	static void tick_frame()
	{
		int cur_time = timeGetTime();
		if (last_frame()/100 != cur_time/100)
		{
			really_fps() = float(frames()*1000)/float(cur_time-last_fps_time());
			last_fps_time() = cur_time;
			frames() = 0;
		}
		last_frame() = cur_time;
		frames()++;
	}

	// входит в бесконечный цикл - дожидается начала следубщего фрейма
	static void wait_next_frame()
	{
		while (!is_next_frame()) Sleep(1);
	}

	// это можно использовать когда во время ожидания
	// следующего фрейма надо еще что то сделать
	static bool is_next_frame()
	{
		int cur_time = timeGetTime();
		return ((cur_time - last_frame())*fps() >= 1000);
	}

	// примерный реальный фпс
	static float get_really_fps()
	{
		return really_fps();
	}

	// примерный реальный фпс в виде строки
	static std::string get_really_fps_s()
	{
		char re[256];
		float fps = get_really_fps();
		sprintf(re, "%.3lf", (double)fps);
		return std::string(re);
	}

	// установаить ограничение на фпс - именно этот параметр
	// используется в is_next_frame
	static void set_fps(int _fps)
	{
		if (fps < 0) return;
		fps() = _fps;
	}
};

class fps_counter
{
	int last_frame;
	int last_fps_time;
	int frames;
	float really_fps;
public:
	fps_counter()
	{
		last_frame = timeGetTime();
		last_fps_time = timeGetTime();
		frames = 0;
		really_fps = 0.f;
	}

	void tick_frame()
	{
		int cur_time = timeGetTime();
		if (last_frame/100 != cur_time/100)
		{
			really_fps = float(frames*1000)/float(cur_time-last_fps_time);
			last_fps_time = cur_time;
			frames = 0;
		}
		last_frame = cur_time;
		frames++;
	}

	float get_really_fps()
	{
		return really_fps;
	}

	std::string get_really_fps_s()
	{
		char re[256];
		float fps = get_really_fps();
		sprintf(re, "%.3lf", (double)fps);
		return std::string(re);
	}
};

#endif