#ifndef KINECTSDKIMAGE_H__
#define KINECTSDKIMAGE_H__

#include "ritkRImage.h"
#include "ritkRGBRImage.h"
#include "KinectSDKRangeToWorldFilter.h"
#include "Skeleton.h"
#include "CudaKinectRangeToWorldFilter.h"

#include <itkSmartPointer.h>

//#include <.h>


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

	typedef Skeleton	SkeletonType;
	typedef typename SkeletonType::Pointer SkeletonPointer;
	typedef typename SkeletonType::ConstPointer SkeletonConstPointer; 

	/// Object creation
	itkNewMacro(Self);

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

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

	/** @name Convenience methods to set the LargestPossibleRegion, BufferedRegion and RequestedRegion. Allocate must still be called.*/
	//@{
	virtual void SetRegions(RegionType region);
	virtual void SetRegions(SizeType size);
	//@}

	/**	@name LargestPossibleRegion, BufferedRegion, RequestedRegion. Calling these methods will correctly set the SX and SY camera parameters!*/
	//@{
	virtual void SetLargestPossibleRegion(const RegionType &region);
	virtual void SetRequestedRegion(const RegionType &region);
	virtual void SetBufferedRegion(const RegionType &region);
	//@}

	/// Allocate the internal images (inherited from itk::ImageBase)
	virtual void Allocate();

	/** @name Set the spacing. Will be delegated to the internal images*/
	//@{
	virtual void SetSpacing(const SpacingType &Spacing);
	virtual void SetSpacing(const double Spacing[ImageDimension]);
	virtual void SetSpacing(const float Spacing[ImageDimension]);
	//@}

	/** @name Set the origin. Will be delegated to the internal images*/
	//@{
	virtual void SetOrigin(const PointType &Origin);
	virtual void SetOrigin(const double Origin[ImageDimension]);
	virtual void SetOrigin(const float Origin[ImageDimension]);
	//@}

	/// Set the direction 
	virtual void SetDirection(const DirectionType direction);

	/// 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();

	/// Set parameters used to convert from projective to real world space
	void SetConversionParameters(float XToZ, float YToZ);
	void GetConversionParameters(float *XToZ, float *YToZ);

	/// Compute the world coord image
	virtual void ComputeRangeToWorldCoords();

	virtual SkeletonConstPointer GetSkeleton() const;
	virtual SkeletonPointer GetSkeleton();

	virtual void SetSkeleton(SkeletonPointer Skel);
	

	//xn::DepthGenerator *m_DepthGenerator;
	//xn::DepthGenerator *m_UserGenerator;

public:
	//Skeleton * m_Skeleton;
	
protected:
	/// Constructor
	KinectSDKImage();
	/// Destructor
	~KinectSDKImage();

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

protected:
	/**	@name Members used to compute the world coords out of the range 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 CudaKinectRangeToWorldFilter<RangeImageType,FlagImageType,WorldCoordImageType> R2WCFilterType;
	typename static R2WCFilterType::Pointer s_R2WCFilter;
	//@}

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

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


//#include "KinectSDKImage.txx"

#endif KINECTSDKIMAGE_H__