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

	Program:		Range Imaging Toolkit (RITK)
	Module:			ritkThreadedEventProcessor.h
	Version:		$Revision: 1761 $
	Date:			$Date: 2011-09-23 17:25:41 +0200 (Fri, 23 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 THREADEDEVENTPROCESSOR_H__
#define THREADEDEVENTPROCESSOR_H__

#include "ritkCore.h"
#include "ritkEvent.h"

#include <QThread>
#include <QQueue>
#include <QWaitCondition>
#include <QMutex>

namespace ritk
{

/**	@ingroup	Core
 *	@class		ThreadedEventProcessor
 *	@author		Jakob Wasza
 *	@brief		Event processing in an individual thread
 *
 *	@details
 *	Assigning certain tasks to individual threads is one of the key concepts of the RITK core module. 
 *	This base class provides the very basic interface and methods for processing event/tasks in a separate thread. 
 *	A processing thread runs in an endless loop passively waiting for events to be enqueued. 
 *	Enqueued events are processed sequentially by delegating them to the ProcessEvent() method that all subclasses must provide. 
 *	By enqueuing the StopEvent event, all previously enqueued events will be processed and the processor's endless loop 
 *	will be ultimatively terminated. However, the StopEvent will be delegated via the ProcessEvent() method to enable a proper shutdown 
 *	for subclasses. Subsequently enqueued events are ignored. \n
 *	Note that a ThreadedEventProcessor has to be explicitely started using the QThread::start() method.
 */
class CORE_EXPORT ThreadedEventProcessor : public QThread
{

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

	/**	@brief	Enqueue an event to be processed 
	 *	@param	Event				The event
	 *	@param	SingleInstance		Force a single instance of one event
	 *	@return	true if the event was sucessfully enqueued, false otherwise
	 *
	 *	@details
	 *	This method will enqueue an event to be processed. Note that this is a non-blocking (i.e. asynchronuous) call for the
	 *	calling thread as the actual event-processing is performed within the processor's thread context! Calling this method
	 *	will eventually invoke the ProcessEvent() method. \n
	 *	The SingleInstance flag is used to allow only one particular event instance enqueued. In case that the internal queue
	 *	already contains an event of the same type as the event that is to be enqueued false will be returned.
	 */
	bool EnqueueEvent(Event::Pointer Event, bool SingleInstance=true);

	/**	@brief	Shutdown the processor
	 *
	 *	@details
	 *	Calling this method will stop/shutdown the processor. Always call this method instead of relying on the destructor or
	 *	QThread-specific method as these won't allow a proper propagation of the StopEvent() to subclasses. Calling the Shutdown()
	 *	method will enqueue the ShutdownEvent();
	 */
	void Shutdown();

	/// Return the workers thread handle
	Qt::HANDLE GetThreadHandle();

protected:
	/**	@brief	Process an event
	 *	@param	Event	The event
	 *
	 *	@details
	 *	This method has to perform the actual event processing and has to be provided by all subclasses. It is up to a 
	 *	subclass' implementation to handle a certain event. However, all subclasses should handle the StopEvent in order
	 *	to enable a proper shutdown.
	 */
	virtual void ProcessEvent(Event::Pointer Event)=0;

	/// QT thread run method
    void run();

private:
	/// The thread handle
	Qt::HANDLE m_ThreadHandle;

	/// Holds the added data processes
	QQueue<Event::Pointer> m_Events;
	/// Used to halt the thread if no events to be processed are available
    QWaitCondition m_EventAdded;
	/// Mutex to synchronize the queue
    QMutex m_Mutex;

	/// Flag that indicates proper shutdown
	bool m_ShutdownFlag;
	/// Mutex used to synchronize the shutdown flag
	QMutex m_ShutdownFlagMutex;
};

} // ritk

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


#endif // THREADEDEVENTPROCESSOR_H__