#include "StorageChangeNotifier.h"
#include "StorageChangeNotifierPlugin.h"
#include "PluginManager.h"
#include "LogMacros.h"

#include <QStringList>

using namespace Buteo;

StorageChangeNotifier::StorageChangeNotifier()
    : iPluginManager(nullptr)
{
    FUNCTION_CALL_TRACE(lcButeoTrace);
}

StorageChangeNotifier::~StorageChangeNotifier()
{
    FUNCTION_CALL_TRACE(lcButeoTrace);
    StorageChangeNotifierPlugin *plugin = 0;
    for (QHash<QString, StorageChangeNotifierPlugin *>::iterator storageNameItr = iNotifierMap.begin();
            storageNameItr != iNotifierMap.end(); ++storageNameItr) {
        plugin = storageNameItr.value();
        if (iPluginManager && plugin) {
            iPluginManager->destroyStorageChangeNotifier(plugin);
        }
    }
}

void StorageChangeNotifier::loadNotifiers(PluginManager *aPluginManager,
                                          const QStringList &aStorageNames)
{
    FUNCTION_CALL_TRACE(lcButeoTrace);
    iPluginManager = aPluginManager;

    for (QStringList::const_iterator storageNameItr = aStorageNames.constBegin()
         ; storageNameItr != aStorageNames.constEnd(); ++storageNameItr) {
        if (iPluginManager) {
            StorageChangeNotifierPlugin *plugin = iPluginManager->createStorageChangeNotifier(*storageNameItr);
            if (plugin) {
                iNotifierMap[*storageNameItr] = plugin;
            }
        }
    }
}

bool StorageChangeNotifier::startListen(QStringList *failedStorages)
{
    FUNCTION_CALL_TRACE(lcButeoTrace);
    bool success = true;

    if (!iNotifierMap.count()) {
        success = false;
    }

    for (QHash<QString, StorageChangeNotifierPlugin *>::iterator storageNameItr = iNotifierMap.begin();
            storageNameItr != iNotifierMap.end(); ++storageNameItr) {
        StorageChangeNotifierPlugin *plugin = storageNameItr.value();
        if (plugin) {
            QObject::connect(plugin, SIGNAL(storageChange()),
                             this, SLOT(storageChanged()));
            plugin->enable();
        } else {
            if (failedStorages) {
                *failedStorages << storageNameItr.key();
            }
            success = false;
        }
    }
    return success;
}

void StorageChangeNotifier::stopListen(bool disableAfterNextChange)
{
    FUNCTION_CALL_TRACE(lcButeoTrace);

    for (QHash<QString, StorageChangeNotifierPlugin *>::iterator storageNameItr = iNotifierMap.begin();
            storageNameItr != iNotifierMap.end(); ++storageNameItr) {
        StorageChangeNotifierPlugin *plugin = storageNameItr.value();
        if (plugin) {
            QObject::disconnect(plugin, SIGNAL(storageChange()),
                                this, SLOT(storageChanged()));
            plugin->disable(disableAfterNextChange);
        }
    }
}

void StorageChangeNotifier::storageChanged()
{
    FUNCTION_CALL_TRACE(lcButeoTrace);
    StorageChangeNotifierPlugin *plugin = qobject_cast<StorageChangeNotifierPlugin *>(sender());
    if (plugin) {
        qCDebug(lcButeoMsyncd) << "Change in storage" << plugin->name();
        plugin->changesReceived();
        emit storageChange(plugin->name());
    }
}

void StorageChangeNotifier::checkForChanges()
{
    FUNCTION_CALL_TRACE(lcButeoTrace);

    for (QHash<QString, StorageChangeNotifierPlugin *>::iterator storageNameItr = iNotifierMap.begin();
            storageNameItr != iNotifierMap.end(); ++storageNameItr) {
        StorageChangeNotifierPlugin *plugin = storageNameItr.value();
        if (plugin && plugin->hasChanges()) {
            plugin->changesReceived();
            emit storageChange(plugin->name());
        }
    }
}
