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

	Program:		Range Imaging Toolkit (RITK)
	Module:			ritkPluginBase.h
	Version:		$Revision: 1992 $
	Date:			$Date: 2011-10-31 09:33:43 +0100 (Mo, 31 Okt 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 PLUGINBASE_H__
#define PLUGINBASE_H__

#include "ritkCore.h"

#include <QObject>
#include <QWidget>
#include <QMutex>


namespace ritk
{

/**	@ingroup	Core
 *	@class		PluginBase
 *	@author		Jakob Wasza
 *	@brief		Base class for all plugins in the RITK
 *
 *	@details
 *	This class provides the very basic interface for all plugins that are to be used
 *	within the RITK framework. In particular, this includes \n
 *		- Starting/stopping a plugin \n
 *		- (Un)locking the plugin for thread safe access \n
 *		- GUI access \n
 *		- Runtime query
 */
class CORE_EXPORT PluginBase
{
public:
	/// Constructor
	PluginBase();
	/// Destructor
	virtual ~PluginBase();

	/**	@brief	Start the plugin
	 *	@param	p	An optional pointer to a plugin specific object
	 *	@return	True on success, false otherwise
	 *
	 *	@details
	 *	A call to this method has to start the plugin. The actual behaviour
	 *	of this method depends on the particular purpose of the subclass and
	 *	may for example include GUI creation, allocation of resources or 
	 *	spawning of threads. The optional parameter may be used for plugin
	 *	specific purposes. This base class' implementation will simply perform
	 *	a check if the plugin is already started and return false in this case.
	 *	Otherwise, the internal flag indicating that the plugin is started is set. 
	 *	You should ALWAYS call the implementation of your plugin's superclass!
	 *	A typical starting routine is illustrated in the following code snippet
	 *	\code
	 * bool
	 * MyPlugin::StartPlugin(void *p)
	 * {
	 *  // Call the superclass implementation first
	 *  if ( !PluginBase::StartPlugin(p) )
	 *   return false;
	 *
	 *  // Plugin specific starting routine
	 *  ...
	 *
	 * }
	 *	\endcode
	 *	Note that this method is NOT thread safe! Calling threads have to lock
	 *	the plugin manually. Also, do not forget the void pointer in your method signature! \n
	 *	\sa StopPlugin() \sa Started()
	 */
	virtual bool StartPlugin(void *p=0);

	/**	@brief	Stop the plugin
	 *	@return	True on sucess, false otherwise
	 *
	 *	@details
	 *	A call to this method has to stop the plugin. Stopping a plugin
	 *	does not necessarily mean to release all resources associated to this
	 *	plugin (this is eventually the task of the destructor) but a call to
	 *	this method should set the state of the plugin in a way such that it
	 *	can be started again using the StartPlugin() method. This base class'
	 *	implementation will simply unset the internal flag indicating that the
	 *	plugin was started. You should ALWAYS call the implementation of your
	 *	plugin's superclass.\n
	 *	Note that this method is NOT thread safe! Calling threads have to lock
	 *	the plugin manually.
	 *	\sa StartPlugin() \sa Started()
	 */
	virtual bool StopPlugin();

	/**	@brief	Was the plugin started
	 *	@return	true if it was started, false otherwise
	 *
	 *	@brief
	 *	This method returns whether the plugin was started using the 
	 *	StartPlugin() method. If the plugin was started and stopped
	 *	this method returns false. In fact, this method simply returns the
	 *	internal flag indicating the state of the plugin.\n
	 *	Note that this method is NOT thread safe! Calling threads have to lock
	 *	the plugin manually.
	 */
	bool Started();

	/**	@brief	Get the plugin's GUI
	 *	@return	Pointer to the plugins GUI as a QWdiget
	 *
	 *	@details
	 *	Providing a GUI is a very important task for plugins but not mandatory.
	 *	This base class' implementation simply returns a NULL-pointer
	 *	subclasses may change this behaviour by overriding this method.
	 */
	virtual QWidget *GetPluginGUI();

	/**	@brief	Get the plugins runtime
	 *	@param	Runtime					The runtime of the plugin in ms (returned value)
	 *	@param	RuntimeStdDeviation		Optional, the standard deviation of the runtime in ms (returned value)
	 *
	 *	@details
	 *	This method should return the runtime of the plugin in ms and, optionally the 
	 *	runtimes standard deviation if the runtime is averaged over several values.
	 *	The runtime of a plugin is quite abstract (especially within this base class) 
	 *	as there is no "single method where the plugins work has to be done" that is 
	 *	common to all types of plugins. Different plugin types usually have a different 
	 *	envoking hierarchy, their runtime may vary extremly and has to be averaged over 
	 *	several invocation cycles, etc. Hence, the task of computing or evaluating 
	 *	the correct runtime is delegated to subclasses. As runtime evaluation is not vital 
	 *	but rather a "nice to have feature" this base class' does not declare an 
	 *	abstract interface (i.e. a pure virtual method) but provides an implementation that 
	 *	returns a negative runtime indicating that runtime computation is not supported for 
	 *	the particular plugin (equivalent to the runtime's standard deviation). 
	 *	However, subclasses should REALLY provide a runtime computation either by overriding
	 *	the GetRuntime() method or storing the runtime in the class member that is returned
	 *	by this base class (m_Runtime). Anyway, plugins have to stick to the convention 
	 *	of returning a negative value if runtime computation/evaluation is not supported. \n
	 *	Calling this method is thread safe as long as subclasses modify the member
	 *	m_Runtime (these values are eventually returned by this method) in a thread safe manner 
	 *	through the LockPlugin() concept.
	 */
	virtual void GetRuntime(double *Runtime, double *RuntimeStdDeviation=0);


	/**	@brief	Lock the plugin
	 *	
	 *	@details
	 *	Will lock the plugin using a mutex. If the plugin is already locked the calling
	 *	thread will be blocked until the owning thread releases the mutex. Note that a 
	 *	"recursive" call from one thread will cause a dead lock.
	 *	\sa UnlockPlugin()
	 */
	void LockPlugin();

	/** @brief	Unlock the plugin
	 *	
	 *	@details
	 *	Will unlock the plugin. \n
	 *	\sa LockPlugin()
	 */
	void UnlockPlugin();

	/** @brief	Set a parameter
	 *	
	 *	@details
	 *	Will set a parameter.
	 */
	virtual void SetParameter(QString Name, QString Value);

protected:
	/// The runtime of the plugin and runtime standard deviation (in ms)
	double m_Runtime[2];

private:
	/// Flag that indicates if the plugin was started
	bool m_Started;
	/// Mutex used to lock the plugin
	QMutex m_Mutex;
};


} // end namespace ritk

Q_DECLARE_INTERFACE(ritk::PluginBase, "ritk.core.PluginBase/1.0")


#endif // PLUGINBASE_H__