/*======================================================================================

	Program:		Range Imaging Toolkit (RITK)
	Module:			OpenCLImportImageContainer.h
	Version:		
	Date:			

	Copyright (c) 2010-2011
	Pattern Recognition Lab, 
    University Erlangen-Nuremberg, Germany
    All rights reserved.

	This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
	See RITKCopyright.txt for more information.

	http://www5.informatik.uni-erlangen.de/research/software/ritk

========================================================================================*/

#ifndef OPENCLIMPORTIMAGECONTAINER_H__
#define OPENCLIMPORTIMAGECONTAINER_H__

#include <list>

#include "RITKOpenCL.h"

#include "ritkGenericImportImageContainer.h"

#include "OpenCLContext.h"

namespace ritk
{

/**	@ingroup	OpenCL
 *	@class		OpenCLImportImageContainer
 *	@author		Martin Stumpf (Origin: Jakob Wasza, RITKCuda)
 *	@brief		Class extending the GenericImportImageContainer by OpenCL GPU memory
 *
 *	@details
 *	This class provides basic interfaces for OpenCL GPU memory management in compliance with
 *	the GenericImportImageContainer concept.  As there is no "single" CUDA memory type
 *	(there exists regular, pitched and array memory) this class does not provide any
 *	direct methods for allocating/deallocating or synchronization. This is the task
 *	of subclasses.
 */
template<typename TElementIdentifier, typename TElement>
class OpenCLImportImageContainer : public GenericImportImageContainer<TElementIdentifier,TElement>
{
public:
	/** @name	Std typedefs */
	//@{
	typedef OpenCLImportImageContainer									Self;
	typedef GenericImportImageContainer<TElementIdentifier,TElement>	Superclass;
	typedef itk::SmartPointer<Self>										Pointer;
	typedef itk::SmartPointer<const Self>								ConstPointer;
	//@}

	/**	@name	Template parameters */
	//@{
	typedef TElementIdentifier  ElementIdentifier;
	typedef TElement            Element;
	//@}

	/// Object creation
	itkNewMacro(Self);

	/// RTTI
	itkTypeMacro(OpenCLImportImageContainer, GenericImportImageContainer);

	/**	@name	Host/device synchronization. Is delegated to the superclass */
	//@{
	virtual void SynchronizeDevice();
	virtual void SynchronizeHost();
	//@}

	/**	@brief	Deep copy the buffer
	 *	@param	Container	The GenericImportImageContainer providing the source
	 *
	 *	@details
	 *	Copy the data from a GenericImportImageContainer. This baseclass' implementation
	 *	will perform a host memory copy. Memory will be allocated automatically.
	 */
	virtual void DeepCopy(const GenericImportImageContainer *Container);
	


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

	/// Print
	virtual void PrintSelf(std::ostream& os, itk::Indent indent) const;

	/**	@brief	Allocate the buffer
	 *	@param	size	The size in elements to allocate
	 *
	 *	@details
	 *	TODO
	 */
	virtual TElement* AllocateElements(ElementIdentifier size) const;
	//virtual Element* AllocateElements(ElementIdentifier size);

	/**	@brief	Free the buffer
	 *
	 *	@details
	 *	TODO
	 *	@sa AllocateElements
	 */
	virtual void DeallocateManagedMemory();
	
	/**	@name	Host Memory Pointer */
	//@{
protected:
	mutable Element *m_HostMem;
	mutable cl_mem m_HostMemPinnedData;
	//@}


private:
	/// purposely not implemented
	OpenCLImportImageContainer(const Self&); 
	/// purposely not implemented
	void operator=(const Self&);
	mutable std::list<Element *> m_HostMemList;
	mutable std::list<cl_mem> m_HostMemPinnedDataList;

};


/** @name Template instantiations */
//@{
typedef OpenCLImportImageContainer<unsigned long,float> OpenCLImportImageContainerF;
typedef OpenCLImportImageContainer<unsigned long,unsigned char> OpenCLImportImageContainerUC;
typedef OpenCLImportImageContainer<unsigned long, itk::Vector<float,3>> OpenCLImportImageContainerF3;
//@}


} // end namespace ritk

#endif // OPENCLIMPORTIMAGECONTAINER_H__
