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

	Program:		Range Imaging Toolkit (RITK)
	Module:			OpenCLImageMemoryImportImageContainer.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 OPENCLIMAGEMEMORYIMPORTIMAGECONTAINER_H__
#define OPENCLIMAGEMEMORYIMPORTIMAGECONTAINER_H__

#include "OpenCLImportImageContainer.h"



namespace ritk
{

/**	@ingroup	OpenCL
 *	@class		OpenCLRegularMemoryImportImageContainer
 *	@author		Martin Stumpf (Origin: Jakob Wasza)
 *	@brief		CUDA regular memory container
 *
 *	@details
 *	This class provides methods for regular CUDA memory management.
 */
template<typename TElementIdentifier, typename TElement>
class OpenCLImageMemoryImportImageContainer : public OpenCLImportImageContainer<TElementIdentifier,TElement>
{
public:
	/**	@name	Std typedefs */
	//@{
	typedef OpenCLImageMemoryImportImageContainer						Self;
	typedef OpenCLImportImageContainer<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(OpenCLImageMemoryImportImageContainer, OpenCLImportImageContainer);

	/**	@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);

	/**	@brief	Allocates OpenClImageMemory
	 *	@param	size_x 	The Image size in x-Direction
	 *	@param	size_y 	The Image size in y-Direction
	 *
	 *	@details
	 *	Needs to be called before any other allocation-calls to define the size of the image
	 */
	void AllocateManually(ElementIdentifier size_x, ElementIdentifier size_y);

	/**	@name	Pointer to the wrapped OpenCL memory. Non-const version will modify the device MTime! */
	//@{
	cl_mem GetOpenCLMemoryPointer();
	const cl_mem GetOpenCLMemoryPointer() const;
	//@}

	/**	@name	Width/Height of the Image */
	//@{
	TElementIdentifier GetWidth() const {return m_size_width;}
	TElementIdentifier GetHeight() const {return m_size_height;}
	//@}

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

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

	/// Allocate the buffer. Is delegated to the superclass. Only checks if AllocateManually was called before
	virtual Element* AllocateElements(ElementIdentifier size) const;

	/// Free the buffer. Is delegated to the superclass. (Does nothing. Only decreases the numAllocatedElements.)
	virtual void DeallocateManagedMemory();

	/// Creates the correct oclImgFormat for specific template arguments
	cl_image_format getOclImgFormat();


	void DeallocateOpenCLMemory();

protected:
	/// The actual OpenCL memory 
	mutable cl_mem m_OpenCLMemory;

	// NumberOfAllocations/Deallocations
	mutable int m_numAllocations;
	// Actual Image Size
	ElementIdentifier m_size_width, m_size_height;
	

private:

	/// purposely not implemented
	OpenCLImageMemoryImportImageContainer(const Self&); 
	/// purposely not implemented
	void operator=(const Self&);
};

/** @name Template instantiations */
//@{
typedef OpenCLImageMemoryImportImageContainer<unsigned long,float> OpenCLImageMemoryImportImageContainerF;
typedef OpenCLImageMemoryImportImageContainer<unsigned long,unsigned char> OpenCLImageMemoryImportImageContainerUC;
typedef OpenCLImageMemoryImportImageContainer<unsigned long,itk::Vector<float,3>> OpenCLImageMemoryImportImageContainerF3;
//@}

} // ritk


#endif // OPENCLIMAGEMEMORYIMPORTIMAGECONTAINER_H__