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

	Program:		Range Imaging Toolkit (RITK)
	Module:			ritkRImageFilterWrapper.txx
	Version:		$Revision: 1761 $
	Date:			$Date: 2011-09-23 17:25:41 +0200 (Fr, 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

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

#include "ritkRImageFilterWrapper.h"

#include <string.h>

namespace ritk
{


//----------------------------------------------------------------------------
template<class TRImage>
RImageFilterWrapper<TRImage>
::RImageFilterWrapper()
{
	// No filtering, just copying by default
	m_FilterMode = NONE;

	// Shallow copy (grafting) by default
	m_CopyMode = SHALLOW;

	// Autotimer by default. We average over 10 passes
	m_AutoTimer = true;
	SetNumberOfPassesToAverageRuntime(10);

	// We might have to hold a handle due to generic image propagation
	this->ProcessObject::SetNumberOfRequiredOutputs(2);
}


//----------------------------------------------------------------------------
template<class TRImage>
RImageFilterWrapper<TRImage>
::~RImageFilterWrapper()
{
}


//----------------------------------------------------------------------------
template<class TRImage>
void
RImageFilterWrapper<TRImage>
::SetFilterMode(FilterModeType Mode)
{
	// Nothing to do
	if ( Mode == m_FilterMode )
		return;

	// Update filter mode
	m_FilterMode = Mode;
	this->Modified();
}


//----------------------------------------------------------------------------
template<class TRImage>
typename RImageFilterWrapper<TRImage>::FilterModeType
RImageFilterWrapper<TRImage>
::GetFilterMode()
{
	return m_FilterMode;
}


//----------------------------------------------------------------------------
template<class TRImage>
void
RImageFilterWrapper<TRImage>
::SetAutoTimerMode(bool Mode)
{
	m_AutoTimer = Mode;
}


//----------------------------------------------------------------------------
template<class TRImage>
void
RImageFilterWrapper<TRImage>
::InvalidateOutputs()
{
	this->ProcessObject::SetNthOutput(0,NULL);
	this->ProcessObject::SetNthOutput(1,NULL);
}


//----------------------------------------------------------------------------
template<class TRImage>
void
RImageFilterWrapper<TRImage>
::GenerateData()
{
	// Start timer
	if ( m_AutoTimer )
		StartTimer();

	// Update the input. 
	typedef itk::ImageSource<TRImage> SourceType;
	InputImageConstPointer OldInput = this->GetInput();
	typename SourceType::Pointer Source = dynamic_cast<SourceType*>((itk::ProcessObject*)this->GetInput()->GetSource());
	if ( Source && this->GetInput() != Source->GetOutput() )
		this->SetInput(Source->GetOutput());

	// Update the output
	if ( !this->GetOutput() || strcmp(this->GetOutput()->GetNameOfClass(), this->GetInput()->GetNameOfClass()) != 0 )
	{
		// Hold handle to the old output
		OutputImagePointer OldOutput = this->GetOutput();

		// Set the output to match the input type
		typename OutputImageType::Pointer Output = dynamic_cast<OutputImageType*>((itk::LightObject*)this->GetInput()->CreateAnother());
		if ( !Output )
		{
			itkExceptionMacro(<<"Could not cast to output image type!");
		}
		/*else
		{
			std::cout << "Cloning..." << std::endl;
		}*/
		this->ProcessObject::SetNthOutput(0, Output.GetPointer());

		// Remember old output. In particular, this will set the source of output #1 (= the old output) to ourself.
		this->ProcessObject::SetNthOutput(1,OldOutput);

		// Set the regions. Using the old input ensures correct region propagation trough the pipeline!
		this->GetOutput()->SetLargestPossibleRegion(this->GetInput()->GetLargestPossibleRegion());
		this->GetOutput()->SetBufferedRegion(this->GetInput()->GetBufferedRegion());
		this->GetOutput()->SetRequestedRegion(this->GetInput()->GetRequestedRegion());

		// Allocate the output
		this->GetOutput()->Allocate();
	}

	// Deep copy or shallow copy
	if ( m_CopyMode == DEEP )
	{
		this->GetOutput()->DeepCopy(this->GetInput());
	}
	else
	{
		this->GetOutput()->Graft(this->GetInput());
	}

	/*std::cout << "OldInputRegions: " << std::endl;
	std::cout << "	" << OldInput->GetRequestedRegion() << std::endl;
	std::cout << "	" << OldInput->GetLargestPossibleRegion() << std::endl;

	std::cout << "InputRegions: " << std::endl;
	std::cout << "	" << this->GetInput()->GetRequestedRegion() << std::endl;
	std::cout << "	" << this->GetInput()->GetLargestPossibleRegion() << std::endl;

	std::cout << "OldOutputRegions: " << std::endl;
	std::cout << "	" << OldOutput->GetRequestedRegion() << std::endl;
	std::cout << "	" << OldOutput->GetLargestPossibleRegion() << std::endl;

	std::cout << "OutputRegions: " << std::endl;
	std::cout << "	" << Output->GetRequestedRegion() << std::endl;
	std::cout << "	" << Output->GetLargestPossibleRegion() << std::endl;
	std::cout << "====================================================" << std::endl;*/

	// Invoke the actual filtering method
	DoFiltering();

	// Stop timer
	if ( m_AutoTimer )
		StopTimer();
}


//----------------------------------------------------------------------------
template<class TRImage>
void
RImageFilterWrapper<TRImage>
::SetCopyMode(CopyModes Mode)
{
	m_CopyMode = Mode;
}


//----------------------------------------------------------------------------
template<class TRImage>
typename RImageFilterWrapper<TRImage>::CopyModes
RImageFilterWrapper<TRImage>
::GetCopyMode()
{
	return m_CopyMode;
}

} // end namespace ritk
