///////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                           //
//  Copyright (c) 2012-2015, Jan de Graaf (jan@jlib.nl)                                                      //
//                                                                                                           //
//  Permission to use, copy, modify, and/or distribute this software for any purpose with or                 //
//  without fee is hereby granted, provided that the above copyright notice and this permission              //
//  notice appear in all copies.                                                                             //
//                                                                                                           //
//  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS             //
//  SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL              //
//  THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES          //
//  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE     //
//  OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  //
//                                                                                                           //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef _JLIB_HEADER_TIMER
#define _JLIB_HEADER_TIMER

/*

Template chrono timer class

Wraps std chrono basic time functions in a timer object.

*/

#include <chrono>

namespace jlib
{
	class timer
	{
	public:
		// Constructors
		timer() : m_start(std::chrono::high_resolution_clock::now()) {}
		template<typename rep, typename period> timer(std::chrono::duration<rep, period> duration) : m_start(std::chrono::high_resolution_clock::now())
		{
			m_start -= duration;
		}
		template<typename rep, typename period> timer& operator=(std::chrono::duration<rep, period> duration)
		{
			restart();
			m_start -= duration;
			return *this;
		}

		inline void restart()
		{
			m_start = std::chrono::high_resolution_clock::now();
		}

		template<typename dur> inline dur duration() const
		{
			return std::chrono::duration_cast<dur>(std::chrono::high_resolution_clock::now() - m_start);
		}

		// Simplified get functions
		inline std::chrono::nanoseconds::rep nanoseconds() const
		{
			return duration<std::chrono::nanoseconds>().count();
		}
		inline std::chrono::microseconds::rep microseconds() const
		{
			return duration<std::chrono::microseconds>().count();
		}
		inline std::chrono::milliseconds::rep milliseconds() const
		{
			return duration<std::chrono::milliseconds>().count();
		}
		inline std::chrono::seconds::rep seconds() const
		{
			return duration<std::chrono::seconds>().count();
		}
		inline std::chrono::minutes::rep minutes() const
		{
			return duration<std::chrono::minutes>().count();
		}
		inline std::chrono::hours::rep hours() const
		{
			return duration<std::chrono::hours>().count();
		}
		inline float seconds_float() const
		{
			return duration<std::chrono::duration<float>>().count();
		}

		// Addition or substraction
		// Allows to add or substract time periods from the timer
		template<typename rep, typename period> inline timer& operator+=(std::chrono::duration<rep, period> duration)
		{
			m_start -= duration;
			return *this;
		}
		template<typename rep, typename period> inline timer& operator-=(std::chrono::duration<rep, period> duration)
		{
			m_start += duration;
			return *this;
		}

	private:
		std::chrono::high_resolution_clock::time_point m_start;
	};
}

#endif