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

	Program:		Range Imaging Toolkit (RITK)
	Module:			ritkManager.cxx
	Version:		$Revision: 3115 $
	Date:			$Date: 2012-04-19 09:55:24 +0200 (Do, 19 Apr 2012) $

	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

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

#include "ritkManager.h"
#include "ritkPluginManagerDialog.h"
#include "ritkPluginCreatorDialog.h"
#include "ritkRImageIOManager.h"
#include "ritkRImageIO.h"

#include <QMessageBox>
#include <QFileDialog>
#include <QtXml/QDomDocument>
#include <QtXml/QXmlStreamReader>
#include <QPainter>
#include <QTime>

#include <QBitmap>
#include "ThirdParty/CustomSplashScreen.h"



namespace ritk
{


//----------------------------------------------------------------------------
Manager& Manager::GetInstance()
{
	static Manager Instance;
	return Instance;
}


//----------------------------------------------------------------------------
Manager::Manager()
{	
	// Safe handle to the main thread
	m_MainThreadHandle = QThread::currentThreadId();

	//PluginManager
	m_PluginDir = QApplication::applicationDirPath() + "/plugins";
	m_PluginConfigsDir = QApplication::applicationDirPath();
	m_PluginConfigsDir.cdUp();
	m_PluginConfigsDir.cdUp();
	m_PluginConfigsDir = m_PluginConfigsDir.absolutePath().append("/PluginConfigs");
	m_PluginManager = new PluginManager();

	
	// Initialize time stamps
	m_FrameCounter = 0;
	m_Clock = itk::RealTimeClock::New();
	m_TimeStamp1 = 0;
	m_TimeStamp1 = 0;

	m_ValidityFlag = true;

	m_LogTextEditIODevice = 0;
	m_LogTextStream = 0;

	m_CurrentSource = NULL;
}


//----------------------------------------------------------------------------
Manager::~Manager()
{
}


//----------------------------------------------------------------------------
Qt::HANDLE 
Manager::GetMainThreadHandle()
{
	return m_MainThreadHandle;
}


//----------------------------------------------------------------------------
MainWindow*
Manager::GetMainWindow()
{
	return m_MainWindow;
}


//----------------------------------------------------------------------------
void
Manager::Initialize(QWidget* parent)
{
	// Our splash screen ;)
	QPixmap splashImage(":/ritk/Resources/Splashscreen.png");
	QPixmap splashMask(":/ritk/Resources/SplashscreenMask.png");
	customSplashScreen SplashScreen(splashImage);
	if(!parent)
	{
		SplashScreen.setMessageRect(QRect(0, 174, 479, 20), Qt::AlignCenter);
		QFont splashFont;
		splashFont.setFamily("Arial");
		splashFont.setBold(true);
		splashFont.setPixelSize(9);
		splashFont.setStretch(125);
		
		SplashScreen.setFont(splashFont);
		SplashScreen.setMask(QBitmap(splashMask));
		SplashScreen.setWindowFlags(Qt::WindowStaysOnTopHint | Qt::SplashScreen);
		SplashScreen.show();
		SplashScreen.showStatusMessage(tr("Initializing..."));
	}
	// Create the main window
	m_MainWindow = new MainWindow();
	if(!parent)
	{
		m_MainWindow->showMaximized();
	}

	// Start working thread
	m_ThreadedWorker = new ThreadedWorker();
	m_ThreadedWorker->start();

	// Set the debug manager's output to the log window
	m_LogTextEditIODevice = new QTextEditIODevice(m_MainWindow->m_LogTextEdit, this);
	m_LogTextStream = new QTextStream(m_LogTextEditIODevice);
	DebugManager::GetInstance().SetOutputStream(m_LogTextStream);
	/*QFile *File = new QFile("D://Temp//LOG.txt");
	File->open(QIODevice::WriteOnly|QIODevice::Text);
	QTextStream *Text = new QTextStream(File);
	ritk::DebugManager::GetInstance().SetOutputStream(Text);*/
	LOG_DEB("Initializing manager...");

	// Create the acquisition pipeline, connect the new frame signal to ourself and start
	if(!parent)
		SplashScreen.showStatusMessage(tr("Starting acquisition pipeline..."));
	m_AcquisitionPipeline = new AcquisitionPipeline();
	connect(m_AcquisitionPipeline, SIGNAL(NewFrame(NewFrameEvent::Pointer)), this, SLOT(NewFrame(NewFrameEvent::Pointer)));
	m_AcquisitionPipeline->start();
	m_AcquisitionPipeline->setPriority(QThread::TimeCriticalPriority);

	// Register the very basic IO object, register and enable the file player
	if(!parent)
		SplashScreen.showStatusMessage(tr("Registering file player..."));
	RImageIOManager<RImageF2>::GetInstance().RegisterIOObject(RImageIOF2::New());
	m_FilePlayer = new RImageFilePlayer();
	RegisterPlugin(m_FilePlayer,tr("File"));
	m_MainWindow->menuPlayer_mode->actions()[0]->trigger();
	
	// Connect signals and slots
	connect(m_MainWindow,	SIGNAL(ShutDown()),																		this,				SLOT(ShutDown())																		);
	connect(m_MainWindow,	SIGNAL(ShowPluginManagerDialog()),														this,				SLOT(ShowPluginManagerDialog())															);	
	connect(m_MainWindow,	SIGNAL(ShowPluginCreatorDialog()),														this,				SLOT(ShowPluginCreatorDialog())															);	
	connect(m_MainWindow,	SIGNAL(ShowPluginConfigDialog()),														this,				SLOT(ShowPluginConfigDialog())															);	
	connect(this,			SIGNAL(StartPluginAndConfigure(PluginManager::PluginStruct&, QHash<QString, QString>)),	m_PluginManager,	SLOT(StartPluginAndConfigure(PluginManager::PluginStruct&, QHash<QString, QString>))	);
	connect(this,			SIGNAL(StopPlugin(PluginManager::PluginStruct&)),										m_PluginManager,	SLOT(StopPlugin(PluginManager::PluginStruct&))											);	
	connect(this,			SIGNAL(StopFilePlayer()),																m_FilePlayer,		SLOT(Stop()) 												);
	connect(m_MainWindow,	SIGNAL(ClosePlugin(int, PluginManager::PluginTypes)),									this,				SLOT(ClosePlugin(int, PluginManager::PluginTypes))										);
	

	// set default plugin configuration file
	if(!parent)
		SplashScreen.showStatusMessage(tr("Scanning available plugins..."));
	m_PluginConfigFileName = m_PluginConfigsDir.absolutePath().append("/default.xml");
	LoadPluginConfig();

	if(!parent)
	{
		// Finish the splash screen
		SplashScreen.finish(m_MainWindow);

		// Show the main window
		m_MainWindow->showMaximized();
		m_MainWindow->move(0,0);
	}
	else
	{	
		m_MainWindow->setParent(parent);
        QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
        sizePolicy.setHorizontalStretch(1);
        sizePolicy.setVerticalStretch(1);
        m_MainWindow->setSizePolicy(sizePolicy);
		m_MainWindow->move(0,0);
		//m_MainWindow->setSizePolicy(parent->sizePolicy());
		m_MainWindow->resize(1400,500);
		m_MainWindow->showMaximized();
	}
}


//----------------------------------------------------------------------------
void
Manager::ShutDown()
{
	// Lock
	{
		QMutexLocker locker(&m_ValidityFlagMutex);
		m_ValidityFlag = false;
	}

	if(m_FilePlayer->GetState() != RImageFilePlayer::ClosedState)
	{
		emit StopFilePlayer();
	}
	m_FilePlayer->StopPlugin();

	QTime DieTime = QTime::currentTime().addSecs(1);
	while( QTime::currentTime() < DieTime )
		QCoreApplication::processEvents(QEventLoop::AllEvents, 100);

	//// Stop all plugins. This will also unregister them
	m_PluginManager->UpdateAvailablePluginLoaders(m_PluginDir.path());
	QList<PluginManager::PluginStruct> &Plugins  = m_PluginManager->GetAvailablePluginLoaders();

	// The order for stopping the plugins is cricital, hence:
	// 1st: Stop the application plugins
	for ( int i = 0; i < Plugins.size(); i++ )
	{
		if ( Plugins[i].Started && Plugins[i].PluginType == PluginManager::Application)
			emit StopPlugin(Plugins[i]);
	}

	// 2nd: Stop the filter plugins
	for ( int i = 0; i < Plugins.size(); i++ )
	{
		if ( Plugins[i].Started && Plugins[i].PluginType == PluginManager::Filter)
			emit StopPlugin(Plugins[i]);
	}

	// Delete file player
	UnregisterPlugin(m_FilePlayer);
	delete m_FilePlayer;
	m_FilePlayer = NULL;

	// 3rd: Stop the source plugins
	for ( int i = 0; i < Plugins.size(); i++ )
	{
		if ( Plugins[i].Started && Plugins[i].PluginType == PluginManager::Source)
			emit StopPlugin(Plugins[i]);
	}

	// 4th: Stop the image type plugins
	for ( int i = 0; i < Plugins.size(); i++ )
	{
		if ( Plugins[i].Started && Plugins[i].PluginType == PluginManager::ImageType)
			emit StopPlugin(Plugins[i]);
	}

	// Shutdown and delete the threaded worker
	m_ThreadedWorker->Shutdown();
	delete m_ThreadedWorker;

	// Delete the plugin manager.
	delete m_PluginManager;
	m_PluginManager = NULL;

	// Delete acquisition pipeline
	m_AcquisitionPipeline->Shutdown();
	delete m_AcquisitionPipeline;
	m_AcquisitionPipeline = NULL;

	// Delete the log
	if ( m_LogTextStream )
		delete m_LogTextStream;
	if ( m_LogTextEditIODevice )
		delete m_LogTextEditIODevice;
	DebugManager::GetInstance().SetOutputStream(NULL);

	// Delete the main window
	delete m_MainWindow;
	m_MainWindow = NULL;
	
}



//----------------------------------------------------------------------------
void
Manager::ShowPluginConfigDialog()
{
	m_PluginConfigFileName = QFileDialog::getOpenFileName(NULL, tr("Load Plugin Configuration"), m_PluginConfigsDir.absolutePath(),"*.xml");

	if(m_PluginConfigFileName.isEmpty()) return;

	// Lock
	{
		QMutexLocker locker(&m_ValidityFlagMutex);
		m_ValidityFlag = false;
	}

	if(m_FilePlayer->GetState() != RImageFilePlayer::ClosedState)
		emit StopFilePlayer();

	//// Stop all plugins. This will also unregister them
	m_PluginManager->UpdateAvailablePluginLoaders(m_PluginDir.path());
	QList<PluginManager::PluginStruct> &Plugins  = m_PluginManager->GetAvailablePluginLoaders();

	// The order for stopping the plugins is cricital, hence:
	// 1st: Stop the application plugins
	for ( int i = 0; i < Plugins.size(); i++ )
	{
		if ( Plugins[i].Started && Plugins[i].PluginType == PluginManager::Application)
			emit StopPlugin(Plugins[i]);
	}
	// 2nd: Stop the filter plugins
	for ( int i = 0; i < Plugins.size(); i++ )
	{
		if ( Plugins[i].Started && Plugins[i].PluginType == PluginManager::Filter)
			emit StopPlugin(Plugins[i]);
	}

	// Delete file player
	UnregisterPlugin(m_FilePlayer);
	delete m_FilePlayer;
	m_FilePlayer = NULL;

	// 3rd: Stop the source plugins
	for ( int i = 0; i < Plugins.size(); i++ )
	{
		if ( Plugins[i].Started && Plugins[i].PluginType == PluginManager::Source)
			emit StopPlugin(Plugins[i]);
	}

	// 4th: Stop the image type plugins
	for ( int i = 0; i < Plugins.size(); i++ )
	{
		if ( Plugins[i].Started && Plugins[i].PluginType == PluginManager::ImageType)
			emit StopPlugin(Plugins[i]);
	}

	delete m_AcquisitionPipeline;
	m_AcquisitionPipeline = NULL;

	m_AcquisitionPipeline = new AcquisitionPipeline();
	connect(m_AcquisitionPipeline, SIGNAL(NewFrame()), this, SLOT(NewFrame()));
	m_AcquisitionPipeline->start();
	m_AcquisitionPipeline->setPriority(QThread::TimeCriticalPriority);

	LoadPluginConfig();
}


//----------------------------------------------------------------------------
void
Manager::LoadPluginConfig()
{
	if(!m_FilePlayer)
	{
		m_FilePlayer = new RImageFilePlayer();
		RegisterPlugin(m_FilePlayer,tr("File"));
		m_MainWindow->menuPlayer_mode->actions()[0]->trigger();
	}

	QString DefaultPlayer = tr("FilePlayer");

	std::vector<QString> PluginList;
	std::vector<QHash<QString, QString> > ParameterHash;
	
	// Open database
	QFile* file = new QFile(m_PluginConfigFileName);
	if (!file->open(QIODevice::ReadOnly | QIODevice::Text)) 
	{
		QMessageBox::critical(NULL, "Manager::LoadPluginConfig()", "Could not open *.xml", QMessageBox::Ok);
		return;
	}

	// Error handling
    QString errorStr;
    int errorLine;
    int errorColumn;

    QDomDocument doc;
    if (!doc.setContent(file, false, &errorStr, &errorLine,
                        &errorColumn)) {
        std::cerr << "Error: Parse error at line " << errorLine << ", "
                  << "column " << errorColumn << ": "
                  << qPrintable(errorStr) << std::endl;
    }

    QDomElement Root = doc.documentElement();
    if (Root.tagName() != "RITKPluginConfig") {
        std::cerr << "Error: Not a RITKPluginConfig file" << std::endl;
		return;
    }

	// Read
	QDomNode PluginNode = Root.firstChild();
    while (!PluginNode.isNull()) {
        if (PluginNode.toElement().tagName() == "plugin")
		{
			QString PluginName = PluginNode.toElement().attribute("name");
			PluginList.push_back(PluginName);

			QHash<QString, QString> CurrentParameterHash;

			QDomNode ParameterNode = PluginNode.firstChild();
			while (!ParameterNode.isNull()) {
				if (ParameterNode.toElement().tagName() == "parameter") 
				{
					CurrentParameterHash.insert(ParameterNode.toElement().attribute("name"), ParameterNode.toElement().text());
				} 
				ParameterNode = ParameterNode.nextSibling();
			}

			ParameterHash.push_back(CurrentParameterHash);
		}
		else if ( PluginNode.toElement().tagName() == "default_player" )
		{
			DefaultPlayer = PluginNode.toElement().attribute("name");
		}
        PluginNode = PluginNode.nextSibling();
    }


	m_PluginManager->UpdateAvailablePluginLoaders(m_PluginDir.path());

	QList<PluginManager::PluginStruct> *m_PluginList = &m_PluginManager->GetAvailablePluginLoaders();
	QList<PluginManager::PluginStruct> &Plugins = *m_PluginList;	

	for( unsigned int i = 0; i < PluginList.size(); i++ )
	{
		//std::cout << "Attempting to start plugin <" << PluginList[i].toStdString() << ">" << std::endl;
		// Find the correct plugin
		for ( int j = 0; j < Plugins.size(); j++ )
		{
			//std::cout << "	Plugin #" << j << Plugins[j].PluginName.toStdString() << std::endl;
			if ( Plugins[j].PluginName == PluginList[i] )
			{
				try
				{
					//std::cout << Plugins[j].PluginName.toStdString() << std::endl;
					emit StartPluginAndConfigure(Plugins[j], ParameterHash[i]);
				}
				catch ( itk::ExceptionObject &e )
				{
					LOG_DEB(e);
				}
			}			
		}
	}

	// Special handling for the file source plugin (not a member of the PluginList)
	for( unsigned int i = 0; i < PluginList.size(); i++ )
	{
		if ( PluginList[i] == "FilePlayer" )
		{
			QHashIterator<QString, QString> itHash(ParameterHash[i]);
			while (itHash.hasNext()) {
				itHash.next();
				m_FilePlayer->SetParameter(itHash.key(),itHash.value());										
			}		
		}
	}

	// Activate the default player
	for ( int i = 0; i < Plugins.size(); i++ )
	{
		if (Plugins[i].PluginName == DefaultPlayer )
		{
			SourcePlugin *tmp = dynamic_cast<SourcePlugin*>(Plugins[i].InstancePointer);
			if ( tmp )
			{
				SwitchPlayer(tmp);
			}
			else
				LOG_DEB("Invalid default player!");
		}
	}

	// Lock
	{
		QMutexLocker locker(&m_ValidityFlagMutex);
		m_ValidityFlag = true;
	}
}


//----------------------------------------------------------------------------
void 
Manager::AddThreadedJob(ThreadedJob  *Job)
{
	//LOG_DEB("Adding data process " << Job);
	if ( m_ThreadedWorker )
		m_ThreadedWorker->AddNewJob(Job);
	else
		LOG_DEB("Threaded worker does not exist anymore!");
}


//----------------------------------------------------------------------------
AcquisitionPipeline*
Manager::GetAcquisitionPipeline()
{
	return m_AcquisitionPipeline;
}


//----------------------------------------------------------------------------
bool
Manager::RegisterPlugin(PluginBase *Plugin, QString Name)
{
	QMutexLocker locker(&m_PluginMutex);

	// Image type plugin
	ImageTypePlugin *ImageType = dynamic_cast<ImageTypePlugin*>(Plugin);
	if ( ImageType )
	{
		// Starting the plugin should register the provided IO object
		ImageType->StartPlugin();
		return true;
	}

	// Source plugin
	SourcePlugin *Player = dynamic_cast<SourcePlugin*>(Plugin);
	if ( Player )
	{
		// Append the plugin to the internal list
		m_SourcePlugins.append(Player);

		// Connect the players' start signal to ourself
		connect(Player, SIGNAL(StartSignal(SourcePlugin*)), this, SLOT(SwitchPlayer(SourcePlugin*)));
		
		// Add menu entry
		m_MainWindow->AddPlayer(Player, Name);

		// Yes, we found a valid plugin and we can return true
		return true;
	}

	// Filter plugin
	FilterPlugin *Filter= dynamic_cast<FilterPlugin*>(Plugin);
	if ( Filter )
	{
		// Call the starting routine
		Filter->StartPlugin(m_AcquisitionPipeline);

		// The filter struct
		FilterPluginStruct Struct;
		Struct.Plugin = Filter;
		Struct.TabIndex = -1;

		// If the filter provides a GUI set the corresponding widget
		if ( Filter->GetPluginGUI() )
		{
			int TabID = m_MainWindow->m_FilterTabs->addTab(Filter->GetPluginGUI(),Name);
			Struct.TabIndex = TabID;
		}

		// Append the filter to the internal list
		m_FilterPlugins.append(Struct);

		// Yes, we found a valid plugin and we can return true
		return true;
	}

	// Application plugin
	ApplicationPlugin *Application = dynamic_cast<ApplicationPlugin*>(Plugin);
	if ( Application )
	{
		// Start the plugin
		Application->StartPlugin();

		// The application struct
		ApplicationPluginStruct Struct;
		Struct.Plugin = Application;
		Struct.TabIndex = -1;

		// If the filter provides a GUI set the corresponding widget
		if ( Application->GetPluginGUI() )
		{
			int TabID  = m_MainWindow->m_PluginTabs->addTab(Application->GetPluginGUI(),Name);
			Struct.TabIndex = TabID;
		}

		// Append the plugin to the internal list
		m_ApplicationPlugins.append(Struct);
		
		// Yes, we found a valid plugin and we can return true
		return true;
	}

	// We can not handle this plugin
	return false;
}


//----------------------------------------------------------------------------
bool
Manager::UnregisterPlugin(PluginBase *Plugin)
{
	QMutexLocker locker(&m_PluginMutex);
	bool Valid = false;

	// Image type plugin
	ImageTypePlugin *ImageType = dynamic_cast<ImageTypePlugin*>(Plugin);
	if ( ImageType )
	{
		// The StopPlugin() method will automatically unregister the IO object
		ImageType->StopPlugin();
		Valid = true;
	}

	// Source plugin
	SourcePlugin *Player = dynamic_cast<SourcePlugin*>(Plugin);
	if ( Player )
	{
		// Loop
		typedef QList<SourcePlugin*>::Iterator IteratorType;
		for ( IteratorType it = m_SourcePlugins.begin(); it != m_SourcePlugins.end(); it++ )
		{
			if ( (*it) == Player )
			{
				m_MainWindow->RemovePlayer((*it));
				m_SourcePlugins.erase(it);
				(*it)->StopPlugin();
				if ( (*it)->GetPluginGUI() )
					(*it)->GetPluginGUI()->hide();
				Valid = true;
				break;
			}
		}
	}

	// Filter plugin
	FilterPlugin *Filter= dynamic_cast<FilterPlugin*>(Plugin);
	if ( Filter )
	{
		int RemovedTabIndex = -1;
		// Loop
		typedef QList<FilterPluginStruct>::Iterator IteratorType;
		for ( IteratorType it = m_FilterPlugins.begin(); it != m_FilterPlugins.end(); it++ )
		{			
			if ( (*it).Plugin == Plugin )
			{				
				RemovedTabIndex = (*it).TabIndex;
				m_MainWindow->m_FilterTabs->removeTab((*it).TabIndex);
				m_FilterPlugins.erase(it);
				// StopPlugin automatically removes plugin from the acquisition pipeline
				Filter->StopPlugin();
				Valid = true;
				break;
			}

		}
		// Refresh the tab indices of the remaining filter tabs
		for ( IteratorType it = m_FilterPlugins.begin(); it != m_FilterPlugins.end(); it++ )
		{
			if(RemovedTabIndex >= 0 && (*it).TabIndex > RemovedTabIndex)
			{
				(*it).TabIndex--;
			}
		}
	}

	// Application plugin
	ApplicationPlugin *Application = dynamic_cast<ApplicationPlugin*>(Plugin);
	if ( Application )
	{
		int RemovedTabIndex = -1;
		// Loop
		typedef QList<ApplicationPluginStruct>::Iterator IteratorType;
		for ( IteratorType it = m_ApplicationPlugins.begin(); it != m_ApplicationPlugins.end(); it++ )
		{
			if ( (*it).Plugin == Plugin )
			{
				RemovedTabIndex = (*it).TabIndex;
				m_MainWindow->m_PluginTabs->removeTab((*it).TabIndex);
				m_ApplicationPlugins.erase(it);
				Application->StopPlugin();
				Valid = true;
				break;
			}
		}
		// Refresh the tab indices of the remaining application tabs
		for ( IteratorType it = m_ApplicationPlugins.begin(); it != m_ApplicationPlugins.end(); it++ )
		{
			if(RemovedTabIndex >= 0 && (*it).TabIndex > RemovedTabIndex)
			{
				(*it).TabIndex--;
			}
		}
	}
	return Valid;
}


//----------------------------------------------------------------------------
void 
Manager::DispatchEvent(Event::Pointer e)
{
	QMutexLocker locker(&m_PluginMutex);
	for ( int i = 0; i < m_ApplicationPlugins.size(); i++ )
	{		
		if ( m_ApplicationPlugins[i].Plugin->Started() )
			m_ApplicationPlugins[i].Plugin->EnqueueEvent(e);
	}
}


//----------------------------------------------------------------------------
void 
Manager::NewFrame(NewFrameEvent::Pointer e)
{
	// Return if Manager does no more exist	
	/*{
		QMutexLocker locker(&m_ValidityFlagMutex);
		if(!m_ValidityFlag)
			return;
	}*/

	// Dispatch the NewFrameEvent
	this->DispatchEvent(e);
	
	ritk::NewFrameEvent::RImageConstPointer CurrentFrameP = e->RImage;
	emit NewFrame(CurrentFrameP);

	// Update counter
	m_FrameCounter++;

	if ( m_TimeStamp1 == 0 )
		m_TimeStamp1 = m_Clock->GetTimeStamp();	

	// Runtime
	if ( m_FrameCounter%200 == 0 )
	{
		double d1 = 0;
		double d2 = 0;
		std::cout << "Runtimes:" << std::endl;
		std::cout << "=========" << std::endl;
		std::cout << "FrameCounter=" << m_FrameCounter << std::endl;
		std::cout << "Players:" << std::endl;
		for ( int i = 0; i < m_SourcePlugins.size(); i++ )
		{
			m_SourcePlugins[i]->GetRuntime(&d1,&d2);
			std::cout << "	#" << i << ": " << d1 << "ms (" << d2 << ")" << std::endl;
		}
		std::cout << "Filters: " << std::endl;
		for ( int i = 0; i < m_FilterPlugins.size(); i++ )
		{
			m_FilterPlugins[i].Plugin->GetRuntime(&d1,&d2);
			std::cout << "	#" << i << ": " << d1 << "ms (" << d2 << ")" << std::endl;
		}
		std::cout << "Applications:" << std::endl;
		for ( int i = 0; i < m_ApplicationPlugins.size(); i++ )
		{
			m_ApplicationPlugins[i].Plugin->GetRuntime(&d1,&d2);
			std::cout << "	#" << i << ": " << d1 << "ms (" << d2 << ")" << std::endl;
		}
		m_AcquisitionPipeline->GetElapsedTime(&d1,&d2);
		std::cout << "Overall: " << d1 << "ms (" << d2 << ")" << std::endl;
		std::cout << std::endl << std::endl << std::endl;

		// Reset counter 
		m_FrameCounter = 0;
	}

	// GUI runtime
	int NumFrames = 50;
	if ( m_FrameCounter%NumFrames == 0 )
	{
		m_TimeStamp2 = m_Clock->GetTimeStamp();
		double fps = NumFrames/(m_TimeStamp2 - m_TimeStamp1);
		m_TimeStamp1 = m_TimeStamp2;	
		std::stringstream ss;
		ss.precision(3);
		ss << fps << " FPS";
		m_MainWindow->statusBar()->showMessage(tr(ss.str().c_str()),5000);
	}
}


//----------------------------------------------------------------------------
void 
Manager::SwitchPlayer(SourcePlugin *Player)
{
	// First, stop the active player
	typedef QList<SourcePlugin*>::Iterator IteratorType;
	for ( IteratorType it = m_SourcePlugins.begin(); it != m_SourcePlugins.end(); it++ )
	{
		if ( (*it)->Started() )
		{
			// Lock the player
			(*it)->LockPlugin();

			// Hide GUI
			if ( (*it)->GetPluginGUI() )
			{
				(*it)->GetPluginGUI()->hide();
				m_MainWindow->m_PlayerFrame->layout()->removeWidget((*it)->GetPluginGUI());
			}

			/// Disconnect signal
			m_AcquisitionPipeline->Lock();
			disconnect(m_AcquisitionPipeline, SIGNAL(NewFrame()), (*it), SLOT(NewFrame()));
			m_AcquisitionPipeline->Unlock();
			(*it)->StopPlugin();

			// Unlock the player
			(*it)->UnlockPlugin();
		}
	}

	// Start the new player
	Player->StartPlugin(m_AcquisitionPipeline);

	// Sanity check
	if ( !Player->Started() )
		return;

	// If the player provides a GUI set the corresponding widget
	if ( Player->GetPluginGUI() )
	{
		m_MainWindow->m_PlayerFrame->layout()->addWidget(Player->GetPluginGUI());
		Player->GetPluginGUI()->show();
	}

	// Finally connect the pipeline's new frame signal to the player
	m_AcquisitionPipeline->Lock();
	connect(m_AcquisitionPipeline, SIGNAL(NewFrame()), Player, SLOT(NewFrame()));
	m_AcquisitionPipeline->Unlock();

	// Update our member
	m_CurrentSource = Player;
}


//----------------------------------------------------------------------------
SourcePlugin*
Manager::GetCurrentSource()
{
	return m_CurrentSource;
}


//----------------------------------------------------------------------------
void 
Manager::ShowPluginManagerDialog()
{
	m_PluginManager->UpdateAvailablePluginLoaders(m_PluginDir.path());

	PluginManagerDialog *dialog = new PluginManagerDialog(m_MainWindow);
	dialog->PopulatePluginInformation(m_PluginManager->GetPluginDir(),&m_PluginManager->GetAvailablePluginLoaders());

	connect(dialog, SIGNAL(StartPlugin(PluginManager::PluginStruct&)), m_PluginManager, SLOT(StartPlugin(PluginManager::PluginStruct&)));
	connect(dialog, SIGNAL(StopPlugin(PluginManager::PluginStruct&)), m_PluginManager, SLOT(StopPlugin(PluginManager::PluginStruct&)));
	connect(m_PluginManager, SIGNAL(PluginStatusChanged(PluginManager::PluginStruct&)), dialog, SLOT(PluginStatusChanged(PluginManager::PluginStruct&)));

	dialog->exec();

	disconnect(dialog, SIGNAL(StartPlugin(PluginManager::PluginStruct&)), m_PluginManager, SLOT(StartPlugin(PluginManager::PluginStruct&)));
	disconnect(dialog, SIGNAL(StopPlugin(PluginManager::PluginStruct&)), m_PluginManager, SLOT(StopPlugin(PluginManager::PluginStruct&)));
	disconnect(m_PluginManager, SIGNAL(PluginStatusChanged(PluginManager::PluginStruct&)), dialog, SLOT(PluginStatusChanged(PluginManager::PluginStruct&)));

	
	delete dialog;
}


//----------------------------------------------------------------------------
void 
Manager::ClosePlugin(int TabId, PluginManager::PluginTypes PluginType)
{
	m_PluginManager->UpdateAvailablePluginLoaders(m_PluginDir.path());
	QList<PluginManager::PluginStruct> &Plugins  = m_PluginManager->GetAvailablePluginLoaders();

	if(PluginType == PluginManager::Filter)
	{				
		for ( int i = 0; i < m_FilterPlugins.size(); i++ )
		{		
			if(m_FilterPlugins[i].TabIndex == TabId)			
			{
				for ( int j = 0; j < Plugins.size(); j++ )
				{
					if ( Plugins[j].Started && Plugins[j].InstancePointer == m_FilterPlugins[i].Plugin)
					{
						emit StopPlugin(Plugins[j]);
						return;
					}
				}
			}
		}
	}

	else if(PluginType == PluginManager::Application)
	{		
		for ( int i = 0; i < m_ApplicationPlugins.size(); i++ )
		{			
			if(m_ApplicationPlugins[i].TabIndex == TabId)
			{
				for ( int j = 0; j < Plugins.size(); j++ )
				{
					if ( Plugins[j].Started && Plugins[j].InstancePointer == m_ApplicationPlugins[i].Plugin)
					{
						emit StopPlugin(Plugins[j]);
						return;
					}
				}
			}
		}
	}
}



//----------------------------------------------------------------------------
void 
Manager::ShowPluginCreatorDialog()
{
	PluginCreatorDialog *dialog = new PluginCreatorDialog(m_MainWindow);

	dialog->exec();
	
	delete dialog;
}

} // end namespace ritk


