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

	Program:		Range Imaging Toolkit (RITK)
	Module:			ritkRImageFilterWrapper.h
	Version:		$Revision: 1817 $
	Date:			$Date: 2011-09-30 16:52:28 +0200 (Fri, 30 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 RImageFilterWrapper_H__
#define RImageFilterWrapper_H__

#include "ritkCommon.h"

#include <itkImageToImageFilter.h>
#include "ritkTimer.h"
#include "ritkRImage.h"

namespace ritk
{

/**	@ingroup	Common
 *	@class		RImageFilterWrapper
 *	@author		Jakob Wasza
 *	@brief		Base class for all filters that operate on range images
 *
 *	@details
 *	This class provides the basic interface for filtering range images.
 *	Filtering of range images differs a little from the filtering of "normal" images
 *	as range images are composed of several sub images (e.g. range image, RGB images)
 *	where it might be necessary to apply a certain filter to only one specific sub image 
 *	(usually, only the range image is filtered). The sub images the filter will operate on should 
 *	be set via the SetFilterMode() method. This base class defines four default filter modes: \n
 *		-	No filtering \n
 *		-	range \n
 *		-	amplitudes \n
 *		-	world coords \n
 *	If additional filter modes are required the types should be defined in accordance to the once provided. \n
 *	The actual filtering is triggered as in regular ITK filters through the Update() mechanism. This will 
 *	eventually invoke the DoFiltering() method that all subclasses have to provide. This method has to 
 *	perform the actual filtering based on the filter mode. \n
 *	A RImageFilterWrapper can be used as a regular ITK pipeline element. In particular, this means that
 *	region propagation through the pipeline is fully supported. However, this does NOT hold true for
 *	filters that operate on sub images and are eventually invoked in the DoFiltering() method. It is very
 *	important that these sub filters do not describe a composite filter that is part of the actual processing
 *	pipeline. See DoFiltering() for details. \n
 *	Automatic runtime evaluation is supported by this class' implementation of the GenerateData()
 *	method and the Timer class that RImageFilterWrapper is derived from: The timer will be 
 *	started at the beginning of GenerateData() and stopped after all calls finished. Elapsed times will
 *	by default be averaged over 10 passes (see Timer how to change this behaviour).
 */
template<class TRImage>
class RImageFilterWrapper : public itk::ImageToImageFilter<TRImage,TRImage>,  public TimerD
{
public:
	/** @name	Typedefs */
	//@{

	/** @name	Standard typedefs */
	//@{
	typedef RImageFilterWrapper							Self;
	typedef itk::ImageToImageFilter<TRImage,TRImage>	Superclass;
	typedef itk::SmartPointer<Self>						Pointer;
	typedef itk::SmartPointer<const Self>				ConstPointer;
	//@}

	/**	@name	Input and output typedefs */
	//@{
	typedef typename Superclass::InputImageType		InputImageType;
	typedef typename InputImageType::Pointer		InputImagePointer;
	typedef typename InputImageType::ConstPointer	InputImageConstPointer;
	typedef typename Superclass::OutputImageType	OutputImageType;
	typedef typename OutputImageType::Pointer		OutputImagePointer;
	//@}

	//@}

	/// RTTI
	itkTypeMacro(RImageFilterWrapper, itk::ImageToImageFilter);

	/**	@name	Filter mode */
	//@{
	/// The type of a filter mode
	typedef unsigned int FilterModeType;

	/**	@name Default modes */
	//@{
	static const FilterModeType	NONE		= 0;
	static const FilterModeType	RGB			= 1;
	static const FilterModeType	RANGE		= 2;
	static const FilterModeType	WORLDCOORD	= 4;
	//@}


	/**	@brief	Set the filter mode
	 *	@param	Mode	The mode using bitwise OR
	 *
	 *	@details
	 *	Set the filter mode for this RImageFilter. The argument can be constructed out of 
	 *	the provided filter modes by bitwise OR, e.g.
	 *	\code
	 * // Set the filter to operate on the RGB and range data
	 * RImageFilter->SetFilterMode(RImageFilterWrapper::RGB | RImageFilterWrapper::RANGE);
	 *	\endcode
	 *	By default, the filter mode is set to NONE!
	 */
	void SetFilterMode(FilterModeType Mode);

	/// Get the filter mode
	FilterModeType GetFilterMode();
	//@}

	/**	Invalidate the outputs. See GenerateData() for details */
	void InvalidateOutputs();

	/// Set the auto-timer mode (default is true)
	void SetAutoTimerMode(bool Mode);

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

	/**	@brief	Filter the range image
	 *	
	 *	@details
	 *	This method has to do the actual filtering and is eventually invoked by
	 *	calling the filter's Update() method. Filtering has to be done in accordance
	 *	to the filter mode. It is very important to set the requested region of the sub
	 *	filter's output to the requested region of the output of the RImageFilterWrapper.
	 *	This will ensure correct region propagation for the sub image filter pipeline! \n
	 *	A typical scheme for this method is illustrated in the following code snippet:
	 *	\code
	 * void
	 * MyFilter::DoFiltering()
	 * {
	 *  // Filter the range image if requested
	 *  if ( (GetFilterMode()&RANGE) == RANGE )
	 *  {
	 *   // Standard ITK filtering
	 *   typedef itk::SomeFilter<InputImageType::RangeImageType> FilterType;
	 *   FilterType::Pointer Filter = FilterType::New();
	 *   Filter->SetParameter(m_MyParameter);
	 *   Filter->SetInput1(this->GetInput->GetRangeImage());
	 *   Filter->SetInput2(this->GetInput->GetRGBImage()); // Optional second parameter for your filter
	 *   Filter->GetOutput()->SetRequestedRegion(this->GetOutput()->GetRequestedRegion()); // Region propagation operates on the filter OUTput!
	 *   Filter->Update();
	 *  
	 *   // Set the filtered range image to the output. Also disconnect the image from the sub pipeline
	 *   this->GetOutput()->SetRangeImage(Filter->GetOutput());
	 *   this->GetOutput()->GetRangeImage()->DisconnectPipeline();
	 *  }
	 *  
	 *  // Filter the RGB image if requested
	 *  ...
	 * }
	 *	\endcode
	 *	@sa GenerateData()
	 */
	virtual void DoFiltering()=0;


	/**	@brief	Generate the data
	 *
	 *	@details
	 *	Just as for regular ITK filters this method is called during pipeline update and will eventually 
	 *	generate the filters output. However, the implementation is completely different to ITK filters for
	 *	the following reasons: \n
	 *		1.	RImageFilterWrappers are in general templated over a RImage base class. Though, the input
	 *			may be a user defined RImage sub class and, thus, the output as generated by the 
	 *			ITK ImageToImageFilter (from which this class is derived from) has the wrong type. \n
	 *		2.	As the concrete type of the input is not known to a RImageFilterWrapper (possibly a derived class
	 *			as in 1) it cannot determine the sub images that are not filtered and have to be copied to the output. \n
	 *	The first problem is solved by setting the output dynamically via ITK's Object::CreateAnother() method. However, this 
	 *	will result in invalid inputs for downstream pipeline elements (that previously connected their input to the output of the
	 *	upstream). For downstream elements this means the following: If the input's source' output coincides with the current
	 *	input then nothing has to be done. Otherwise, the current input has to be updated by using the current inputs' source'
	 *	output. All this is handled internally by this base class, however, this scheme implies the need to "rember" sources. This
	 *	is achieved by providing two outputs. As it may be necessary to invalidate these outputs manually (e.g. in the reconfiguration
	 *	of a dynamic pipeline) the InvalidateOutputs() method is provided. Invalidating an output creates a new blank output. \n
	 *	For the second problem two solution strategies exist: A shallow copy (aka Graft() in ITK) or a 
	 *	deep copy of the data. As both copy operations are delegated to the actual image type it is ensured that
	 *	all data is available at the output. A shallow copy is faster than a deep copy but has the consequence
	 *	that by modifying the output data the input data is also modified as the two images refer to the same
	 *	memory region. Whether a shallow copy is sufficient or a deep copy is mandatory depends on the concrete situation. 
	 *	Thus, this base class provides the SetCopyMode() method, by default shallow copying is enabled. Note by setting regions and
	 *	calling Allocate() on a particular sub-image will reserve new memory, i.e. the grafted image is not affected by modifications
	 *	on the output image.\n
	 *	However, if all these concepts do not apply for a concrete filter you may override this GenerateData() method.
	 *	@sa	DoFiltering()
	 *	@sa SetCopyMode()
	 */
	virtual void GenerateData();

	/**	@name The copy mode */
	//@{
	/// The modes
	enum CopyModes
	{
		SHALLOW,
		DEEP
	};
	/// Set the copy mode
	void SetCopyMode(CopyModes Mode);
	/// Get the copy mode
	CopyModes GetCopyMode();
	//@}

protected:
	/// The filter mode
	FilterModeType m_FilterMode;
	/// The copy mode
	CopyModes m_CopyMode;
	/// The auto-timer mode
	bool m_AutoTimer;


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


/** @name Template instantiations */
//@{
typedef class COMMON_EXPORT RImageFilterWrapper<RImage<float,2> > RImageFilterWrapperF2;
//@}

// #include "RImageFilterWrapper.txx"

} // end namespace ritk

#endif // RImageFilterWrapper_H__
