#ifndef KinectSDKPLAYERPLUGINSOURCE_H__
#define KinectSDKPLAYERPLUGINSOURCE_H__

// Microsoft SDK Includes
#include <Ole2.h>
#include <windows.h>
#include <MSR_NuiApi.h>


// RITK Includes
#include "ritkRImageSource.h"
#include "KinectImage.h"

// Threadsafe Includes
#include <QThread>
#include <QQueue>
#include <QWaitCondition>
#include <QMutex>
#include "itkVectorImageToImageAdaptor.h"

template<class TRImage, class TKinectImage>
class KinectSDKSourcePluginSource : public ritk::RImageSource<TRImage>
{
public:
	/** @name Typedefs */
	//@{

	/** @name Standard typedefs */
	//@{
	typedef KinectSDKSourcePluginSource			Self;
	typedef ritk::RImageSource<TRImage>			Superclass;
	typedef itk::SmartPointer<Self>				Pointer;
	typedef itk::SmartPointer<const Self>		ConstPointer;
	//@}

	/**	@name The RImage types */
	//@{
	typedef typename Superclass::RImageType			RImageType;
	typedef typename RImageType::Pointer			RImagePointer;
	typedef TKinectImage							KinectImageType;
	typedef typename KinectImageType::Pointer		KinectImagePointer;
	//@}
	

	//@}

	/// Object creation
	itkNewMacro(Self);

	/// RTTI
	itkTypeMacro(Self, Superclass);

	/** @brief	Generate the output information
	 *
	 *	@details
	 *	Prepare the allocation of the output image during the first back propagation of the pipeline.
	 *	In particular, the regions of the output image and the camera parameters are set.
	 */
	void GenerateOutputInformation();

	/**	@name Connect/disconnect */
	//@{
	void Connect();
	void Disconnect();
	//@}

protected:
	/// Constructor
	KinectSDKSourcePluginSource();
	/// Destructorthe
	virtual ~KinectSDKSourcePluginSource();

	/// Generate the image here
	virtual void GenerateRImage();
	
	/// Handle Events
	void Nui_GotDepthAlert();
	void Nui_GotVideoAlert();
	void Nui_GotSkeletonAlert();

	static DWORD WINAPI Nui_ProcessThread(LPVOID pParam);

	/// Buffer Images for threadsafe handling
	KinectImagePointer m_ImageBuffer;

	/// Calibration Mapping
	typedef itk::Image<float, 2>   UIImageType;
	UIImageType::Pointer CalibrationX;
	UIImageType::Pointer CalibrationY;


	std::pair<float,float> *m_MappingTable;


	VF3 Undistort(VF3 InputPoint);
	short m_TrackingState[KinectSkeleton::SKEL_COUNT * NUMBEROFSKELETONS];

	/// Connected flag
	bool m_Connected;

	/// Indicates that we're generating
	bool m_Generating;

	/// Set up Calibration Mask
	bool m_Calibrated;

	/** @name Real time clock */
	//@{
	typedef itk::RealTimeClock::TimeStampType TimeStampType;
	itk::RealTimeClock::Pointer m_Clock;

	// Timestamps for Image synchronization
	double m_MaxFrameDelta;
	int m_EventType;
	//@}

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


	bool m_TrackingStarted;
	bool m_CalibrationRequested;
	bool m_FirstGenerateRImageCall;

	//// threadsafe Output writing
	QMutex			m_MutexBufferIO;

	HANDLE        m_hThNuiProcess;
    HANDLE        m_hEvNuiProcessStop;

    HANDLE        m_hNextDepthFrameEvent;
    HANDLE        m_hNextVideoFrameEvent;
    HANDLE        m_hNextSkeletonEvent;

    HANDLE        m_pDepthStreamHandle;
    HANDLE        m_pVideoStreamHandle;

	// Skeleton Data
	std::vector<VF3> m_JointPositions1;	
	std::vector<VF3> m_JointPositions2;

	// Stream resolutions
	int	m_RGBFrameW;
	int	m_RGBFrameH;
	int	m_DepthFrameW;
	int	m_DepthFrameH;
	float m_DepthScale;

    int m_FramesTotal;
    int m_LastFPStime;
    int m_LastFramesTotal;

	// debug timestamp delta
	double			m_lastTimestamp;
	int m_x;
	int m_y;
};

/// Explicit template instantiation (default)
typedef KinectSDKSourcePluginSource<ritk::RImageF2, KinectImageF2> KinectSDKSourcePluginSourceF2;


#endif // KinectSDKPLAYERPLUGINSOURCE_H__
