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

	Program:		Range Imaging Toolkit (RITK)
	Module:			ritkManager.h
	Version:		$Revision: 1763 $
	Date:			$Date: 2011-09-25 20:22:20 +0200 (Sun, 25 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 MANAGER_H
#define MANAGER_H

#include "ritkCore.h"

#include "ritkDebugManager.h"
#include "ritkThreadedWorker.h"
#include "ritkAcquisitionPipeline.h"
#include "ritkPluginManager.h"
#include "ritkApplicationPlugin.h"
#include "ritkFilterPlugin.h"
#include "ritkSourcePlugin.h"
#include "ritkImageTypePlugin.h"
#include "ritkRImageFilePlayer.h"

#include "ritkMainWindow.h"

#include "ritkQTextEditIODevice.h"

#include <QSplashScreen>
#include <QTimer>


namespace ritk
{

/**	@ingroup	Core
 *	@class		Manager
 *	@author		Sebastian Bauer / Jakob Wasza
 *	@brief		Class used for managing core components and plugins of the toolkit
 *
 *	@details
 *	The manager. This class provides functionality for managing plugins, the acquisition pipeline,
 *	and the GUI interface. Also provides a threaded worker.
 *	@todo	Needs a more detailed documentation ASAP! Especially on how plugins are managed!
 *	@todo	Check for old funcionality that is not used anymore and remove them.
 */
class CORE_EXPORT Manager : public QObject
{
	Q_OBJECT

public:
	/// Singleton access
	static Manager& GetInstance();

	/**	@brief	Initialize the manager
	 *
	 *	@details
	 *	A call to this method will initialize the manager
	 *
	 *	@todo more detailed description of the involved processes/procedures
	 */
	void Initialize();

	/** @brief	Register a plugin
	 *	@param	Plugin	The plugin
	 *	@param	Name	The name for this plugin
	 *	@return	True if the plugin is registered successfully, false otherwise
	 *
	 *	@details
	 *	This method will register a plugin. The type of the plugin
	 *	will be determined via a dynamic cast and the plugin inserted
	 *	into the corresponding list (SourcePlugin, FilterPlugin, ApplicationPlugin). \n
	 *	If the parameter is no valid plugin the method will return false.
	 */
	bool RegisterPlugin(PluginBase *Plugin, QString Name="");

	/**	@brief	Unregister a plugin
	 *	@param	Plugin	The plugin
	 *	@return	True if the plugin could be removed, false otherwise
	 *
	 *	@brief
	 *	This method will unregister (or remove) the given plugin.
	 */
	bool UnregisterPlugin(PluginBase *Plugin);

	/**	@brief	Dispatch an event to all registered application plugins 
	 *	@param	e	The event
	 *
	 *	@details
	 *	This method will dispatch the given event to all registered application plugins.
	 *	Among others, this provides a method for inter-plugin communication
	 *
	 *	@todo more detailed documentation
	 */
	void DispatchEvent(Event::Pointer e);

	/**	@brief	Get the acquisition pipeline 
	 *	@return	The acquisition pipeline
	 *
	 *	@details
	 *	Get the current acquisition pipeline. Use with care!
	 */
	AcquisitionPipeline *GetAcquisitionPipeline();

	/// Add a job for threaded execution
	void AddThreadedJob(ThreadedJob *Job);

	/// Get the main thread handle
	Qt::HANDLE GetMainThreadHandle();

signals:
	/// Emitted when the user wants to start a plugin and configure it with a given parameter hash
	void StartPluginAndConfigure(PluginManager::PluginStruct&, QHash<QString, QString>);
	/// Emitted when the user wants to stop a plugin
	void StopPlugin(PluginManager::PluginStruct&);
	///	Emitted when the user wants to shutdown
	void StopFilePlayer();

public slots:
	/// Show the plugin creator dialog. Is connected to the mainwindow's signal
	void ShowPluginCreatorDialog();
	/// Show the plugin manager dialog. Is connected to the mainwindow's signal
	void ShowPluginManagerDialog();
	/// Show the plugin config dialog. Is connected to the mainwindows's signal
	void ShowPluginConfigDialog();

	/**	@brief	Shut down the manager
	 *
	 *	@details
	 *	A call to this method will shut down the manager
	 *
	 *	@todo more detailed description of the involved processes/procedures
	 */
	void ShutDown();

protected slots:
	/// Connected to the available players.
	void SwitchPlayer(SourcePlugin *Player);

	/// Is connected to the players NewFrame(NewFrameEvent::Pointer) signal
	void NewFrame(NewFrameEvent::Pointer e);

	/// Close a plugin from the tab
	void ClosePlugin(int TabId, PluginManager::PluginTypes);

protected:
	/// Mutex used to lock the plugin lists
	QMutex m_PluginMutex;

	/**	@name	Application plugins */
	//@{
	/// Struct that encapsulates an application plugin and the tab index for its widget
	typedef struct
	{
		/// The actual plugin
		ApplicationPlugin *Plugin;
		/// The tab index for the plugin
		int TabIndex;
	} ApplicationPluginStruct;
	/// List of registered application plugins
	QList<ApplicationPluginStruct> m_ApplicationPlugins;
	//@}


	/**	@name	Filter plugins */
	//@{
	/// Struct that encapsulates a filter plugin and the tab index for its widget
	typedef struct
	{
		/// The actual plugin
		FilterPlugin *Plugin;
		/// Tab index for the plugin
		int TabIndex;
	} FilterPluginStruct;
	/// List of registered filter plugins
	QList<FilterPluginStruct> m_FilterPlugins;
	//@}

	/**	@name	Source plugins */
	//@{
	/// List of registered source plugins
	QList<SourcePlugin*> m_SourcePlugins;
	//@}

	/**	@name	FPS counter members */
	//@{
	long m_FrameCounter;
	itk::RealTimeClock::Pointer m_Clock;
	itk::RealTimeClock::TimeStampType m_TimeStamp1;
	itk::RealTimeClock::TimeStampType m_TimeStamp2;
	//@}

private:
	/// Constructor 
	Manager();
	/// Destructor
	~Manager();
	/// Prevent copy-construction
	Manager(const Manager&);
	/// Prevent assignment
	Manager& operator=(const Manager&);

		
private:
	/// Handle to the main thread
	Qt::HANDLE m_MainThreadHandle;

	/// The acquisition pipeline
	AcquisitionPipeline *m_AcquisitionPipeline;

	/// The data thread
	ThreadedWorker *m_ThreadedWorker;

	/// The main window
	MainWindow *m_MainWindow;

	/// The plugin creator
	PluginCreator *m_PluginCreator;

	/**	@name plugin manager  */
	//@{
	PluginManager *m_PluginManager;
	QDir m_PluginDir;
	QDir m_PluginConfigsDir;
	QStringList m_PluginsFileNames;
	//@}

	/**	 @name	QTextEditIODevice and TextStream to stream logs into the window */
	//@{
	QTextStream *m_LogTextStream;
	QTextEditIODevice *m_LogTextEditIODevice;
	//@}

	/**	@name	Plugin configuration */
	//@{
	/// ...
	QString m_PluginConfigFileName;
	/// ...
	void LoadPluginConfig();
	//@}

	/// The file player
	RImageFilePlayer * m_FilePlayer;

	/**	@name	Manage shutdown flags */
	//@{
	/// Flag that indicates whether the Manager has already been destroyed
	bool m_ValidityFlag;
	/// Mutex used to lock access to the validity flag
	QMutex m_ValidityFlagMutex;	
	//@}
};

} // end namespace ritk

#endif // MANAGER_H
