/* ============================================================
 *
 * This file is a part of kipi-plugins project
 * http://www.digikam.org
 *
 * Date        : 2011-04-12
 * Description : A KIPI Plugin to export albums to rajce.net
 *
 * Copyright (C) 2011 by Lukas Krejci <krejci.l at centrum dot cz>
 *
 * 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, 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.
 *
 * ============================================================ */

#include "rajcesession.h"

// Qt includes

#include <QWidget>
#include <QCryptographicHash>
#include <QXmlResultItems>
#include <QXmlQuery>
#include <QFileInfo>
#include <QUrl>

// KDE includes

#include <kio/job.h>
#include <kio/jobuidelegate.h>
#include <kjobwidgets.h>

// Libkipi includes

#include <KIPI/Interface>
#include <KIPI/PluginLoader>

// Local includes

#include "kipiplugins_debug.h"
#include "mpform.h"
#include "kpversion.h"
#include "kputil.h"

using namespace KIPI;
using namespace KIPIPlugins;

namespace KIPIRajcePlugin
{

const QUrl     RAJCE_URL(QStringLiteral("http://www.rajce.idnes.cz/liveAPI/index.php"));
const unsigned THUMB_SIZE = 100;

struct PreparedImage
{
    QString scaledImagePath;
    QString thumbPath;
};

PreparedImage _prepareImageForUpload(const QString& saveDir, const QImage& img, const QString& imagePath,
                                     unsigned maxDimension, unsigned thumbDimension, int jpgQuality)
{
    PreparedImage ret;

    if (img.isNull())
        return ret;

    QImage image(img);

    // get temporary file name
    QString baseName    = saveDir + QFileInfo(imagePath).baseName().trimmed();
    ret.scaledImagePath = baseName + QStringLiteral(".jpg");
    ret.thumbPath       = baseName + QStringLiteral(".thumb.jpg");

    if (maxDimension > 0 && ((unsigned) image.width() > maxDimension || (unsigned) image.height() > maxDimension))
    {
        qCDebug(KIPIPLUGINS_LOG) << "Resizing to " << maxDimension;
        image = image.scaled(maxDimension, maxDimension, Qt::KeepAspectRatio, Qt::SmoothTransformation);
    }

    qCDebug(KIPIPLUGINS_LOG) << "Saving to temp file: " << ret.scaledImagePath;
    image.save(ret.scaledImagePath, "JPEG", jpgQuality);

    QImage thumb = image.scaled(thumbDimension, thumbDimension, Qt::KeepAspectRatio, Qt::SmoothTransformation);
    qCDebug(KIPIPLUGINS_LOG) << "Saving thumb to temp file: " << ret.thumbPath;
    thumb.save(ret.thumbPath, "JPEG", jpgQuality);

    PluginLoader* const pl = PluginLoader::instance();

    if (pl)
    {
        Interface* const iface = pl->interface();
        
        if (iface)
        {
            // copy meta data to temporary image
            QPointer<MetadataProcessor> meta = iface->createMetadataProcessor();

            if (meta->load(QUrl::fromLocalFile(imagePath)))
            {
                meta->setImageDimensions(image.size());
                meta->setImageProgramId(QStringLiteral("Kipi-plugins"), kipipluginsVersion());
                meta->save(QUrl::fromLocalFile(ret.scaledImagePath));
            }
        }
    }

    return ret;
}

/// Commands definitions

class RajceCommand
{
public:

    explicit RajceCommand(const QString& name, RajceCommandType commandType);
    virtual ~RajceCommand();

    QString getXml() const;

    void processResponse(const QString& response, SessionState& state);

    RajceCommandType commandType() const;

    virtual QByteArray encode()   const;
    virtual QString contentType() const;

protected:

    virtual void parseResponse(QXmlQuery& query, SessionState& state) = 0;
    virtual void cleanUpOnError(SessionState& state) = 0;

    QMap<QString, QString>& parameters() const; // allow modification in const methods for lazy init to be possible

    // additional xml after the "parameters"
    virtual QString additionalXml() const;

private:

    bool _parseError(QXmlQuery& query, SessionState& state);

private:

    QString                m_name;
    RajceCommandType       m_commandType;
    QMap<QString, QString> m_parameters;
};

// -----------------------------------------------------------------------

class LoginCommand : public RajceCommand
{
public:

    LoginCommand(const QString& username, const QString& password);

protected:

    virtual void parseResponse(QXmlQuery& response, SessionState& state);
    virtual void cleanUpOnError(SessionState& state);
};

// -----------------------------------------------------------------------

class OpenAlbumCommand : public RajceCommand
{
public:

    explicit OpenAlbumCommand(unsigned albumId, const SessionState& state);

protected:

    virtual void parseResponse(QXmlQuery& response, SessionState& state);
    virtual void cleanUpOnError(SessionState& state);
};

// -----------------------------------------------------------------------

class CreateAlbumCommand : public RajceCommand
{
public:

    CreateAlbumCommand(const QString& name, const QString& description, bool visible, const SessionState& state);

protected:

    virtual void parseResponse(QXmlQuery& response, SessionState& state);
    virtual void cleanUpOnError(SessionState& state);
};

// -----------------------------------------------------------------------

class CloseAlbumCommand : public RajceCommand
{
public:

    CloseAlbumCommand(const SessionState& state);

protected:

    virtual void parseResponse(QXmlQuery& response, SessionState& state);
    virtual void cleanUpOnError(SessionState& state);
};

// -----------------------------------------------------------------------

class AlbumListCommand : public RajceCommand
{
public:

    AlbumListCommand(const SessionState&);

protected:

    virtual void parseResponse(QXmlQuery& response, SessionState& state);
    virtual void cleanUpOnError(SessionState& state);
};

// -----------------------------------------------------------------------

class AddPhotoCommand : public RajceCommand
{
public:

    AddPhotoCommand(const QString& tmpDir, const QString& path, unsigned dimension, int jpgQuality, const SessionState& state);
    virtual ~AddPhotoCommand();

    virtual QByteArray encode() const;
    virtual QString contentType() const;

protected:

    virtual void cleanUpOnError(KIPIRajcePlugin::SessionState& state);
    virtual void parseResponse(QXmlQuery& query, KIPIRajcePlugin::SessionState& state);
    virtual QString additionalXml() const;

private:

    int        m_jpgQuality;

    unsigned   m_desiredDimension;
    unsigned   m_maxDimension;

    QString    m_tmpDir;
    QString    m_imagePath;

    QImage     m_image;

    MPForm*    m_form;
};

/// Commands impls

RajceCommand::RajceCommand(const QString& name, RajceCommandType type)
    : m_name(name),
      m_commandType(type)
{
}

RajceCommand::~RajceCommand()
{
}

QMap<QString, QString>& RajceCommand::parameters() const
{
    return const_cast<QMap<QString, QString> &>(m_parameters);
}

QString RajceCommand::getXml() const
{
    QString ret(QStringLiteral("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));

    ret.append(QStringLiteral("<request>\n"));
    ret.append(QStringLiteral("  <command>")).append(m_name).append(QStringLiteral("</command>\n"));
    ret.append(QStringLiteral("  <parameters>\n"));

    foreach(QString key, m_parameters.keys())
    {
        ret.append(QStringLiteral("    <")).append(key).append(QStringLiteral(">"));
        ret.append(m_parameters[key]);
        ret.append(QStringLiteral("</")).append(key).append(QStringLiteral(">\n"));
    }

    ret.append(QStringLiteral("</parameters>\n"));
    ret.append(additionalXml());
    ret.append(QStringLiteral("\n</request>\n"));

    return ret;
}

bool RajceCommand::_parseError(QXmlQuery& query, SessionState& state)
{
    QString results;

    query.setQuery(QStringLiteral("/response/string(errorCode)"));
    query.evaluateTo(&results);

    if (results.trimmed().length() > 0)
    {
        state.lastErrorCode() = results.toUInt();
        query.setQuery(QStringLiteral("/response/string(result)"));
        query.evaluateTo(&results);
        state.lastErrorMessage() = results.trimmed();

        return true;
    }

    return false;
}

void RajceCommand::processResponse(const QString& response, SessionState& state)
{
    QXmlQuery q;
    q.setFocus(response);

    state.lastCommand() = m_commandType;

    if (_parseError(q, state))
    {
        cleanUpOnError(state);
    }
    else
    {
        parseResponse(q, state);
    }
}

QString RajceCommand::additionalXml() const
{
    return QString();
}

QByteArray RajceCommand::encode() const
{
    QByteArray ret = QStringLiteral("data=").toLatin1();
    ret.append(QUrl::toPercentEncoding(getXml()));

    return ret;
}

QString RajceCommand::contentType() const
{
    return QStringLiteral("application/x-www-form-urlencoded");
}

RajceCommandType RajceCommand::commandType() const
{
    return m_commandType;
}

// -----------------------------------------------------------------------

OpenAlbumCommand::OpenAlbumCommand(unsigned albumId, const SessionState& state)
    : RajceCommand(QStringLiteral("openAlbum"), OpenAlbum)
{
    parameters()[QStringLiteral("token")]   = state.sessionToken();
    parameters()[QStringLiteral("albumID")] = QString::number(albumId);
}

void OpenAlbumCommand::parseResponse(QXmlQuery& q, SessionState& state)
{
    state.openAlbumToken() = QString();

    QString result;

    q.setQuery(QStringLiteral("/response/data(albumToken)"));
    q.evaluateTo(&result);

    state.openAlbumToken() = result.trimmed();
}

void OpenAlbumCommand::cleanUpOnError(SessionState& state)
{
    state.openAlbumToken() = QString();
}

// -----------------------------------------------------------------------

LoginCommand::LoginCommand(const QString& username, const QString& password)
    : RajceCommand(QStringLiteral("login"), Login)
{
    parameters()[QStringLiteral("login")]    = username;
    parameters()[QStringLiteral("password")] = QString::fromLatin1(
        QCryptographicHash::hash(password.toUtf8(), QCryptographicHash::Md5).toHex());
}

void LoginCommand::parseResponse(QXmlQuery& q, SessionState& state)
{
    QString results;

    q.setQuery(QStringLiteral("/response/string(maxWidth)"));
    q.evaluateTo(&results);
    state.maxWidth() = results.toUInt();

    q.setQuery(QStringLiteral("/response/string(maxHeight)"));
    q.evaluateTo(&results);
    state.maxHeight() = results.toUInt();

    q.setQuery(QStringLiteral("/response/string(quality)"));
    q.evaluateTo(&results);
    state.imageQuality() = results.toUInt();

    q.setQuery(QStringLiteral("/response/string(nick)"));
    q.evaluateTo(&results);
    state.nickname() = results.trimmed();

    q.setQuery(QStringLiteral("data(/response/sessionToken)"));
    q.evaluateTo(&results);
    state.sessionToken() = results.trimmed();

    state.username() = parameters()[QStringLiteral("login")];
}

void LoginCommand::cleanUpOnError(SessionState& state)
{
    state.openAlbumToken() = QStringLiteral("");
    state.nickname()       = QStringLiteral("");
    state.username()       = QStringLiteral("");
    state.imageQuality()   = 0;
    state.maxHeight()      = 0;
    state.maxWidth()       = 0;
    state.sessionToken()   = QStringLiteral("");
    state.albums().clear();
}

// -----------------------------------------------------------------------

CreateAlbumCommand::CreateAlbumCommand(const QString& name, const QString& description,
                                       bool visible, const SessionState& state)
    : RajceCommand(QStringLiteral("createAlbum"), CreateAlbum)
{
    parameters()[QStringLiteral("token")]            = state.sessionToken();
    parameters()[QStringLiteral("albumName")]        = name;
    parameters()[QStringLiteral("albumDescription")] = description;
    parameters()[QStringLiteral("albumVisible")]     = visible ? QStringLiteral("1") : QStringLiteral("0");
}

void CreateAlbumCommand::parseResponse(QXmlQuery&, SessionState&)
{
}

void CreateAlbumCommand::cleanUpOnError(SessionState&)
{
}

void CloseAlbumCommand::parseResponse(QXmlQuery&, SessionState&)
{
}

void CloseAlbumCommand::cleanUpOnError(SessionState&)
{
}

// -----------------------------------------------------------------------

CloseAlbumCommand::CloseAlbumCommand(const SessionState& state)
    : RajceCommand(QStringLiteral("closeAlbum"), CloseAlbum)
{
    parameters()[QStringLiteral("token")]      = state.sessionToken();
    parameters()[QStringLiteral("albumToken")] = state.openAlbumToken();
}

// -----------------------------------------------------------------------

AlbumListCommand::AlbumListCommand(const SessionState& state)
    : RajceCommand(QStringLiteral("getAlbumList"), ListAlbums)
{
    parameters()[QStringLiteral("token")] = state.sessionToken();
}

void AlbumListCommand::parseResponse(QXmlQuery& q, SessionState& state)
{
    state.albums().clear();

    QXmlResultItems results;

    q.setQuery(QStringLiteral("/response/albums/album"));
    q.evaluateTo(&results);

    QXmlItem item(results.next());

    while(!item.isNull())
    {
        q.setFocus(item);
        Album album;
        QString detail;

        q.setQuery(QStringLiteral("data(./@id)"));
        q.evaluateTo(&detail);
        album.id = detail.toUInt();

        q.setQuery(QStringLiteral("data(./albumName)"));
        q.evaluateTo(&detail);
        album.name = detail.trimmed();

        q.setQuery(QStringLiteral("data(./description)"));
        q.evaluateTo(&detail);
        album.description = detail.trimmed();

        q.setQuery(QStringLiteral("data(./url)"));
        q.evaluateTo(&detail);
        album.url = detail.trimmed();

        q.setQuery(QStringLiteral("data(./thumbUrl)"));
        q.evaluateTo(&detail);
        album.thumbUrl = detail.trimmed();

        q.setQuery(QStringLiteral("data(./createDate)"));
        q.evaluateTo(&detail);
        album.createDate = QDateTime::fromString(detail.trimmed(), QStringLiteral("yyyy-MM-dd hh:mm:ss"));

        qCDebug(KIPIPLUGINS_LOG) << "Create date: " << detail.trimmed() << " = " << QDateTime::fromString(detail.trimmed(), QStringLiteral("yyyy-MM-dd hh:mm:ss"));

        q.setQuery(QStringLiteral("data(./updateDate)"));
        q.evaluateTo(&detail);
        album.updateDate = QDateTime::fromString(detail.trimmed(), QStringLiteral("yyyy-MM-dd hh:mm:ss"));

        q.evaluateTo(&detail);
        album.isHidden = detail.toUInt() != 0;

        q.setQuery(QStringLiteral("data(./secure)"));
        q.evaluateTo(&detail);
        album.isSecure = detail.toUInt() != 0;

        q.setQuery(QStringLiteral("data(./startDateInterval)"));
        q.evaluateTo(&detail);

        if (detail.trimmed().length() > 0)
        {
            album.validFrom = QDateTime::fromString(detail, QStringLiteral("yyyy-MM-dd hh:mm:ss"));
        }

        q.setQuery(QStringLiteral("data(./endDateInterval)"));
        q.evaluateTo(&detail);

        if (detail.trimmed().length() > 0)
        {
            album.validTo = QDateTime::fromString(detail, QStringLiteral("yyyy-MM-dd hh:mm:ss"));
        }

        q.setQuery(QStringLiteral("data(./thumbUrlBest)"));
        q.evaluateTo(&detail);
        album.bestQualityThumbUrl = detail.trimmed();

        state.albums().append(album);
        item = results.next();
    }
}

void AlbumListCommand::cleanUpOnError(SessionState& state)
{
    state.albums().clear();
}

// -----------------------------------------------------------------------

AddPhotoCommand::AddPhotoCommand(const QString& tmpDir, const QString& path, unsigned dimension,
                                 int jpgQuality, const SessionState& state)
    : RajceCommand(QStringLiteral("addPhoto"), AddPhoto),
      m_jpgQuality(jpgQuality),
      m_desiredDimension(dimension),
      m_maxDimension(0),
      m_tmpDir(tmpDir),
      m_imagePath(path),
      m_form(0)
{
    PluginLoader* const pl = PluginLoader::instance();

    if (pl)
    {
        Interface* const iface = pl->interface();
        
        if (iface)
        {
            QPointer<RawProcessor> rawdec = iface->createRawProcessor();

            // check if its a RAW file.
            if (rawdec && rawdec->isRawFile(QUrl::fromLocalFile(path)))
            {
                rawdec->loadRawPreview(QUrl::fromLocalFile(path), m_image);
            }
        }
    }

    if (m_image.isNull())
    {
        m_image.load(path);
    }

    if (m_image.isNull())
    {
        qCDebug(KIPIPLUGINS_LOG) << "Could not read in an image from " << path << ". Adding the photo will not work.";
        return;
    }

    m_maxDimension             = state.maxHeight() > state.maxWidth() ? state.maxWidth() : state.maxHeight();
    parameters()[QStringLiteral("token")]      = state.sessionToken();
    parameters()[QStringLiteral("albumToken")] = state.openAlbumToken();
    m_form                     = new MPForm;
}

AddPhotoCommand::~AddPhotoCommand()
{
    delete m_form;
}

void AddPhotoCommand::cleanUpOnError(KIPIRajcePlugin::SessionState&)
{
}

void AddPhotoCommand::parseResponse(QXmlQuery&, KIPIRajcePlugin::SessionState&)
{
}

QString AddPhotoCommand::additionalXml() const
{
    if (m_image.isNull())
    {
        return QString();
    }

    QMap<QString, QString> metadata;
    QFileInfo f(m_imagePath);

    metadata[QStringLiteral("FullFilePath")]          = m_imagePath;
    metadata[QStringLiteral("OriginalFileName")]      = f.fileName();
    metadata[QStringLiteral("OriginalFileExtension")] = QStringLiteral(".") + f.suffix();
    metadata[QStringLiteral("PerceivedType")]         = QStringLiteral("image"); //what are the other values here? video?
    metadata[QStringLiteral("OriginalWidth")]         = QString::number(m_image.width());
    metadata[QStringLiteral("OriginalHeight")]        = QString::number(m_image.height());
    metadata[QStringLiteral("LengthMS")]              = QLatin1Char('0');
    metadata[QStringLiteral("FileSize")]              = QString::number(f.size());

    //TODO extract these from exif
    metadata[QStringLiteral("Title")]           = QStringLiteral("");
    metadata[QStringLiteral("KeywordSet")]      = QStringLiteral("");
    metadata[QStringLiteral("PeopleRegionSet")] = QStringLiteral("");

    qsrand((uint)QTime::currentTime().msec());
    QString id = QString::number(qrand());
    QString ret(QStringLiteral("  <objectInfo>\n    <Item id=\""));
    ret.append(id).append(QStringLiteral("\">\n"));

    foreach(QString key, metadata.keys())
    {
        ret.append(QStringLiteral("      <")).append(key);
        QString value = metadata[key];

        if (value.length() == 0)
        {
            ret.append(QStringLiteral(" />\n"));
        }
        else
        {
            ret.append(QStringLiteral(">"));
            ret.append(value);
            ret.append(QStringLiteral("</"));
            ret.append(key);
            ret.append(QStringLiteral(">\n"));
        }
    }

    ret.append(QStringLiteral("    </Item>\n  </objectInfo>\n"));

    return ret;
}

QString AddPhotoCommand::contentType() const
{
    return m_form->contentType();
}

QByteArray AddPhotoCommand::encode() const
{
    if (m_image.isNull())
    {
        qCDebug(KIPIPLUGINS_LOG) << m_imagePath << " could not be read, no data will be sent.";
        return QByteArray();
    }

    PreparedImage prepared = _prepareImageForUpload(m_tmpDir, m_image, m_imagePath, m_desiredDimension, THUMB_SIZE, m_jpgQuality);

    //add the rest of the parameters to be encoded as xml
    QImage scaled(prepared.scaledImagePath);
    parameters()[QStringLiteral("width")]  = QString::number(scaled.width());
    parameters()[QStringLiteral("height")] = QString::number(scaled.height());

    QString xml = getXml();

    qCDebug(KIPIPLUGINS_LOG) << "Really sending:\n" << xml;

    //now we can create the form with all the info
    m_form->reset();

    m_form->addPair(QStringLiteral("data"), xml);

    m_form->addFile(QStringLiteral("thumb"), prepared.thumbPath);
    m_form->addFile(QStringLiteral("photo"), prepared.scaledImagePath);

    QFile::remove(prepared.thumbPath);
    QFile::remove(prepared.scaledImagePath);

    m_form->finish();

    QByteArray ret = m_form->formData();

    return ret;
}

/// RajceSession impl

RajceSession::RajceSession(QWidget* const parent, const QString& tmpDir)
    : QObject(parent), m_queueAccess(), m_tmpDir(tmpDir), m_currentJob(0)
{
}

const SessionState& RajceSession::state() const
{
    return m_state;
}

void RajceSession::_startJob(RajceCommand* command)
{
    qCDebug(KIPIPLUGINS_LOG) << "Sending command:\n" << command->getXml();

    QByteArray data             = command->encode();
    KIO::TransferJob* const job = KIO::http_post(RAJCE_URL, data, KIO::HideProgressInfo);
    KJobWidgets::setWindow(job, static_cast<QWidget*>(parent()));
    job->addMetaData(QStringLiteral("content-type"), command->contentType());

    connect(job, SIGNAL(data(KIO::Job*,QByteArray)),
            this, SLOT(data(KIO::Job*,QByteArray)));

    connect(job, SIGNAL(result(KJob*)),
            this, SLOT(finished(KJob*)));

    connect(job, SIGNAL(percent(KJob*,ulong)),
            this, SLOT(slotPercent(KJob*,ulong)));

    m_currentJob = job;
    m_buffer.resize(0);

    emit busyStarted(command->commandType());
}

void RajceSession::login(const QString& username, const QString& password)
{
    LoginCommand* const command = new LoginCommand(username, password);
    _enqueue(command);
}

void RajceSession::loadAlbums()
{
    AlbumListCommand* const command = new AlbumListCommand(m_state);
    _enqueue(command);
}

void RajceSession::createAlbum(const QString& name, const QString& description, bool visible)
{
    CreateAlbumCommand* const command = new CreateAlbumCommand(name, description, visible, m_state);
    _enqueue(command);
}

void RajceSession::data(KIO::Job*, const QByteArray& data)
{
    if (data.isEmpty())
        return;

    int oldSize = m_buffer.size();
    m_buffer.resize(m_buffer.size() + data.size());
    memcpy(m_buffer.data() + oldSize, data.data(), data.size());
}

void RajceSession::finished(KJob*)
{
    QString response = QString::fromUtf8(m_buffer.data());

    qCDebug(KIPIPLUGINS_LOG) << response;

    m_queueAccess.lock();

    RajceCommand* const c = m_commandQueue.head();
    m_currentJob          = 0;

    c->processResponse(response, m_state);

    RajceCommandType type = c->commandType();

    delete c;

    qCDebug(KIPIPLUGINS_LOG) << "State after command: " << m_state;

    //let the users react on the command before we
    //let the next queued command in.
    //This enables the connected slots to read in
    //reliable values from the state and/or
    //clear the error state once it's handled.
    emit busyFinished(type);

    //only deque the command after the above signal has been
    //emitted so that the users can queue other commands
    //without them being started straight away in the enqueue
    //method which would happen if the command was dequed
    //before the signal and the signal was emitted in the same
    //thread (which is the case (always?)).
    m_commandQueue.dequeue();

    //see if there's something to continue with
    if (m_commandQueue.size() > 0)
    {
        _startJob(m_commandQueue.head());
    }

    m_queueAccess.unlock();
}

void RajceSession::logout()
{
    //TODO
}

void RajceSession::openAlbum(const KIPIRajcePlugin::Album& album)
{
    OpenAlbumCommand* const command = new OpenAlbumCommand(album.id, m_state);
    _enqueue(command);
}

void RajceSession::closeAlbum()
{
    if (!m_state.openAlbumToken().isEmpty())
    {
        CloseAlbumCommand* const command = new CloseAlbumCommand(m_state);
        _enqueue(command);
    }
    else
    {
        emit busyFinished(CloseAlbum);
    }
}

void RajceSession::uploadPhoto(const QString& path, unsigned dimension, int jpgQuality)
{
    AddPhotoCommand* const command = new AddPhotoCommand(m_tmpDir, path, dimension, jpgQuality, m_state);
    _enqueue(command);
}

void RajceSession::clearLastError()
{
    m_state.lastErrorCode()    = 0;
    m_state.lastErrorMessage() = QStringLiteral("");
}

void RajceSession::slotPercent(KJob* job, ulong percent)
{
    qCDebug(KIPIPLUGINS_LOG) << "Percent signalled: " << percent;

    if (job == m_currentJob)
    {
        qCDebug(KIPIPLUGINS_LOG) << "Re-emitting percent";
        emit busyProgress(m_commandQueue.head()->commandType(), percent);
    }
}

void RajceSession::_enqueue(RajceCommand* command)
{
    if (m_state.lastErrorCode() != 0)
    {
        return;
    }

    m_queueAccess.lock();
    m_commandQueue.enqueue(command);

    if (m_commandQueue.size() == 1)
    {
        _startJob(command);
    }

    m_queueAccess.unlock();
}

void RajceSession::cancelCurrentCommand()
{
    if (m_currentJob != 0)
    {
        KJob* const job = m_currentJob;
        finished(job);
        job->kill();
    }
}

void RajceSession::init(const KIPIRajcePlugin::SessionState& initialState)
{
    m_state = initialState;
}

} // namespace KIPIRajcePlugin
