#ifndef CUDAKINECTRANGETOWORLDFILTER_H__
#define CUDAKINECTRANGETOWORLDFILTER_H__

//#include <cuda_runtime.h>
#include <C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v4.0/include/cuda_runtime_api.h>

#include "RITKCommon.h"
#include "ritkCudaContext.h"
#include <itkImageToImageFilter.h>


/**	@class		CudaKinectRangeToWorldFilter
 *	@author		Jakob Wasza
 *	@brief		Filter that generates a world coord image from a kinect range image
 *
 *	@details
 *	This filter generates a world coord image (3D points at each pixel) from a kinect range image (orthogonal distances at each pixel).
 */
template<class TRangeImage, class TFlagImage, class TWorldCoordImage> 
class CudaKinectRangeToWorldFilter : public itk::ImageToImageFilter<TRangeImage, TWorldCoordImage>
{
public:
	/** @name	Typedefs */
	//@{

	/** @name	Standard typedefs */
	//@{
	typedef CudaKinectRangeToWorldFilter							Self;
	typedef itk::ImageToImageFilter<TRangeImage,TWorldCoordImage>	Superclass;
	typedef itk::SmartPointer<Self>									Pointer;
	typedef itk::SmartPointer<const Self>							ConstPointer;
	typedef itk::DataObject::Pointer								DataObjectPointer;
	//@}

	/**	@name	Input, output and Flag typedefs */
	//@{
	typedef typename Superclass::InputImageType		InputImageType;
	typedef typename InputImageType::Pointer		InputImagePointer;
	typedef typename InputImageType::ConstPointer	InputImageConstPointer;
	typedef typename InputImageType::PixelType		InputPixelType;
	typedef typename Superclass::OutputImageType	OutputImageType;
	typedef typename OutputImageType::Pointer		OutputImagePointer;
	typedef typename OutputImageType::PixelType		OutputImagePixelType;
	typedef TFlagImage								FlagImageType;
	typedef typename FlagImageType::Pointer			FlagImagePointer;
	//@}

	//@}

	/// Object creation
	itkNewMacro(Self);

	/// RTTI
	itkTypeMacro(CudaKinectRangeToWorldFilter, itk::ImageToImageFilter);

	/**	@name	Set/Get the Flag image input */
	//@{
	itkSetInputMacro(FlagImage,FlagImageType,1);
	itkGetInputMacro(FlagImage,FlagImageType,1);
	//@}

	/**	@name	Set/get the conversion parameters */
	//@{
	void SetConversionParameters(float XToZ, float YToZ);
	void GetConversionParameters(float *XToZ, float *YToZ);
	//@}


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

	/// Data generation
	virtual void GenerateData();

	/// Allocate CUDA memory
	CudaMethodMacro(CudaKinectRangeToWorldFilter,AllocateCudaMemory);
	/// Free CUDA memory
	CudaMethodMacro(CudaKinectRangeToWorldFilter,FreeCudaMemory);
	/// The actual filtering method
	CudaMethodMacro(CudaKinectRangeToWorldFilter,DoFiltering);

protected:
	/**	@name Members used to compute the world coords out of the range data */
	//@{
	float m_XToZ;
	float m_YToZ;
	//@}

	/**	@name CUDA memory */
	//@{
	typename InputImageType::SizeType m_CurrentSize;
	cudaArray *m_InputArray;
	//@}


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


/** @name Template instantiations */
//@{
typedef CudaKinectRangeToWorldFilter<itk::Image<float,2>, itk::Image<unsigned char,2>, itk::Image<itk::Vector<float,3>,2>> CudaKinectRangeToWorldFilterF2;
//@}


#endif // CUDAKINECTRANGETOWORLDFILTER_H__