#ifndef CUDATEMPORALAVERAGINGIMAGEFILTER_H__
#define CUDATEMPORALAVERAGINGIMAGEFILTER_H__

#include <itkImageToImageFilter.h>

#include "ritkCudaContext.h"
#include "ritkCudaRegularMemoryImportImageContainer.h"

#include <queue>
#include "ritkCudaMemoryPool.h"

/**	@class	CUDATemporalAveragingImageFilter
 *	@autor	Jakob Wasza
 *	@brief	Filter that implements temporal averaging of several images using CUDA
 *
 *	@details
 *	This class implements the averaging of several images to one single image.
 *	The name "TemporalAveraging" is chosen as this filter is supposed to be used with
 *	input images representing the same scene but at different moments. \n
 *	One pixel in the output image is defined as 
 *	\f[
 *	O(i,j) = \frac{1}{N} \sum_{n=0}^{N-1} I_{n}(i,j)
 *	\f]
 *	where N is the number of images (or frames) that are used to assembly the final 
 *	output image. One might expect that this filter produces no valid output up
 *	to the point where the number of input images equals N. However, in this
 *	implementation a valid output is generated after each call to Update() even
 *	if the number of input images is smaller than N. In this case, the output is
 *	simply computed using the available frames. \n
 *	Note that this class does not provide an interface for setting the input images
 *	simultaneously. Instead the input images have to provided sequentially as 
 *	\code
 * TimeAverageImageFilter->SetInput(Frame0);
 * TimeAverageImageFilter->Update();
 * TimeAverageImageFilter->SetInput(Frame1);
 * TimeAverageImageFilter->Update();
 * ...
 *	\endcode
 *	This filter is implemented in a recursive manner, so the runtime is O(1) wrt
 *	the number of frames that are used.
 */
template<class TInput, class TOutput=TInput, class TAccu=TOutput>
class CUDATemporalAveragingImageFilter : public itk::ImageToImageFilter<TInput,TOutput>
{
public:
	/** @name	Typedefs */
	//@{

	/** @name	Standard typedefs */
	//@{
	typedef CUDATemporalAveragingImageFilter			Self;
	typedef itk::ImageToImageFilter<TInput,TOutput>		Superclass;
	typedef itk::SmartPointer<Self>						Pointer;
	typedef itk::SmartPointer<const Self>				ConstPointer;
	//@}

	/**	@name	Input and output typedefs */
	//@{
	typedef typename Superclass::InputImageType		InputImageType;
	typedef typename InputImageType::Pointer		InputImagePointer;
	typedef typename InputImageType::ConstPointer	InputImageConstPointer;
	typedef typename Superclass::OutputImageType	OutputImageType;
	typedef typename OutputImageType::Pointer		OutputImagePointer;
	typedef  TAccu									AccuImageType;
	typedef typename AccuImageType::Pointer			AccuImagePointer;
	typedef typename AccuImageType::ConstPointer	AccuImageConstPointer;
	//@}

	//@}

	/// Object creation
	itkNewMacro(Self);

	/// RTTI
	itkTypeMacro(Self, Superclass);

	/**	@brief	Reset the filter
	  *
	  * @details
	  * This method will reset the filter. This is nothing else
	  * but removing all previously set images that were supposed
	  * to assembly the final output image. A call to this method
	  * should be considered mandatory if the same instance of this
	  * filter class is used for different scenes...
	  */
	void Reset();

	/**	@brief	Set the number of frames that assembly the final image
	  * @param	N	The number of frames
	  * 
	  * @details
	  * Set the number of frames N that are used to assembly the final
	  *	output image. See the formula in the class description for 
	  * details.
	  */
	void SetNumFrames(unsigned int N);

	/**	@brief	Get the number of frames that assembly the final
	  *	@return	The number of frames
	  *
	  * @details
	  *	Get the number of frames N that assembly the final. See the 
	  *	formula in the class description for details.
	  */
	unsigned int GetNumFrames();

protected:
	/// Constructor
	CUDATemporalAveragingImageFilter();
	/// Destructor
	~CUDATemporalAveragingImageFilter();

	/// Single threaded data generation
	void GenerateData();

	/// Allocate the cuda memory
	CudaMethodMacro(CUDATemporalAveragingImageFilter, AllocateMemory);
	/// The actual filtering
	CudaMethodMacro(CUDATemporalAveragingImageFilter, DoFiltering);

protected:
	/// The number of frames used to compute the average image
	unsigned int m_NumFrames;

	/**	@name CUDA memory */
	//@{
	typename InputImageType::SizeType m_CurrentSize;
	typedef typename ritk::CudaRegularMemoryImportImageContainer<typename AccuImageType::PixelContainer::ElementIdentifier, typename AccuImageType::PixelContainer::Element>		AccuImageContainerType;
	typename AccuImageContainerType::Pointer m_AccuContainer;
	typedef typename ritk::CudaRegularMemoryImportImageContainer<typename OutputImageType::PixelContainer::ElementIdentifier, typename OutputImageType::PixelContainer::Element>	OutputImageContainerType;
	typename OutputImageContainerType::Pointer m_OutputContainer;
	typedef typename ritk::CudaRegularMemoryImportImageContainer<typename InputImageType::PixelContainer::ElementIdentifier, typename InputImageType::PixelContainer::Element>		InputImageContainerType;
	typedef ritk::CudaMemoryPool<InputImageContainerType> CUDAMemoryPoolType;
	typename CUDAMemoryPoolType::Pointer m_MemoryPool;
	//@}

	/// Queue holding the last frames
	std::queue<unsigned int> m_FrameQueue;

private:
	/// purposely not implemented
	CUDATemporalAveragingImageFilter(Self&); 
	/// purposely not implemented
	void operator=(const Self&);
};

//#include "CUDATemporalAveragingImageFilter.txx"


#endif // CUDATEMPORALAVERAGINGIMAGEFILTER_H__
