#ifndef KinectImageIO_H__
#define KinectImageIO_H__

#include <iostream>
#include <fstream>
#include "ritkRImageIOBase.h"
#include "KinectImage.h"


/*	@class		KinectImageIO
 *	@author		Johannes Simon, Jakob Wasza
 *	@brief		IO functionality for Microsoft Kinect images
 *
 *	@details
 */
template<class TRImageBase, class TKinectImage>
class KinectImageIO : public ritk::RImageIOBase<TRImageBase>
{
public:
	/** @name Standard typedefs */
	//@{
	typedef KinectImageIO						Self;
	typedef ritk::RImageIOBase<TRImageBase>		Superclass;
	typedef itk::SmartPointer<Self>				Pointer;
	//@}

	/**	@name RImage typedefs */
	//@{
	typedef typename Superclass::RImageBaseType			RImageBaseType;
	typedef typename RImageBaseType::Pointer			RImageBasePointer;
	typedef typename RImageBaseType::ConstPointer		RImageBaseConstPointer;
	typedef TKinectImage								KinectImageType;
	typedef typename KinectImageType::Pointer			KinectImagePointer;
	//@}

	/// RTTI
	itkTypeMacro(KinectImageIO, RImageIOBase);

	/// Object creation
	itkNewMacro(Self);


	/// Return the class name of the range image that this IO object can process
	const char* GetRImageClassName();

	/// Return the number of frames that are available
	unsigned int GetNumberOfFrames();

	/// The resolution of the frames
	void GetResolution(unsigned int *SX, unsigned int *SY);

	/// Write a frame
	void WriteFrame(RImageBaseConstPointer Frame);

	/// Read a frame
	RImageBasePointer ReadFrame(unsigned int FrameID);

	/// Close the input/output stream
	void Close();

protected:
	/// Constructor
	KinectImageIO();
	/// Destructor
	virtual ~KinectImageIO();

	/** @name	Struct for the header of an input file */
	//@{
	/// The struct
	typedef struct
	{
		/// The version of the format
		std::string FormatVersion; 
		/// Camera parameters as the range image
		ritk::CameraParameters	CurrCameraParameters; 
		/// The number of frames stored in this file
		unsigned int NumFrames; 
		/// Source data size (required for IO version 1.1)
		unsigned SourceDataSize;
		/// Skeleton data ??
	} HeaderStruct;
	//@}

	/** @brief	Open the file and read the header
	 *	
	 *	After calling this method, the input filestream m_InputFile
	 *	will be ready to use and the header will be available
	 *	in the member m_CurrentHeader and the stream position will be
	 *	set to the beginning of the data section. \n
	 *	The method also takes care of the filename dirty flag. If a file was opened previously
	 *	it will be closed;
	 */
	void OpenFileStreamAndReadHeader();

	/// Helper function to initialize the time stamp vector
	void InitTimeStamps();


protected:
	/// The internal class name
	std::string m_ClassName;
	/// Flag that indicates that the filename has changed
	bool m_FileNameDirtyFlag;
	/**	@name Filestream for the data */
	//@{
	std::ofstream m_OutputStream;
	std::ifstream m_InputStream;
	//@}
	/// End of header position
	unsigned long m_HeaderEndPos;
	/// The current index
	long m_Index;
	/// The current header
	HeaderStruct *m_CurrentHeader;

	/// The number of recorded skeletons (version dependent)
	unsigned int m_uiSkeletons;
	unsigned int m_uiQualityFlags;
	unsigned int m_RGBWidth;
	unsigned int m_RGBHeight;
	unsigned int m_RangeWidth;
	unsigned int m_RangeHeight;

	/// An image pool to preallocate images
	std::vector<KinectImagePointer> m_RImagePool;

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

typedef KinectImageIO<ritk::RImageF2,KinectImageF2> KinectImageIOF2;


#endif // KinectImageIO_H__
