/*********************************************************************************
* C++ Implementation: pluginmanager.cpp
* Description:
*                              
* Begin : tis jan 14 2003
* Author : Björn Sahlström <kbjorn@users.sourceforge.net> (C) 2003
* Copyright : See COPYING file that comes with this distribution
**********************************************************************************/

//////////////////////////////////////////////////////////////////////
// Qt specific include files
#include <qvbox.h>
#include <qpushbutton.h>
//////////////////////////////////////////////////////////////////////
// KDE specific include files
#include <kdialogbase.h>
#include <kwizard.h>
#include <ktrader.h>
#include <kmainwindow.h>
#include <kmessagebox.h>
#include <kapplication.h>
#include <kglobal.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kconfig.h>
#include <kconfigbase.h>
#include <kservice.h>
#include <kparts/componentfactory.h>
#include <kdebug.h>
//////////////////////////////////////////////////////////////////////
// System specific include files
//////////////////////////////////////////////////////////////////////
// Application specific include files
#include "pluginmanager.h"
#include "kbearmainwindow.h"
#include "kbeartoplevel.h"
#include "kbearcore.h"
#include "api.h"
#include "kbearplugin.h"
#include "pluginselectwidget.h"


#include "pluginmanager.moc"

using namespace KBear;
//-----------------------------------------------
PluginManager* PluginManager::s_instance = 0L;
//-----------------------------------------------
PluginManager::PluginManager()
	:	KBearPluginManagerInterface( 0L )
{
	connect( API::getInstance()->core(), SIGNAL( configWidget( KDialogBase* ) ),
           this, SLOT( slotConfigWidget( KDialogBase* ) ) );
	connect( API::getInstance()->core(), SIGNAL( configWidget( KWizard* ) ),
           this, SLOT( slotConfigWidget( KWizard* ) ) );
	connect( API::getInstance()->core(), SIGNAL( shuttingDown() ),
           this, SLOT( slotUnloadPlugins() ) );
}
//-----------------------------------------------
PluginManager::~PluginManager() {
}
//-----------------------------------------------
PluginManager* PluginManager::getInstance() {
	if( ! s_instance )
		s_instance = new PluginManager();
	return s_instance;
}
//-----------------------------------------------
void PluginManager::loadPlugins( bool initializePlugins ) {
	KTrader::OfferList offers = KTrader::self()->query( QString::fromLatin1( "KBear/Plugin" ) );
	KConfig *config = kapp->config();
	KConfigGroupSaver cs( config, config->group() );
	for (KTrader::OfferList::ConstIterator it = offers.begin(); it != offers.end(); ++it) {
		config->setGroup("Plugins");
    
		QString name = (*it)->name();
    
		// Unload it if it is marked as ignored and loaded
		if( ! config->readBoolEntry( name, true) ) {
			KBearPlugin* plugin = m_plugins[name];
			if( plugin ) {
				QString warning = plugin->unloadWarning();
				if( warning.isEmpty() || queryUnload( warning ) ) {
					removePlugin( plugin );
					m_plugins.remove( name );
					plugin->deleteLater();
				}
				else
					config->writeEntry( name, true);
			}
			continue;
		}

		// Check if it is already loaded
		if( m_plugins[ name ] != 0 )
			continue;
      
		emit loadingPlugin( i18n("Loading plugin: %1" ).arg( (*it)->genericName() ) );
		kapp->processEvents();

		KBearPlugin* plugin = loadPlugin( *it );
		if( plugin ) {
			m_plugins.insert( name, plugin );
			addPlugin( plugin );
			if( initializePlugins )
				plugin->slotInit();

			emit pluginLoaded( plugin );
		}
	}
}
//-----------------------------------------------
KBearPlugin* PluginManager::loadPlugin( const KService::Ptr &service ) {
	 return KParts::ComponentFactory
        ::createInstanceFromService<KBearPlugin>( service, API::getInstance() );
}
//-----------------------------------------------
void PluginManager::slotLoadPlugins() {
	loadPlugins( true );
}
//-----------------------------------------------
void PluginManager::slotUnloadPlugins() {
	for( QDictIterator<KBearPlugin> it( m_plugins ); !it.isEmpty(); ) {
		KBearPlugin* plugin = it.current();
		m_plugins.remove( it.currentKey() );
		removePlugin( plugin );

		delete plugin;
	}
}
//-----------------------------------------------
void PluginManager::slotConfigWidget( KDialogBase* dlg ) {
	QVBox* vbox = dlg->addVBoxPage( i18n("Plugins"), QString::null,
									KGlobal::iconLoader()->loadIcon("connect_no", KIcon::NoGroup, KIcon::SizeMedium) );
	PluginSelectWidget *w = new PluginSelectWidget( vbox, "PluginSelectWidget" );
	connect( dlg, SIGNAL( okClicked() ), w, SLOT( slotAccept() ) );
	connect( dlg, SIGNAL( destroyed() ), this, SLOT( slotLoadPlugins() ) );
}
//-----------------------------------------------
void PluginManager::slotConfigWidget( KWizard* wiz ) {
	PluginSelectWidget* w = new PluginSelectWidget( wiz, "PluginSelectWidget" );
	wiz->addPage( w, i18n("Plugins") );
	connect( wiz->finishButton(), SIGNAL( clicked() ), w, SLOT( slotAccept() ) );
	connect( w, SIGNAL( accepted() ), this, SLOT( slotLoadPlugins() ) );
}
//-----------------------------------------------
void PluginManager::addPlugin( KBearPlugin* plugin ) {
	API::getInstance()->mainWindow()->mainWindow()->guiFactory()->addClient( plugin );
}
//-----------------------------------------------
void PluginManager::removePlugin( KBearPlugin* plugin ) {
	API::getInstance()->mainWindow()->mainWindow()->guiFactory()->removeClient( plugin );
	emit pluginUnloaded( plugin );
}
//-----------------------------------------------
bool PluginManager::queryUnload( const QString& text ) {
	int value = KMessageBox::warningContinueCancel( API::getInstance()->mainWindow()->mainWindow(), text );
	return ( value == KMessageBox::Continue );
}
//-----------------------------------------------
