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

	Program:		Range Imaging Toolkit (RITK)
	Module:			ritkCudaArrayImportImageContainer.h
	Version:		$Revision: 1761 $
	Date:			$Date: 2011-09-23 17:25:41 +0200 (Fri, 23 Sep 2011) $

	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 CUDAARRAYIMPORTIMAGECONTAINER_H__
#define CUDAARRAYIMPORTIMAGECONTAINER_H__

#include "ritkCudaImportImageContainer.h"

namespace ritk
{

/**	@ingroup	Cuda
 *	@class		CudaArrayImportImageContainer
 *	@author		Jakob Wasza
 *	@brief		Memory container for CUDA arrays
 *
 *	@details
 *	This class provides methods for CUDA array management
 */
template<typename TElementIdentifier, typename TElement>
class CudaArrayImportImageContainer : public CudaImportImageContainer<TElementIdentifier,TElement>
{
public:
	/**	@name	Std typedefs */
	//@{
	typedef CudaArrayImportImageContainer								Self;
	typedef CudaImportImageContainer<TElementIdentifier,TElement>		Superclass;
	typedef itk::SmartPointer<Self>										Pointer;
	typedef itk::SmartPointer<const Self>								ConstPointer;
	//@}

	/// For convenience
	//@{
	typedef typename Superclass::GenericImportImageContainerType		GenericImportImageContainerType;
	typedef typename Superclass::ImportImageContainerType				ImportImageContainerType;
	//@}

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

	//@}

	/// Object creation
	itkNewMacro(Self);

	/// RTTI
	itkTypeMacro(CudaArrayImportImageContainer, CudaImportImageContainer);

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

	/**	@name	Deep copy */
	//@{

	/**	@brief	Deep copy the buffer
	 *	@param	Container	The container providing the source
	 *
	 *	@details
	 *	Copy data from an itk::ImportImageContainer, however, this class' implementation only addresses copying device memory,
	 *	host memory copy will be performed by the baseclass that eventually also allocates memory (host AND device). \n
	 *	This special CUDA container will copy the CUDA memory if a CUDAImportImageContainer can be derived from the parameter.
	 *	This class' implementation will automatically determine and execute the proper copy scheme (i.e. Array -> Regular, ...).
	 *	Note that copying device memory will be performed if and only if the device modified time is equal or more up-to-date 
	 *	than the host memory. 
	 */
	virtual void DeepCopy(ImportImageContainerType *Container);


	/**	@brief	Deep copy from a container
	 *	@param	Container	The container providing the source
	 *
	 *	@details
	 *	This method will simply remove the const qualifier (const_cast) of the input argument and pass it to the non-const DeepCopy(ImportImageContainerType *) method.
	 *	Note that a non-const input is necessary due to the synchronization mechanism. However, it is granted, that the memory (host or device) that is up-to-data
	 *	will NOT be modified!
	 */
	virtual void DeepCopy(const ImportImageContainerType *Container);

	//@}


	/**	@name	Pointer to the wrapped CUDA memory array. Non-const version will modify the device MTime! */
	//@{
	cudaArray *GetCudaMemoryArray();
	const cudaArray *GetCudaMemoryArray() const;
	//@}

	/**	@name Set/get the channel descriptor of the wrapped array */
	//@{
	virtual void SetChannelDesc(cudaChannelFormatDesc Desc);
	virtual cudaChannelFormatDesc GetChannelDesc() const;


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

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

	/// Allocate the buffer. Is delegated to the superclass.
	virtual Element* AllocateElements(ElementIdentifier size) const;

	/// Free the buffer. Is delegated to the superclass
	virtual void DeallocateManagedMemory();

	/**	@name	Methods that have to be executed in the global CUDA context */
	//@{
	CudaConstMethodMacro(CudaArrayImportImageContainer, AllocateCudaMemory);
	CudaMethodMacro(CudaArrayImportImageContainer, DeallocateCudaMemory);
	CudaMethodMacro(CudaArrayImportImageContainer, CopyDeviceToHost);
	CudaMethodMacro(CudaArrayImportImageContainer, CopyHostToDevice);
	Superclass *m_TmpCudaContainer;
	CudaMethodMacro(CudaArrayImportImageContainer, DeepCopyCudaMemory);
	//@}

protected:
	/// The actual CUDA array
	cudaArray *m_CudaArray;

	/// The channel descriptor of the CUDA array
	cudaChannelFormatDesc m_Desc;

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

/** @name Template instantiations */
//@{
typedef CudaArrayImportImageContainer<unsigned long,float> CudaArrayImportImageContainerF;
//@}

} // ritk


#endif // CUDAARRAYIMPORTIMAGECONTAINER_H__
