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

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

#include "ritkCore.h"

#include "ritkThreadedEventProcessor.h"
#include "ritkPluginBase.h"
#include "ritkEvent.h"

#include "ritkTimer.h"

namespace ritk
{

/**	@ingroup	Core
 *	@class		ApplicationPlugin
 *	@author		Jakob Wasza
 *	@brief		Base class for all RITK application plugins
 *
 *	@details
 *	This class provides the basic interface and concepts for all RITK application plugins.
 *	An application plugin is a "stand-alone application" within the RITK frame work. In contrast
 *	to filter plugins that are active parts of the acquisition pipeline, application plugins 
 *	are located at the very tail of the acquisition pipeline and do not interact directly with the
 *	pipeline: they are only "feeded" with data and produce no output that is used by other plugins
 *	within the RITK framework. A typical example of an application plugin is a visualization plugin 
 *	that simply maps the range data to the screen. \n
 *	Application plugins run in their own thread parallel to other application plugins and have to
 *	provide an implementation of the ProcessEvent() method, the key concept for this class of
 *	plugins: This method will eventually be invoked if a certain event occurs (e.g. a new frame
 *	is available) from the plugins own thread context. This base class' implementation provides
 *	all necessary functionality to ensure the execution of this key method in the correct thread
 *	context through the usage of the EnqueueEvent() method that is called from the manager
 *	and enqueues the corresponding event to the plugins event queue (to be more precise: into
 *	the ThreadedProcessor's event queue). The ProcessEvent() method is then successively "feeded" with enqueued events. 
 *	It is important to know that the StopPluginEvent will NEVER be delegated to a sub class but is instead processed in 
 *	this base class: If this event occurs the remaining enqueued events in the plugins event queue 
 *	will be processed and the plugin stopped (a call to StopPlugin() will in fact enqueue the stop 
 *	event). \n
 *	It is very important that an application plugin is ALWAYS created from the main thread context. 
 *	The constructor of this base class wil perform a check and if this is not the case an exception is 
 *	thrown. \n
 *	Subclases should provide a GUI by overloading the GetPluginGUI() method and HAVE TO ensure that the 
 *	GUI is deleted within the subclass' destructor! \n
 *	Note that application plugins are not allowed to have more than one instance of a specific event 
 *	in their event queue. This is automatically enforced! \n
 *	Automatic runtime evaluation is NOT supported directly by this base class!
 *	
 *	@sa PluginBase
 *	@sa FilterPlugin
 *	@sa SourcePlugin
 *	@todo	Update description to match the ThreadedEventProcess superclass
 */
class CORE_EXPORT ApplicationPlugin : public ThreadedEventProcessor, public PluginBase, public TimerD
{
	Q_INTERFACES(ritk::ThreadedEventProcessor ritk::PluginBase)

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

	/**	@brief	Start the plugin
	 *	@param	p	Not used for application plugins
	 *	@return	true on success, false otherwise
	 *
	 *	@details
	 *	Will start the plugin. In particular this includes calling the Initialize() routine
	 *	from within in the callers thread context (allowing GUI operations if the caller
	 *	is the main thread) and spawning the plugins own thread. \n
	 *	If you try to start a plugin via its start() method inherited from QThread (which in
	 *	theory would be possible) you will receive an error message! \n
	 *	Note that this method is NOT thread safe! Calling threads have to lock
	 *	the plugin manually.
	 */
	virtual bool StartPlugin(void *p=0);

	/**	@brief	Stop the plugin
	 *
	 *	@details
	 *	Will stop the plugin. In particular this includes the termination of the plugins thread.
	 *	As the plugin might perform some work at the time when this method is called the actual
	 *	termination of the plugins thread may be delayed until the plugin finishes its current
	 *	job. Thus, a call to this method blocks the calling thread until the plugin really stops.\n
	 *	Note that this method is NOT thread safe! Calling threads have to lock
	 *	the plugin manually.
	 */
	virtual bool StopPlugin();


protected:
	/**	@brief	Initialize the plugin
	 *	
	 *	@details
	 *	This method is provided to allow the plugin to do some initialization before
	 *	startup. In contrast to do the initialization in the plugins constructor
	 *	this method is always called when the plugin is started via the StartPlugin()
	 *	method. Note that plugins can be (re)started several times during their lifetime!
	 */
	virtual void Initialize();


	/** @brief	Process an event
	 *	@param	Event	The event that occured
	 *	
	 *	@details
	 *	This method has to be implemented by all subclasses and is invoked from within the plugins own thread context. 
	 *	The method is the key concept for plugins as the actual work is done here. \n
	 *	To process a certain event you should use the events type() method which can be used to determine the actual type of the event. 
	 *	Knowing the type one can then dynamic downcast the event to match the indicated type. \n
	 *	A typical scenario is illustrated in the following code snippet (note that we can't use a C++ dynamic_cast as we're working with Qt smart pointers)
	 *	\code
	 * void
	 * MyPlugin::ProcessEvent(Event::Pointer Event)
	 * {
	 *   if ( Event->type() == NewFrameEvent::EventType )
	 *   {
	 *     // Cast the event
	 *     NewFrameEvent::Pointer NewFrameEvent = qSharedPointerDynamicCast<NewFrameEvent,Event>(Event);
	 *     if ( !NewFrameEvent )
	 *     {
	 *       LOG_DEB("Something went horribly wrong...");
	 *       return;
	 *     }
	 *
	 *     // Start plugin timer
	 *     Timer::StartTimer();
	 *
	 *     // Get the range image frame
	 *     NewFrameEvent::RImageConstPointer frame = NewFrameEvent->RImage;
	 *     // Process frame
	 *     ...
	 *
	 *     // Stop timer and update the superclass' member to enable proper runtime evaluation
	 *     Timer::StopTimer();
	 *     Timer::GetElapsedTime(&m_Runtime[0],&m_Runtime[1]);
	 *   }
	 *   else
	 *   {
	 *     // Intercept other events
	 *     ...
	 *   }
	 * }
	 *	\endcode
	 */
	virtual void ProcessEvent(Event::Pointer Event)=0;
};

} // end namespace ritk


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

#endif // APPLICATIONPLUGIN_H__