/***************************************************************************
 *   Copyright (C) 2009 by Mathias Rabe <masterunderlined [at] web.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 3 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 "drop2ftp.h"
#include "urlgenerator.h"

#include <QDrag>
#include <QGraphicsSceneDragDropEvent>
#include <QTimer>
#include <QFontMetrics>

#include <QPainter>
#include <QPixmap>

#include <KUrl>
#include <KConfigDialog>
#include <KFileDialog>
#include <kio/copyjob.h>
#include <KIcon>
#include <KGlobalSettings>
#include <kicondialog.h>
#include <KMessageBox>
#include <KRun>

#include <Plasma/BusyWidget>
 
#include <plasma/tooltipmanager.h>

//#include <solid/device.h>
//#include <solid/networking.h>

#define MINSIZE 50

 
using namespace Plasma;

Drop2FTP::Drop2FTP(QObject *parent, const QVariantList &args)
    : Plasma::Applet(parent, args), 
       m_serverAddress(0),
       m_serverTitle(0),
       m_useBrowserOnClick(0),
       m_generateLinks(0),
       m_protocol4Links(0),
       m_defaultAction(0),
       m_numActivJobs(0),
       m_newIcon(0),
       m_iconName(0),
       m_syntax4Links(0),
       m_icon(0),
       m_label(0)
{
    setAcceptDrops(true);
    setHasConfigurationInterface(true);
    setBackgroundHints(NoBackground);
    setAspectRatioMode(Plasma::ConstrainedSquare);
    resize(100, 100);
} 
 
Drop2FTP::~Drop2FTP()
{
    delete m_icon;
    delete m_label;
}
 
void Drop2FTP::init()
{
    layout = new QGraphicsLinearLayout(this);
    layout->setContentsMargins(0, 0, 0, 0);
    layout->setOrientation(Qt::Vertical);
    layout->setSpacing(0);

    KConfigGroup cg = config();
    m_useBrowserOnClick = cg.readEntry("UseBrowserOnClick", false);
    m_serverAddress = cg.readEntry("Server", "");
    m_serverTitle = cg.readEntry("Title", "");
    m_iconName = cg.readEntry("IconName", "applications-internet");
    m_defaultAction = cg.readEntry("DefaultAction", (int)Drop2FTP::CopyFiles);
    m_generateLinks = cg.readEntry("GenerateLinks", false);
    m_protocol4Links = cg.readEntry("Protocol4Links", "http://");
    m_syntax4Links = cg.readEntry("Syntax4Links", "");

    m_label = new Plasma::Label(this);
    m_label->setAlignment(Qt::AlignHCenter);

    m_icon = new Plasma::IconWidget(KIcon(m_iconName), QString(), this);
    registerAsDragHandle(m_icon);
    layout->addItem(m_icon);

    Plasma::ToolTipManager::self()->registerWidget(this);
    Plasma::ToolTipContent toolTipData(i18n("Drop2FTP"), i18n("Drop your files here to send them to your server"), //TODO: replace "to your server" with the specified name in the settings
                                       m_icon->icon().pixmap(IconSize(KIconLoader::Desktop))); //TODO the icon doesn't refresh if it changes
    Plasma::ToolTipManager::self()->setContent(this, toolTipData);

    if (m_useBrowserOnClick) {
        connect(m_icon, SIGNAL(clicked()), this, SLOT(openDestination()));
    } else {
        connect(m_icon, SIGNAL(clicked()), this, SLOT(openFileDialog()));
    }

    QAction* openDial = new QAction(i18n("&Send files"), this);
    openDial->setIcon(KIcon("folder"));
    QAction* openDest = new QAction(i18n("&Open destination in konqueror"), this);
    openDest->setIcon(KIcon("konqueror"));
    QAction* seperator = new QAction(this);
    seperator->setSeparator(true);

    m_actions.append(openDial);
    m_actions.append(openDest);
    m_actions.append(seperator);

    connect(openDial, SIGNAL(triggered(bool)), SLOT(openFileDialog()));
    connect(openDest, SIGNAL(triggered(bool)), SLOT(openDestination()));

    //for the settings:
    model = new QStandardItemModel;
}

void Drop2FTP::paintInterface(QPainter *p,
        const QStyleOptionGraphicsItem *option, const QRect &contentsRect)
{
    Q_UNUSED( p );
    Q_UNUSED( option );

    if (!m_serverTitle.isEmpty() && layout->count() == 1 && qRound(contentsRect.width()) >= MINSIZE) { //add new label
        layout->addItem(m_label);
        layout->setStretchFactor(m_label, 0);
    }
    if (!m_serverTitle.isEmpty() && layout->count() == 2 && qRound(contentsRect.width()) >= MINSIZE) { //rename existing label
        QFontMetrics fontMetric = KGlobalSettings::smallestReadableFont();
        QString elidedServerTitle = fontMetric.elidedText(m_serverTitle, Qt::ElideRight, qRound(contentsRect.width()) - 13);
        m_label->setText(elidedServerTitle);
    } else { //remove label if there is no m_serverTitle or if the icon is to small
        m_label->setText(""); //otherwise fragments are the result
        layout->removeItem(m_label);
    }
}

void Drop2FTP::openDestination()
{
    if (m_serverAddress.isEmpty()) {
        emit showConfigurationInterface();
        return;
    }

    KUrl::List serverList;
    serverList.append(m_serverAddress);
    KRun::run("konqueror %u", serverList, 0);
    //KRun::runUrl(m_serverAddress, "inode/directory", 0); // doesn't work if dolphin is standard and ftp is used?!
}

QList<QAction*> Drop2FTP::contextualActions()
{
    return m_actions;
}

void Drop2FTP::openFileDialog()
{
    if (m_serverAddress.isEmpty()) {
        emit showConfigurationInterface();
        return;
    }
    KUrl::List fileNameListFromDialog = KFileDialog::getOpenFileNames(); //http://api.kde.org/4.x-api/kdelibs-apidocs/kio/html/hierarchy.html
    if (!fileNameListFromDialog.isEmpty()) {
        sendToServer(fileNameListFromDialog);
    }
}

void Drop2FTP::createConfigurationInterface(KConfigDialog *parent)
{
    //Destination address-line
    QWidget *widgetDest = new QWidget;
    uiDest.setupUi(widgetDest);
    uiDest.serverAddress->setToolTip(i18n("Specify here the destination host. Use an entire address like ftp://192.168.0.1:21/folder"));
    uiDest.serverAddress->insert(m_serverAddress);

    //Destination bookmark-button
    bookmarkManager = KBookmarkManager::userBookmarksManager();
    bookmarkManager->setEditorOptions("Drop2FTP", true);
    connect(uiDest.editBookmarkButton, SIGNAL(clicked()), bookmarkManager, SLOT(slotEditBookmarks()));

    //Destination bookmark-treeview
    parentItem = model->invisibleRootItem();
    uiDest.bookmarkTree->setModel(model);
    connect(uiDest.bookmarkTree, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(copyBookmarkAddress(const QModelIndex &)));

    traverser = new BookmarkTraverser;
    connect(traverser, SIGNAL(newBookmarkGroup(QString, QString)), this, SLOT(addBookmarkGroup(QString, QString)));
    connect(traverser, SIGNAL(newBookmark(QString, QString, KUrl)), this, SLOT(addBookmark(QString, QString, KUrl)));
    connect(traverser, SIGNAL(leaveBookmarkGroup()), this, SLOT(leaveBookmarkGroup()));

    connect(bookmarkManager, SIGNAL(changed(const QString &, const QString &)), this, SLOT(traverseBookmarks(const QString &, const QString &)));
    traverseBookmarks();

    //Destination warningwidget
    if (m_serverAddress.isEmpty()) {
        KIcon icon = KIcon("msg_warning");
        QPixmap pixmap = icon.pixmap(QSize(20, 20));

        uiDest.iconLabel->setPixmap(pixmap);
        uiDest.informationLabel->setText(i18n("Please specify your destination host under \"Address\""));
    }

    //Appearance
    QWidget *widgetAppear = new QWidget;
    uiAppear.setupUi(widgetAppear);
    uiAppear.iconButton->setIcon(KIcon(m_iconName));
    connect(uiAppear.iconButton, SIGNAL(clicked()), this, SLOT(openIconDialog()));
    uiAppear.serverTitle->setToolTip(i18n("Here you can specify which text should be displayed under the Icon"));
    uiAppear.serverTitle->insert(m_serverTitle);

    //Behavior
    QWidget *widgetBehav = new QWidget;
    uiBehav.setupUi(widgetBehav);

    //Behavior Default Action
    switch(m_defaultAction) {
        case Drop2FTP::CopyFiles:
            uiBehav.copy->setChecked(true);
            break;
        case Drop2FTP::MoveFiles:
            uiBehav.move->setChecked(true);
            break;
        case Drop2FTP::AskForFiles:
            uiBehav.ask->setChecked(true);
            break;
        default: 
            kDebug() << "error on switch case";
    }

    //Behavior Action On CLick
    uiBehav.useDialog->setToolTip(i18n("Opens an \"open with\" dialog if you click on the icon"));
    uiBehav.useBrowser->setToolTip(i18n("This will open your specified destination in konqueror if you click on the icon"));
    if (m_useBrowserOnClick) {
        uiBehav.useBrowser->setChecked(true);
    } else {
        uiBehav.useDialog->setChecked(true);
    }

    //Behavior protocol
    if (m_protocol4Links == "http://") {
        uiBehav.protocol->setCurrentIndex(0);
    } else { //ftp://
        uiBehav.protocol->setCurrentIndex(1);
    }

    //Behavior Generate Html Links
    if (m_generateLinks) {
        uiBehav.generateLinks->setChecked(true);
    } else {
        uiBehav.generateLinks->setChecked(false);
    }
    uiBehav.syntaxLine->setText(m_syntax4Links);

    UrlGenerator *urlGen = new UrlGenerator;
    urlGen->setProtocol(m_protocol4Links);
    urlGen->setUrl(m_serverAddress);
    urlGen->setSyntax(m_syntax4Links);
    uiBehav.resultLabel->setText(urlGen->dummyUrl());
    connect(urlGen, SIGNAL(dummyUrlGenerated(QString)), uiBehav.resultLabel, SLOT(setText(QString)));
    connect(uiBehav.syntaxLine, SIGNAL(textChanged(QString)), urlGen, SLOT(setSyntax(QString)));
    connect(uiDest.serverAddress, SIGNAL(textChanged(QString)), urlGen, SLOT(setUrl(QString)));
    connect(uiBehav.protocol, SIGNAL(currentIndexChanged(QString)), urlGen, SLOT(setProtocol(QString)));

    //add everything to the settings
    connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
    parent->addPage(widgetDest, i18n("Destination"), Applet::icon());
    parent->addPage(widgetAppear, i18n("Appearance"), QString("video-display"));
    parent->addPage(widgetBehav, i18n("Behavior"), QString("configure"));
}

void Drop2FTP::configAccepted()
{
    KConfigGroup cg = config();
    m_serverAddress = uiDest.serverAddress->text();
    m_serverTitle = uiAppear.serverTitle->text();
    bool isBrowserChecked = uiBehav.useBrowser->isChecked();

    if (uiBehav.copy->isChecked()) {
        m_defaultAction = Drop2FTP::CopyFiles;
    } else if (uiBehav.move->isChecked()) {
        m_defaultAction = Drop2FTP::MoveFiles;
    } else {
        m_defaultAction = Drop2FTP::AskForFiles;
    }

    if (isBrowserChecked != m_useBrowserOnClick) {
        m_useBrowserOnClick = isBrowserChecked;
        disconnect(m_icon, SIGNAL(clicked()), 0, 0);
        if (m_useBrowserOnClick) {
            connect(m_icon, SIGNAL(clicked()), this, SLOT(openDestination()));
        } else {
            connect(m_icon, SIGNAL(clicked()), this, SLOT(openFileDialog()));
        }
        cg.writeEntry("UseBrowserOnClick", m_useBrowserOnClick);
    }

    if (!m_newIcon.isEmpty()) {
        m_iconName = m_newIcon;
        m_icon->setIcon(KIcon(m_iconName));
    }

    if (uiBehav.generateLinks->isChecked()) {
        m_generateLinks = true;
    } else {
        m_generateLinks = false;
    }
    m_protocol4Links = uiBehav.protocol->currentText();
    m_syntax4Links = uiBehav.syntaxLine->text();

    cg.writeEntry("Server", m_serverAddress);
    cg.writeEntry("Title", m_serverTitle);
    cg.writeEntry("IconName", m_iconName);
    cg.writeEntry("DefaultAction", m_defaultAction);
    cg.writeEntry("GenerateLinks", m_generateLinks);
    cg.writeEntry("Protocol4Links", m_protocol4Links);
    cg.writeEntry("Syntax4Links", m_syntax4Links);

    emit configNeedsSaving();
    emit update();
}

void Drop2FTP::traverseBookmarks(const QString &groupAddress, const QString &caller)
{
    Q_UNUSED( groupAddress );
    Q_UNUSED( caller );

    traverseBookmarks();
}

void Drop2FTP::traverseBookmarks()
{
    model->clear();
    QStringList headerLabels;
    headerLabels << i18n("Bookmark") << i18n("URL");
    model->setHorizontalHeaderLabels(headerLabels);
    traverser->traverse( bookmarkManager->root() );
    uiDest.bookmarkTree->expandAll();
}

void Drop2FTP::addBookmarkGroup(QString icon, QString text)
{
    QStandardItem *item = new QStandardItem(KIcon(icon), text);
    item->setEditable(false);
    QStandardItem *dummy = new QStandardItem(); //now I can set editable to false
    dummy->setEditable(false);

    parentItem->appendRow(item);
    parentItem->setChild(item->row(), 1, dummy);
    parentItem = item;
}

void Drop2FTP::addBookmark(QString icon, QString text, KUrl url)
{
    QStandardItem *item = new QStandardItem(KIcon(icon), text);
    item->setEditable(false);
    QStandardItem *urlItem = new QStandardItem(url.url());
    urlItem->setEditable(false);

    parentItem->appendRow(item);
    parentItem->setChild(item->row(), 1, urlItem);
}

void Drop2FTP::leaveBookmarkGroup()
{
    if (parentItem->parent() == 0) {
        parentItem = model->invisibleRootItem();
    } else {
        parentItem = parentItem->parent();
    }
}

void Drop2FTP::copyBookmarkAddress(const QModelIndex &index)
{
    QStandardItem *currentItem = model->itemFromIndex(index);

    //we only want to copy the stuff in the second column
    if(currentItem->column() != 1) {
        int row = currentItem->row();
        QModelIndex childIndex = index.sibling(row, 1);
        currentItem = model->itemFromIndex(childIndex);
    }

    if (currentItem->text().isEmpty()) {
        return;
    }
    emit uiDest.serverAddress->setText(currentItem->text());
}

void Drop2FTP::openIconDialog()
{
    KIconDialog *iDialog = new KIconDialog();
    m_newIcon = iDialog->getIcon();
    if (!m_newIcon.isEmpty()) {
        uiAppear.iconButton->setIcon(KIcon(m_newIcon));
    }
}

void Drop2FTP::slotResult(KJob *job)
{
    m_numActivJobs--;
    if (job->error()) {
        m_icon->setIcon(KIcon("process-stop"));
    } else {
        m_icon->setIcon(KIcon("dialog-ok"));
        if (m_generateLinks) {
            KIO::CopyJob* cJob = qobject_cast<KIO::CopyJob*>(job);

            UrlGenerator *urlGen = new UrlGenerator;
            urlGen->setProtocol(m_protocol4Links);
            urlGen->setUrl(m_serverAddress);
            urlGen->setSyntax(m_syntax4Links);

            QString text;
            text = i18np("Your file is now accessible under:\n\n",
                         "Your files are now accessible under:\n\n",
                         cJob->srcUrls().toStringList().size());
            foreach(QString filename, urlGen->generateUrlList(cJob->srcUrls().toStringList())) {
                filename.prepend("\n");
                text.append(filename);
            }
            KMessageBox::information(0,
                                     text,
                                     i18n("Url List"));
            delete urlGen;
        }
    }
    QTimer::singleShot(3000, this, SLOT(resetIcon()));
    emit update();
}

void Drop2FTP::resetIcon()
{
    if (m_numActivJobs == 0) {
        m_icon->setIcon(KIcon(m_iconName));
    } else {
        m_icon->setIcon(KIcon("view-history"));
    }
    emit update();
}

void Drop2FTP::sendToServer(KUrl::List &src)
{
    const KUrl dest = m_serverAddress;
    /*FIXME check if url is a remote server and if the computer is online
    if (!dest.isLocalFile()) {
        if (Solid::Networking::Status() == Solid::Networking::Connected) {
            kDebug() << "Computer is online";
        } else {
            kDebug() << "Computer is offline";
        }
    }*/
    m_icon->setIcon(KIcon("view-history")); //TODO an animation would be nicer, wouldn't it? (BusyWidget) / icon: process-working

    if (m_defaultAction == Drop2FTP::AskForFiles) {
        QStringList urlList = src.toStringList();
        int messageBoxResult = KMessageBox::warningYesNoCancelList(0,
                                                               i18np("Do you want to copy or to move this file?",
                                                                     "Do you want to copy or to move these %1 files?",
                                                                     urlList.size()),
                                                               urlList,
                                                               i18np("Copy or move file?",
                                                                     "Copy or move files?",
                                                                     urlList.size()),
                                                               KGuiItem(i18np("Copy file",      //ButtonCode::Yes 
                                                                              "Copy files",
                                                                              urlList.size())),
                                                               KGuiItem(i18np("Move file",      //ButtonCode::No
                                                                              "Move files",
                                                                              urlList.size())),
                                                               KStandardGuiItem::cancel(), 
                                                               QString(), 
                                                               KMessageBox::Notify);
       if (messageBoxResult == KMessageBox::Yes) {
           copyToServer(src, dest);
       } else if (messageBoxResult == KMessageBox::No) {
           moveToServer(src, dest);
       } else {
           resetIcon();
       }       
       return;
    }
    if (m_defaultAction == Drop2FTP::CopyFiles) {
        copyToServer(src, dest);
    } else {
        moveToServer(src, dest);
    }
}

void Drop2FTP::copyToServer(const KUrl::List src, const KUrl &dest)
{
    m_numActivJobs++;
    const KJob *cJob = KIO::copy(src, dest);
    connect(cJob, SIGNAL(result(KJob *)), this, SLOT(slotResult(KJob *))); //http://api.kde.org/4.x-api/kdelibs-apidocs/kio/html/classKIO_1_1CopyJob.html
}

void Drop2FTP::moveToServer(const KUrl::List src, const KUrl &dest)
{
    m_numActivJobs++;
    const KJob *mJob = KIO::move(src, dest);
    connect(mJob, SIGNAL(result(KJob *)), this, SLOT(slotResult(KJob *))); //http://api.kde.org/4.x-api/kdelibs-apidocs/kio/html/classKIO_1_1CopyJob.html
}

void Drop2FTP::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
{
    if (event->mimeData()->hasUrls()) {
        event->acceptProposedAction();
    }
}

void Drop2FTP::dropEvent(QGraphicsSceneDragDropEvent *event)
{
    if (m_serverAddress.isEmpty()) {
        emit showConfigurationInterface();
        return;
    }
    if (event->mimeData()->hasUrls()) {
        //The URLs are in QList<QUrl> but we need a KUrl::List
        KUrl::List urlList;
        foreach (KUrl fileName, event->mimeData()->urls()) {
            if (fileName.isLocalFile()) {
                urlList << fileName;
            }
        }
        if (!urlList.isEmpty()) {
            sendToServer(urlList);
        }
    }
    event->acceptProposedAction();
}

#include "drop2ftp.moc"
