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

	Program:		Range Imaging Toolkit (RITK)
	Module:			ritkGenericImportImageContainer.txx
	Version:		$Revision: 2439 $
	Date:			$Date: 2012-01-22 16:31:28 +0100 (So, 22 Jan 2012) $

	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

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

#include "ritkGenericImportImageContainer.h"

namespace ritk
{

//----------------------------------------------------------------------------
template<typename TElementIdentifier, typename TElement>
GenericImportImageContainer<TElementIdentifier, TElement>
::GenericImportImageContainer()
{
}


//----------------------------------------------------------------------------
template<typename TElementIdentifier, typename TElement>
GenericImportImageContainer<TElementIdentifier, TElement>
::~GenericImportImageContainer()
{
	this->DeallocateManagedMemory();
}


//----------------------------------------------------------------------------
template<typename TElementIdentifier, typename TElement>
void
GenericImportImageContainer<TElementIdentifier, TElement>::
PrintSelf(std::ostream& os, itk::Indent indent) const
{
	os << "GenericImportImageContainer" << std::endl;
	Superclass::PrintSelf(os,indent);
} 


//----------------------------------------------------------------------------
template<typename TElementIdentifier, typename TElement>
typename GenericImportImageContainer<TElementIdentifier, TElement>::Element*
GenericImportImageContainer<TElementIdentifier, TElement>::
AllocateElements(ElementIdentifier size) const
{
	return Superclass::AllocateElements(size);
}


//----------------------------------------------------------------------------
template<typename TElementIdentifier, typename TElement>
void
GenericImportImageContainer<TElementIdentifier, TElement>::
DeallocateManagedMemory()
{
	Superclass::DeallocateManagedMemory();
}


//----------------------------------------------------------------------------
template<typename TElementIdentifier, typename TElement>
void
GenericImportImageContainer<TElementIdentifier, TElement>::
HostModified()
{
	m_HostMTime.Modified();
}


//----------------------------------------------------------------------------
template<typename TElementIdentifier, typename TElement>
void
GenericImportImageContainer<TElementIdentifier, TElement>::
DeviceModified()
{
	m_DeviceMTime.Modified();
}


//----------------------------------------------------------------------------
template<typename TElementIdentifier, typename TElement>
unsigned long
GenericImportImageContainer<TElementIdentifier, TElement>::
GetHostMTime() const
{
	return m_HostMTime.GetMTime();
}


//----------------------------------------------------------------------------
template<typename TElementIdentifier, typename TElement>
unsigned long
GenericImportImageContainer<TElementIdentifier, TElement>::
GetDeviceMTime() const
{
	return m_DeviceMTime.GetMTime();
}


//----------------------------------------------------------------------------
template<typename TElementIdentifier, typename TElement>
const itk::TimeStamp& 
GenericImportImageContainer<TElementIdentifier, TElement>::
GetHostTimeStamp() const
{
	return m_HostMTime;
}


//----------------------------------------------------------------------------
template<typename TElementIdentifier, typename TElement>
const itk::TimeStamp& 
GenericImportImageContainer<TElementIdentifier, TElement>::
GetDeviceTimeStamp() const
{
	return m_DeviceMTime;
}


//----------------------------------------------------------------------------
template<typename TElementIdentifier, typename TElement>
void
GenericImportImageContainer<TElementIdentifier, TElement>::
Synchronize()
{
	// Call the correct synchronization routine based on the more up to date MTime
	if ( m_HostMTime < m_DeviceMTime )
	{
		SynchronizeHost();
	}
	else if ( m_DeviceMTime < m_HostMTime )
	{
		SynchronizeDevice();
	}
	else
	{
		//No synchronization required
	}
}


//----------------------------------------------------------------------------
template<typename TElementIdentifier, typename TElement>
void
GenericImportImageContainer<TElementIdentifier, TElement>::
SynchronizeDevice()
{
	m_DeviceMTime = m_HostMTime;
}


//----------------------------------------------------------------------------
template<typename TElementIdentifier, typename TElement>
void
GenericImportImageContainer<TElementIdentifier, TElement>::
SynchronizeHost()
{
	m_HostMTime = m_DeviceMTime;
}


//----------------------------------------------------------------------------
template<typename TElementIdentifier, typename TElement>
void
GenericImportImageContainer<TElementIdentifier, TElement>::
DeepCopy(const ImportImageContainerType *Container)
{
	// Cast and pass
	ImportImageContainerType *NonConstContainer = const_cast<ImportImageContainerType*>(Container);
	if ( !NonConstContainer )
		itkExceptionMacro(<<"Could not remove const qualifier!");
	DeepCopy(NonConstContainer);
}


//----------------------------------------------------------------------------
template<typename TElementIdentifier, typename TElement>
void
GenericImportImageContainer<TElementIdentifier, TElement>::
DeepCopy(ImportImageContainerType *Container)
{
	// Allocate memory on demand
	if ( this->Capacity() != Container->Capacity() )
	{
		// If we have no capacity, there is no need to deallocate memory.
		if ( this->Capacity() != 0 )
		{
			DeallocateManagedMemory();
		}
		Superclass::Reserve(Container->Capacity());
	}

	// Check if we can cast this object to a GenericImportImageContainer and, if so, synchronize
	Self::Pointer GenericContainer = dynamic_cast<Self*>(Container);
	if ( GenericContainer )
	{
		GenericContainer->Synchronize();
	}

	// Std host memory copy
	memcpy(this->GetBufferPointer(), Container->GetBufferPointer(), Container->Capacity()*sizeof(Element));

	// Synchronize. This should be mapped to SynchronizeDevice() as we modify the host
	m_HostMTime.Modified();
	Synchronize();
}


} // ritk