/***************************************************************************
   Copyright (C) 2007 by Matthias Lechner <matthias@lmme.de>

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   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 the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the
   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
 ***************************************************************************/

#include "serviceloader.h"

#include <KService>
#include <KServiceTypeTrader>

#include <QtCore/QMutex>
#include <QtCore/QHash>

#include <libkmobiletools/coreservice.h>
#include <libkmobiletools/deviceloader.h>
#include <libkmobiletools/enginexp.h>

#include <kdebug.h>

namespace KMobileTools {

class ServiceLoaderInstance {
public:
    ServiceLoader m_uniqueInstance;
};

class ServiceLoaderPrivate {
public:
    QHash<QString,KMobileTools::CoreService*> m_loadedServices;
};

K_GLOBAL_STATIC(ServiceLoaderInstance, serviceLoaderInstance)

ServiceLoader::ServiceLoader()
: QObject( 0 ), d( new ServiceLoaderPrivate )
{
}

ServiceLoader* ServiceLoader::instance() {
    // instance is automatically created
    return &serviceLoaderInstance->m_uniqueInstance;
}


ServiceLoader::~ServiceLoader()
{
    // unloading all services
    QHashIterator<QString,KMobileTools::CoreService*> i( d->m_loadedServices );
    while( i.hasNext() ) {
        i.next();
        unloadServices( i.key() );
    }

    delete d;
}

void ServiceLoader::loadServices( const QString& deviceName ) {
    // services already loaded?
    if( d->m_loadedServices.contains( deviceName ) )
        return;

    // query the required service from KDE's services
    KService::List serviceOffers = KServiceTypeTrader::self()->query( "KMobileTools/CoreService" );

    // no services available at all?
    if( serviceOffers.empty() )
        return;

    // get engine for the device
    KMobileTools::EngineXP* engine = KMobileTools::DeviceLoader::instance()->engine( deviceName );
    if( !engine )
        return;

    // iterate over the services and look which one we can use
    QStringList deviceNameList;
    deviceNameList << deviceName;
    foreach( KService::Ptr coreService, serviceOffers ) {
        // get a reference to the service
        KPluginFactory *factory = KPluginLoader( *coreService ).factory();
        if( !factory )
            continue;
		QObject* serviceObject = factory->create<KMobileTools::CoreService>((QObject*)0, deviceNameList );
        if( !serviceObject )
            continue;

        KMobileTools::CoreService* service = qobject_cast<KMobileTools::CoreService*>( serviceObject );
        if( !service )
            continue;

        bool fulfillsRequirements = true;
        QStringList requirements = service->requires();
        foreach( const QString& requirement, requirements ) {
            if( !engine->implements( requirement ) ) {
                fulfillsRequirements = false;
                break;
            }
        }

        // service fulfills our requirements
        if( fulfillsRequirements ) {
            d->m_loadedServices.insert( deviceName, service );
            emit serviceLoaded( deviceName, service );
        } else
            delete service;
    }
}

void ServiceLoader::unloadServices( const QString& deviceName ) {
    kDebug() << "unloading service for " << deviceName;
    kDebug() << d->m_loadedServices;
    if( d->m_loadedServices.contains( deviceName ) ) {
        QList<KMobileTools::CoreService*> services = d->m_loadedServices.values( deviceName );
        for( int i=0; i<services.size(); i++ ) {
            kDebug() << "about to unload service for " << deviceName;
            emit aboutToUnloadService( deviceName, services.value( i ) );
            /// @warning deleting the service here could cause a problem
            /// since a slot that is connected to the aboutToUnloadService signal
            /// could work with the service while it could become invalid
            services.value( i )->deleteLater();
            emit serviceUnloaded( deviceName, services.value( i ) );
        }

        d->m_loadedServices.remove( deviceName );
    }
    kDebug() << "done.";
}

QList<KMobileTools::CoreService*> ServiceLoader::service( const QString& deviceName, const QStringList& interfaces ) const 
{
    /// @todo implement me
    return QList<KMobileTools::CoreService*>();
}


}

#include "serviceloader.moc"
