#ifndef KINECTIMAGE_H__
#define KINECTIMAGE_H__

#include "ritkRImage.h"
#include "ritkRGBRImage.h"
#include "ritkGenericPayloadContainer.h"

#include "KinectSkeleton.h"
#include "KinectImageDepthToWorldFilter.h"
#include "KinectImageCudaDepthToWorldFilter.h"


/**	@class		KinectImage
 *	@author		Jakob Wasza, Sebastian Bauer, Johannes Simon
 *	@brief		Image for the MicroSoft Kinect
 *
 *	@details
 *	@todo asap documentation
*/
template<class TReal, class TRGB, unsigned int NDimension=2>
class KinectImage : public ritk::RGBRImage<TReal, TRGB, NDimension>
{
public:
	/** @name Standard typedefs */
	//@{
	typedef KinectImage										Self;
	typedef ritk::RGBRImage<TReal, TRGB, NDimension>		Superclass;
	typedef itk::SmartPointer<Self>							Pointer;
	typedef itk::SmartPointer<const Self>					ConstPointer;
	//@}

	/// For our payload
	typedef typename Superclass::GenericPayloadContainerType			GenericPayloadContainerType;
	typedef typename Superclass::GenericPayloadContainerPointer			GenericPayloadContainerPointer;

	/**	@name Skeleton typedefs */
	//@{
	typedef KinectSkeleton						SkeletonType;
	typedef typename SkeletonType::Pointer		SkeletonPointer;
	typedef typename SkeletonType::ConstPointer	SkeletonConstPointer;
	//@}

	typedef typename Superclass::RegionType		RegionType;
	//typedef RegionType::Pointer			RegionPointer;


	/// Object creation
	itkNewMacro(Self);

	/// RTTI
	itkTypeMacro(KinectImage, ritk::RImage);

	/// Image dimension
	itkStaticConstMacro(ImageDimension, unsigned int, Superclass::ImageDimension);

	/// Copy information from the specified data set
	virtual void CopyInformation(const DataObject *data);

	/**	@brief	Graft from another image
	 *	@param	data	The object to graft
	 *
	 *	@details
	 *	This method will graft the data and information from another object.
	 *	If the object can be casted to a KinectImage the RGBImage will be grafted, too.
	 */
	virtual void Graft(const DataObject *data);

	/**	@brief	Perform a deep copy
	 *	@param	data	The data to copy from
	 *
	 *	@details
	 *	This method will perform a deep copy (in contrast to the Graft() 
	 *	method that performs a shallow copy) from the given object. 
	 *	If the object can be casted to a KinectImage the RGBImage will be grafted, too.
	 */
	virtual void DeepCopy(const DataObject *data);

	/// Disconnect the image from the pipeline
	virtual void DisconnectPipeline();

	/** @name Parameters used to convert from projective to real world space */
	//@{
	void SetConversionParameters(float XToZ, float YToZ);
	void GetConversionParameters(float *XToZ, float *YToZ);
	//@}


	/**	@name	Skeleton access */
	//@{
	virtual void SetSkeleton(SkeletonPointer Skel);
	virtual SkeletonConstPointer GetSkeleton() const;
	virtual SkeletonPointer GetSkeleton();
	//@}

	/// Compute the world coord image. Overridden as the kinect delivers depth and NOT range values
	virtual void ComputeRangeToWorldCoords();
	
	
protected:
	/// Constructor
	KinectImage();
	/// Destructor
	virtual ~KinectImage();

	/// Print the object on a stream
	void PrintSelf(std::ostream& os, itk::Indent indent) const;

protected:
	/**	@name Members used to compute the world coords from depth data */
	//@{
	TReal m_XToZ;
	TReal m_YToZ;
	//@}

	/// Payload idx for the Skeleton Data
	unsigned int m_SkeletonDataPayloadIdx;

	/**	@name	The range to world coord filter */
	//@{
	typedef KinectImageCudaDepthToWorldFilter<typename Superclass::RangeImageType, typename Superclass::FlagImageType, typename Superclass::WorldCoordImageType> R2WCFilterType;
	//typedef KinectImageDepthToWorldFilter<typename Superclass::RangeImageType, typename Superclass::FlagImageType, typename Superclass::WorldCoordImageType> R2WCFilterType;
	//typedef Cuda2D3DTransformFilter<RangeImageType,FlagImageType,WorldCoordImageType> R2WCFilterType;
	typename R2WCFilterType::Pointer m_R2WCFilter;
	//@}

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

/** @name Template instantiations */
//@{
typedef KinectImage<float, itk::Vector<unsigned char, 3> > KinectImageF2;
//@}


#endif // KINECTIMAGE_H__
