#include "ClampIntensityImageFilter.h"

#include <itkProcessObject.h>
#include <itkImageRegionIterator.h>

#include "ritkGenericImportImageContainer.h"

template<class TInput,class TOutput,class TMaskImage>
ClampIntensityImageFilter<TInput,TOutput,TMaskImage>
::ClampIntensityImageFilter()
{
	MaskImagePointer MaskImage = static_cast<MaskImageType*>(this->MakeOutput(1).GetPointer()); 
	itk::ProcessObject::SetNumberOfRequiredOutputs(2);
	itk::ProcessObject::SetNthOutput(1, MaskImage.GetPointer());
}


template<class TInput,class TOutput,class TMaskImage>
ClampIntensityImageFilter<TInput,TOutput,TMaskImage>
::~ClampIntensityImageFilter()
{
}


//----------------------------------------------------------------------------
template<class TInput,class TOutput,class TMaskImage>
typename ClampIntensityImageFilter<TInput,TOutput,TMaskImage>::DataObjectPointer
ClampIntensityImageFilter<TInput,TOutput,TMaskImage>
::MakeOutput(unsigned int idx)
{
	switch ( idx )
	{
	case 1:
		return static_cast<itk::DataObject*>(MaskImageType::New().GetPointer());
	default:
		return Superclass::MakeOutput(idx);
	}
}


//----------------------------------------------------------------------------
template<class TInput,class TOutput,class TMaskImage>
typename ClampIntensityImageFilter<TInput,TOutput,TMaskImage>::MaskImagePointer
ClampIntensityImageFilter<TInput,TOutput,TMaskImage>
::GetMaskOutput()
{
	return static_cast<MaskImageType*>(itk::ProcessObject::GetOutput(1));
}


//----------------------------------------------------------------------------
template<class TInput,class TOutput,class TMaskImage>
void
ClampIntensityImageFilter<TInput,TOutput,TMaskImage>
::SetLowerBound(InputPixelType value)
{
	m_LowerBound = value;
	this->Modified();
}


//----------------------------------------------------------------------------
template<class TInput,class TOutput,class TMaskImage>
typename ClampIntensityImageFilter<TInput,TOutput,TMaskImage>::InputPixelType
ClampIntensityImageFilter<TInput,TOutput,TMaskImage>
::GetLowerBound()
{
	return m_LowerBound;
}


//----------------------------------------------------------------------------
template<class TInput,class TOutput,class TMaskImage>
void
ClampIntensityImageFilter<TInput,TOutput,TMaskImage>
::SetUpperBound(InputPixelType value)
{
	m_UpperBound = value;
	this->Modified();
}


//----------------------------------------------------------------------------
template<class TInput,class TOutput,class TMaskImage>
void
ClampIntensityImageFilter<TInput,TOutput,TMaskImage>
::SetValidFlag(typename MaskImageType::PixelType Value)
{
	m_ValidFlag = Value;
	this->Modified();
}


//----------------------------------------------------------------------------
template<class TInput,class TOutput,class TMaskImage>
typename ClampIntensityImageFilter<TInput,TOutput,TMaskImage>::InputPixelType
ClampIntensityImageFilter<TInput,TOutput,TMaskImage>
::GetUpperBound()
{
	return m_UpperBound;
}


//----------------------------------------------------------------------------
template<class TInput,class TOutput,class TMaskImage>
void
ClampIntensityImageFilter<TInput,TOutput,TMaskImage>
::BeforeThreadedGenerateData()
{
	Superclass::BeforeThreadedGenerateData();
	/*typedef itk::ImageRegionConstIterator<InputImageType> InputIteratorType;
	float Mean = 0;
	float Min = 1e16;
	float Max = -1e16;
	InputIteratorType itIn(this->GetInput(),this->GetInput()->GetRequestedRegion());
	for ( itIn.GoToBegin(); !itIn.IsAtEnd(); ++itIn )
	{
		Mean += itIn.Value();
		if ( itIn.Value() > Max )
			Max = itIn.Value();
		if ( itIn.Value() < Min )
			Min = itIn.Value();
	}
	Mean /= this->GetInput()->GetRequestedRegion().GetNumberOfPixels();
	std::cout << "Clamping to [" << m_LowerBound << ":" << m_UpperBound << "]" << std::endl;
	std::cout << "Mean: " << Mean << " Min: " << Min << " Max:" << Max << std::endl;*/

	// Synchronize before calling the superclass' implementation
	InputImagePointer NonConstInput = const_cast<InputImageType*>(this->GetInput());
	if ( NonConstInput )
	{
		typedef ritk::GenericImportImageContainer<typename InputImageType::PixelContainer::ElementIdentifier, typename InputImageType::PixelContainer::Element> GenericContainerType;
		typename GenericContainerType::Pointer GenericContainer = dynamic_cast<GenericContainerType*>(NonConstInput->GetPixelContainer());
		if ( GenericContainer )
			GenericContainer->Synchronize();
	}
	else
		itkExceptionMacro(<<"Could not cast to const input image!");
	//const MaskImageType *tmp = this->GetMaskImageInput();
	MaskImagePointer NonConstMaskInput = const_cast<MaskImageType*>(this->GetMaskImageInput());
	if ( NonConstMaskInput )
	{
		typedef ritk::GenericImportImageContainer<typename MaskImageType::PixelContainer::ElementIdentifier, typename MaskImageType::PixelContainer::Element> GenericContainerType;
		typename GenericContainerType::Pointer GenericContainer = dynamic_cast<GenericContainerType*>(NonConstMaskInput->GetPixelContainer());
		if ( GenericContainer )
			GenericContainer->Synchronize();
	}
	else
		itkExceptionMacro(<<"Could not cast to const mask input image!");

	this->GetOutput()->SetRequestedRegion(this->GetInput()->GetRequestedRegion());
	this->GetOutput()->SetBufferedRegion(this->GetInput()->GetBufferedRegion());
	this->GetOutput()->SetLargestPossibleRegion(this->GetInput()->GetLargestPossibleRegion());
	this->GetOutput()->Allocate();

	this->GetMaskOutput()->SetRequestedRegion(this->GetInput()->GetRequestedRegion());
	this->GetMaskOutput()->SetBufferedRegion(this->GetInput()->GetBufferedRegion());
	this->GetMaskOutput()->SetLargestPossibleRegion(this->GetInput()->GetLargestPossibleRegion());
	this->GetMaskOutput()->Allocate();

}


//----------------------------------------------------------------------------
template<class TInput,class TOutput,class TMaskImage>
void
ClampIntensityImageFilter<TInput,TOutput,TMaskImage>
::ThreadedGenerateData(const typename OutputImageType::RegionType &OutputRegionForThread,int threadId)
{
	// Create iterators
	typedef itk::ImageRegionConstIterator<InputImageType> InputIteratorType;
	typedef itk::ImageRegionIterator<OutputImageType> OutputIteratorType;
	typedef itk::ImageRegionConstIterator<MaskImageType> InputMaskIteratorType;
	typedef itk::ImageRegionIterator<MaskImageType> OutputMaskIteratorType;
	InputIteratorType itIn(this->GetInput(),OutputRegionForThread);
	OutputIteratorType itOut(this->GetOutput(),OutputRegionForThread);
	InputMaskIteratorType itMaskIn(this->GetMaskImageInput(), OutputRegionForThread);
	OutputMaskIteratorType itMaskOut(this->GetMaskOutput(),OutputRegionForThread);

	// Loop over the pixels
	for ( itIn.GoToBegin(),itOut.GoToBegin(),itMaskOut.GoToBegin(),itMaskIn.GoToBegin(); !itOut.IsAtEnd(); ++itIn,++itOut,++itMaskOut,++itMaskIn )
	{
		// Check for bounds
		if ( itIn.Value() < m_LowerBound )
		{
			itOut.Value() = m_LowerBound;
			itMaskOut.Value() = itMaskIn.Value() & (~m_ValidFlag);
		}
		else if ( itIn.Value() > m_UpperBound )
		{
			itOut.Value() = m_UpperBound;
			itMaskOut.Value() = itMaskIn.Value() & (~m_ValidFlag);
		}
		else
		{
			itOut.Value() = itIn.Value();
			itMaskOut.Value() = itMaskIn.Value() | (m_ValidFlag);
		}
		//itOut.Value() = exp(itOut.Value());
	}
}


//----------------------------------------------------------------------------
template<class TInput,class TOutput,class TMaskImage>
void
ClampIntensityImageFilter<TInput,TOutput,TMaskImage>
::AfterThreadedGenerateData()
{
	Superclass::AfterThreadedGenerateData();
}

