/* This file is part of the KDE libraries
    Copyright (C) 2013 Dawit Alemayehu <adawit@kde.org>

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

    This library 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
    Library General Public License for more details.

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

#include "clipboardupdater_p.h"
#include "jobclasses.h"
#include "copyjob.h"
#include "deletejob.h"

#include <QApplication>
#include <QMimeData>
#include <QClipboard>

using namespace KIO;


static bool canUseClipboard()
{
    return QApplication::type() != QApplication::Tty;
}

static void overwriteUrlsInClipboard(KJob* job)
{
    CopyJob* copyJob = qobject_cast<CopyJob*>(job);
    FileCopyJob* fileCopyJob = qobject_cast<FileCopyJob*>(job);

    if (!copyJob && !fileCopyJob) {
        return;
    }

    KUrl::List newUrls;

    if (copyJob) {
        Q_FOREACH(const KUrl& url, copyJob->srcUrls()) {
            KUrl dUrl = copyJob->destUrl();
            dUrl.addPath(url.fileName());
            newUrls.append(dUrl);
        }
    } else if (fileCopyJob) {
        newUrls << fileCopyJob->destUrl();
    }

    QMimeData* mime = new QMimeData();
    newUrls.populateMimeData(mime);
    QApplication::clipboard()->setMimeData(mime);
}

static void updateUrlsInClipboard(KJob* job)
{
    CopyJob* copyJob = qobject_cast<CopyJob*>(job);
    FileCopyJob* fileCopyJob = qobject_cast<FileCopyJob*>(job);

    if (!copyJob && !fileCopyJob) {
        return;
    }

    QClipboard* clipboard = QApplication::clipboard();
    KUrl::List clipboardUrls = KUrl::List::fromMimeData(clipboard->mimeData());
    bool update = false;

    if (copyJob) {
        Q_FOREACH(const KUrl& url, copyJob->srcUrls()) {
            const int index = clipboardUrls.indexOf(url);
            if (index > -1) {
                KUrl dUrl = copyJob->destUrl();
                dUrl.addPath(url.fileName());
                clipboardUrls.replace(index, dUrl);
                update = true;
            }
        }
    } else if (fileCopyJob) {
        const int index = clipboardUrls.indexOf(fileCopyJob->srcUrl());
        if (index > -1) {
            clipboardUrls.replace(index, fileCopyJob->destUrl());
            update = true;
        }
    }

    if (update) {
        QMimeData* mime = new QMimeData();
        clipboardUrls.populateMimeData(mime);
        clipboard->setMimeData(mime);
    }
}

static void removeUrlsFromClipboard(KJob* job)
{
    SimpleJob* simpleJob = qobject_cast<SimpleJob*>(job);
    DeleteJob* deleteJob = qobject_cast<DeleteJob*>(job);

    if (!simpleJob && !deleteJob) {
        return;
    }

    KUrl::List deletedUrls;
    if (simpleJob) {
        deletedUrls << simpleJob->url();
    } else if (deleteJob) {
        deletedUrls << deleteJob->urls();
    }

    if (deletedUrls.isEmpty()) {
        return;
    }

    QClipboard* clipboard = QApplication::clipboard();
    KUrl::List clipboardUrls = KUrl::List::fromMimeData(clipboard->mimeData());
    quint32 removedCount = 0;

    Q_FOREACH(const KUrl& url, deletedUrls) {
        removedCount += clipboardUrls.removeAll(url);
    }

    if (removedCount > 0) {
        QMimeData* mime = new QMimeData();
        if (!clipboardUrls.isEmpty()) {
            clipboardUrls.populateMimeData(mime);
        }
        clipboard->setMimeData(mime);
    }
}

void ClipboardUpdater::slotResult(KJob* job)
{
    if (job->error()) {
        return;
    }

    switch (m_mode) {
    case UpdateContent:
        updateUrlsInClipboard(job);
        break;
    case OverwriteContent:
        overwriteUrlsInClipboard(job);
        break;
    case RemoveContent:
        removeUrlsFromClipboard(job);
        break;
    }
}

void ClipboardUpdater::setMode(ClipboardUpdater::Mode mode)
{
    m_mode = mode;
}

ClipboardUpdater* ClipboardUpdater::create(Job* job, ClipboardUpdater::Mode mode)
{
    if (canUseClipboard()) {
      return new ClipboardUpdater(job, mode);
    }

    return 0;
}

void ClipboardUpdater::update(const KUrl& srcUrl, const KUrl& destUrl)
{
    if (!canUseClipboard()) {
        return;
    }

    QClipboard* clipboard = QApplication::clipboard();
    if (clipboard->mimeData()->hasUrls()) {
        KUrl::List clipboardUrls = KUrl::List::fromMimeData(clipboard->mimeData());
        const int index = clipboardUrls.indexOf(srcUrl);
        if (index > -1) {
            clipboardUrls.replace(index, destUrl);
            QMimeData* mime = new QMimeData();
            clipboardUrls.populateMimeData(mime);
            clipboard->setMimeData(mime);
        }
    }
}

ClipboardUpdater::ClipboardUpdater(Job* job, Mode mode)
    :QObject(job),
     m_mode(mode)
{
    Q_ASSERT(job);
    connect(job, SIGNAL(result(KJob*)), this, SLOT(slotResult(KJob*)));
}
