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

	Program:		Range Imaging Toolkit (RITK)
	Module:			ritkFilterPlugin.h
	Version:		$Revision: 1791 $
	Date:			$Date: 2011-09-28 11:43:43 +0200 (Wed, 28 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 FILTERPLUGIN_H__
#define FILTERPLUGIN_H__

#include "ritkCore.h"

#include <QObject>

#include "ritkPluginBase.h"
#include "ritkRImageFilterWrapper.h"
#include "ritkAcquisitionPipeline.h"

namespace ritk
{

/**	@ingroup	Core
 *	@class		FilterPlugin
 *	@author		Jakob Wasza
 *	@brief		Base class for all plugins that provide a filter for the acquisition pipeline.
 *
 *	@details
 *	Filter plugins are one class of RITK plugins and provide a filter that eventually will
 *	be part of the acquisition pipeline. Filter plugins can be seen as a wrapper around a regular
 *	RImageFilterWrapper and are supposed to provide functionalities to set the filter's parameters
 *	during runtime (usually using a GUI). The actual filter object is provided through the GetFilter()
 *	method that all subclasses have to provide. Once a filter plugin is started its wrapped filter object
 *	is automatically added to the acquisition pipeline. Several filter modes can be set, however, only 
 *	range filtering should be used atm (@sa RImageFilterWrapper) .\n
 *	A plugin specific GUI can be provided via the GetPluginGUI() method that should return a QWidget 
 *	containing the actual GUI. It is very important that the provided GUI is deleted in the plugins' destructor.\n
 *	As the acquisition pipeline (and thus the execution of the wrapped filter) usually runs in its own thread 
 *	it is crucial to change the filter parameters in a thread safe manner. This base class therefore provides
 *	methods to (un)lock the pipeline. Note that subclasses have no direct access to the acquisition pipeline. \n
 *	Automatic runtime computation is provided from RImageFilterWrapper.
 */
class CORE_EXPORT FilterPlugin : public QObject, public PluginBase
{
	Q_OBJECT

public:
	/// Constructor
	FilterPlugin();
	/// Destructor
	virtual ~FilterPlugin();

	/**	@brief	Start the filter plugin
	 *	@param	Pipeline	A pointer to the acquisition pipeline
	 *	@return	True if the plugin is started successfully, false otherwise
	 *
	 *	@details
	 *	A call to this method will start the filter plugin. In particular,
	 *	this includes connecting the wrapped filter to the acquisition pipeline
	 *	that has to be passed as argument to this function. This class' implementation
	 *	will check if the argument is actually the acquisition pipeline. \n
	 *	After starting the plugin through this method the wrapped filter is part 
	 *	of the pipeline and parameter changes have to be thread safe w.r.t 
	 *	to the acquisition pipeline. \n
	 *	Note that this method is NOT thread safe! Calling threads have to lock
	 *	the plugin manually.
	 *	@sa LockPipeline() @sa UnlockPipeline()
	 */
	virtual bool StartPlugin(void *Pipeline);

	/**	@brief	Stop the filter plugin
	 *	@return	True on success, false otherwise
	 *
	 *	@details
	 *	A call to this method will stop the filter plugin. This includes
	 *	removing the wrapped filter object from the acquisition pipeline.\n
	 *	Note that this call is NOT thread safe! \n
	 */
	virtual bool StopPlugin();

	/// Needs to be overridden
	void GetRuntime(double *Runtime, double *RuntimeStdDeviation=0);

	/**	@name	Typedefs for the filter */
	//@{
	typedef RImageFilterWrapperF2		FilterType;
	typedef FilterType::Pointer			FilterPointer;
	//@}

	/// The type of filter mode
	typedef FilterType::FilterModeType FilterModeType;

public slots:
	/**	@brief	Set the filter mode
	 *	@param	Mode	The filter mode
	 *
	 *	@details
	 *	This method will set the filter mode. This baseclass' implementation
	 *	will set the internal member variable and pass the argument automatically
	 *	to the wrapped filter provided by the GetFilter() method. If this behaviour
	 *	is not appropriate, subclasses may overload/override this method. A call to this method
	 *	will lock the pipeline before setting the mode to the wrapped filter, however the
	 *	plugin itself is NOT locked!
	 * @sa SetFilterMode()
	 * @sa RImageFilterWrapper::SetFilterModes()
	 */
	virtual void SetFilterMode(FilterModeType Mode);

	/**	@brief	Update filter mode
	 *
	 *	@details
	 *	This method will set the filter mode based on the members provides by this base class 
	 *	(m_FilterRGB,m_FilterRange,m_FilterWorldCoord). Based on these members the mode
	 *	is computed and SetFilterModes(FilterModes Mode) is called.
	 * @sa SetFilterMode(FilterModes Mode)
	 */
	virtual void UpdateFilterMode();

	/**	@brief	Enable/disable filtering of the RGB data
	 *	@param	b	true to enable, false to disable
	 *
	 *	@details
	 *	This method will enable or disable filtering of the RGB data. This method updates
	 *	the internal flag for RGB filtering (m_FilterRGB) followed by a call to 
	 *	UpdateFilterMode().
	 */
	virtual void SetRGBFilterMode(bool b);

	/**	@brief	Enable/disable filtering of the range data
	 *	@param	b	true to enable, false to disable
	 *
	 *	@details
	 *	This method will enable or disable filtering of the range data. This method updates
	 *	the internal flag for range filtering (m_FilterRange) followed by a call to 
	 *	UpdateFilterMode().
	 */
	virtual void SetRangeFilterMode(bool b);

	/**	@brief	Enable/disable filtering of the world coord data
	 *	@param	b	true to enable, false to disable
	 *
	 *	@details
	 *	This method will enable or disable filtering of the world coord data. This method updates
	 *	the internal flag for range filtering (m_FilterWorldCoord) followed by a call to 
	 *	UpdateFilterMode().
	 */
	virtual void SetWorldCoordFilterMode(bool b);
	
protected:
	/**	@brief	Get the filter
	 *	@return	Pointer to the filter object
	 *
	 *	@brief
	 *	Get the pointer to the wrapped filter provided by this plugin.
	 *	Subclasses have to implement this method. The returned
	 *	filter will be added to the acquisition pipeline when
	 *	the filter plugin is started using the StartPlugin() method. \n
	 *	\sa StartPlugin()
	 */
	virtual FilterPointer GetFilter()=0;

	/**	@brief	Will lock the pipeline
	 *
	 *	@details
	 *	A call to this method will lock the pipeline which allows 
	 *	thread safe operations on the pipeline. Note that a call to
	 *	this method will halt the calling thread if the pipeline is
	 *	already locked. Trying to call this method multiply times
	 *	without unlocking the pipeline will result in a dead lock!\n
	 *	A typical scenario where locking the pipeline is required would be 
	 *	\code
	 * void
	 * MyFilterPlugin::ParameterChanged(float NewValue)
	 * {
	 *  // Lock the pipeline
	 *  LockPipeline();
	 *
	 *  // Set the new value to our wrapped filter
	 *  m_MyFilter->SetParameter(NewValue);
	 * 
	 *  // Unlock the pipeline
	 *  UnlockPipeline();
	 * }
	 *	\endcode
	 *	\sa UnlockPipeline() \sa AcquisitionPipeline::Lock()
	 */
	void LockPipeline();

	/**	@brief	Will unlock the pipeline
	 *
	 *	@details
	 *	Will unlock the acquisition pipeline. \n
	 *	\sa LockPipeline() \sa AcquisitionPipeline::Unlock()
	 */
	void UnlockPipeline();

protected:
	/// The filter mode
	FilterModeType m_FilterMode;
	/// Flag that indicates whether to filter the RGB data
	bool m_FilterRGB;
	/// Flag that indicates whether to filter the range data
	bool m_FilterRange;
	/// Flag that indicates whether to filter the world coord data
	bool m_FilterWorldCoord;

private:
	/// The acquisition pipeline
	AcquisitionPipeline *m_AcquisitionPipeline;
	/// Pointer to the filter provided by this plugin
	FilterPointer m_FilterPointer;
};

} // end namespace ritk

#endif // FILTERPLUGIN_H__