/*======================================================================================

	Program:		Range Imaging Toolkit (RITK)
	Module:			ritkTimer.h
	Version:		$Revision: 1817 $
	Date:			$Date: 2011-09-30 16:52:28 +0200 (Fri, 30 Sep 2011) $

	Copyright (c) 2010-2011
	Pattern Recognition Lab, 
	University Erlangen-Nuremberg, Germany
 	All rights reserved.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
	See RITKCopyright.txt for more information.

	http://www5.informatik.uni-erlangen.de/research/software/ritk

========================================================================================*/

#ifndef TIMER_H__
#define TIMER_H__

#include "ritkTools.h"

#include <itkSimpleFastMutexLock.h>
#include <itkRealTimeClock.h>
#include <deque>

namespace ritk
{

/**	@ingroup	Tools
 *	@class		Timer
 *	@author		Jakob Wasza
 *	@brief		Timer within the RITK framework
 *
 *	This class provides the timer that is used within the RITK framework.
 *	One single time measurement (or one pass) is defined as the elapsed time
 *	between a call to StartTimer() and StopTimer(). The actual returned time
 *	can be averaged over several single passes. By default, one pass is used. \n
 *	Note that calling GetElapsedTime() when the timer was not stopped will return
 *	zero values! \n
 *	Due to the visual studio warning warning C4251 explicit template instantiations
 *	has to be used for this class.
 */
template<class TVal>
class Timer
{
public:
	/// Constructor
	Timer();
	/// Destructor
	virtual ~Timer();

	/**	@brief	Set the number of passes for time evaluation
	 *	@param	num		The number of passes
	 *
	 *	@details
	 *	Set the number of passes that are used to average the actual runtime.
	 *	By default, this class uses one pass. \n
	 *	Calling this method is thread safe!
	 *	@sa	StartTimer()
	 *	@sa StopTimer()
	 *	@sa	GetElapsedTime()
	 */
	void SetNumberOfPassesToAverageRuntime(unsigned int num);

	/**	@brief	Get the elapsed time
	 *	@param	AverageElapsedTime			The elapsed in ms
	 *	@param	ElapsedTimeStdDeviation		Optional the elapsed time's standard deviation
	 *
	 *	@details
	 *	This method will return the elapsed time averaged over several passes. \n
	 *	Calling this method is thread safe!
	 */
	void GetElapsedTime(TVal *AverageElapsedTime, TVal *ElapsedTimeStdDeviation=0);
	
	
	/**	@brief	Start the timer
	 *	@return	True if the timer was started successfully, false otherwise
	 *
	 *	@details
	 *	A call to this method will start the internal timer. \n
	 *	Calling this method is thread safe!
	 */
	bool StartTimer(bool Reset=false);

	/**	@brief	Stop the timer
	 *
	 *	@details
	 *	A call to this method will stop the internal timer. A time measurement 
	 *	is defined as the elapsed time during a call to StartTimer() and a call 
	 *	to this method. The internal members will be updated according to the 
	 *	number of passes that can be specified via the SetNumberOfPassesToAverageRuntime()
	 *	method. \n
	 *	Calling this method is thread safe!
	 */
	void StopTimer();

	/**	@brief	Reset the timer
	 *	
	 *	@details
	 *	A call to this method will reset the timer.\n
	 *	Calling this method is thread safe!
	 */
	inline void ResetTimer();

	/// Method to add elapsed times obtianed from a third party timer
	void AddElapsedTime(TVal ElapsedTime);


protected:
	/// Mutex
	itk::SimpleFastMutexLock m_Mutex;
	/// Flag that indicates whether the timer has been initialized properly
	bool m_TimerInitialized;
	/// Flag that indiates whether the internal timer was started
	bool m_TimerStarted;
	/// Real-time clock
	itk::RealTimeClock::Pointer m_Clock;
	/// Timestamp generated at StartTimer()
	itk::RealTimeClock::TimeStampType m_CurrentTimeStamp;
	/// Holding the elapsed time (index 0) and its standard deviation (index 1)
	TVal m_ElapsedTime[2];
	/// Number of passes that are averaged
	unsigned int m_NumPassesToAverageElapsedTime;
	/// Member that holds the accumulated elapsed times (used for averaging over several passes)
	TVal m_AccumulatedElapsedTime;
	/// Holds the last elapsed times (used for averaging over several passes)
	std::deque<TVal> m_LastElapsedTimes;
};


/** @name Explicit template instantiations */
//@{
typedef Timer<double> TimerD;
//@}

} // end namespace ritk

#endif // TIMER_H__
