/***************************************************************************
 *   Copyright (C) 2008 by S. MANKOWSKI / G. DE BURE support@mankowski.fr  *
 *                                                                         *
 *   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, see <http://www.gnu.org/licenses/>  *
 ***************************************************************************/
/** @file
 * A plugin to manage properties on objects
 *
 * @author Stephane MANKOWSKI
 */
#include "skgpropertiesplugin.h"

#include <QDockWidget>
#include <QDir>

#include <KActionCollection>
#include <KStandardAction>
#include <KToolBarPopupAction>
#include <KAboutData>
#include <KGenericFactory>

#include "skgpropertiesplugindockwidget.h"
#include "skgtraces.h"
#include "skgmainpanel.h"
#include "skgtransactionmng.h"

/**
 * This plugin factory.
 */
K_PLUGIN_FACTORY(SKGPropertiesPluginFactory, registerPlugin<SKGPropertiesPlugin>();)
/**
 * This plugin export.
 */
K_EXPORT_PLUGIN(SKGPropertiesPluginFactory("skg_properties", "skg_properties"))

SKGPropertiesPlugin::SKGPropertiesPlugin(QWidget* iWidget, QObject* iParent, const QVariantList& /*iArg*/) :
    SKGInterfacePlugin(iParent),
    m_currentDocument(NULL), m_dockWidget(NULL), m_dockContent(NULL), m_addPropertyAction(NULL), m_addPropertyMenu(NULL)
{
    Q_UNUSED(iWidget);
    SKGTRACEINFUNC(10);

    // Get list of bills
    m_billsProcess.setStandardOutputFile(QDir::tempPath() % "/skg_bills.csv");
    m_billsProcess.start("boobill bills  -q -f csv -v");

    connect(&m_billsProcess, SIGNAL(finished(int)), this, SLOT(onBillsRetreived()));
    connect(&m_billsProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(onBillsRetreived()));
}

SKGPropertiesPlugin::~SKGPropertiesPlugin()
{
    SKGTRACEINFUNC(10);
    m_currentDocument = NULL;
    m_dockWidget = NULL;
    m_dockContent = NULL;
    m_addPropertyMenu = NULL;
    m_addPropertyAction = NULL;

    if (m_billsProcess.state() == QProcess::Running) {
        m_billsProcess.kill();
    }
}

void SKGPropertiesPlugin::onBillsRetreived()
{
    QFile file(QDir::tempPath() % "/skg_bills.csv");
    if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        QTextStream stream(&file);
        stream.readLine();  // To avoid header id;date;format;label;idparent;price;currency;deadline;startdate;finishdate
        while (!stream.atEnd()) {
            // Read line
            QString line = stream.readLine().trimmed();

            m_bills.push_back(line);
        }

        // close file
        file.close();
    }
    file.remove();
}

bool SKGPropertiesPlugin::setupActions(SKGDocument* iDocument, const QStringList& iArgument)
{
    SKGTRACEINFUNC(10);
    Q_UNUSED(iArgument);

    m_currentDocument = iDocument;

    setComponentData(KGlobal::mainComponent());
    setXMLFile("../skg_properties/skg_properties.rc");

    m_dockContent = new SKGPropertiesPluginDockWidget(m_currentDocument);
    if (m_dockContent) {
        m_dockWidget = new QDockWidget(SKGMainPanel::getMainPanel());
        if (m_dockWidget) {
            m_dockWidget->setObjectName(QString::fromUtf8("skg_properties_docwidget"));
            m_dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
            m_dockWidget->setWindowTitle(title());
            m_dockWidget->setWidget(m_dockContent);

            // add action to control hide / display of Bookmarks
            QAction* toggle = m_dockWidget->toggleViewAction();
            KAction* panelAction = actionCollection()->addAction("view_properties");
            registerGlobalAction("view_properties", panelAction);
            panelAction->setCheckable(true);
            panelAction->setChecked(toggle->isChecked());
            panelAction->setText(toggle->text());
            panelAction->setShortcut(Qt::SHIFT + Qt::Key_F12);
            connect(panelAction, SIGNAL(triggered()), toggle, SLOT(trigger()));
            connect(toggle, SIGNAL(toggled(bool)), panelAction, SLOT(setChecked(bool)));
        }
    }

    // Menu
    m_addPropertyAction = new KToolBarPopupAction(KIcon("feed-subscribe"), i18nc("Allows user to add a user defined property on an object", "Add property"), this);
    m_addPropertyMenu = static_cast<KMenu*>(m_addPropertyAction->menu());
    connect(m_addPropertyMenu , SIGNAL(aboutToShow()), this, SLOT(onShowAddPropertyMenu()));
    m_addPropertyAction->setStickyMenu(false);
    m_addPropertyAction->setDelayed(false);
    registerGlobalAction("add_property", m_addPropertyAction);
    return true;
}

void SKGPropertiesPlugin::onAddProperty()
{
    SKGTRACEINFUNC(10);
    SKGError err;
    // Scope for the transaction
    QAction* act = qobject_cast<QAction*>(sender());
    if (act && m_currentDocument) {
        // Get parameters
        QStringList list = act->data().toStringList();
        QString name = list.at(0);
        QString value = list.at(1);

        // Create properties
        IFOK(err) {
            SKGObjectBase::SKGListSKGObjectBase selection = SKGMainPanel::getMainPanel()->getSelectedObjects();
            int nb = selection.count();
            SKGBEGINPROGRESSTRANSACTION(*m_currentDocument, i18nc("Create a user defined property", "Property creation"), err, nb);
            for (int i = 0; !err && i < nb; ++i) {
                err = selection[i].setProperty(name, value);
                IFOKDO(err, m_currentDocument->stepForward(i + 1))
            }
        }
    }

    // status bar
    IFOK(err) {
        err = SKGError(0, i18nc("The user defined property was successfully created", "Property created"));
    }
    SKGMainPanel::displayErrorMessage(err);
}

void SKGPropertiesPlugin::onDownloadAndAddBills()
{
    SKGTRACEINFUNC(10);
    SKGError err;
    // Scope for the transaction
    QAction* act = qobject_cast<QAction*>(sender());
    if (act && m_currentDocument) {
        // Get parameters
        QStringList list = act->data().toStringList();
        QString id = list.at(0);
        QString fileName = QDir::tempPath() % '/' % list.at(3) % '.' % list.at(2);

        // Create properties
        IFOK(err) {
            SKGObjectBase::SKGListSKGObjectBase selection = SKGMainPanel::getMainPanel()->getSelectedObjects();
            int nb = selection.count();
            SKGBEGINPROGRESSTRANSACTION(*m_currentDocument, i18nc("Create a user defined property", "Property creation"), err, 2 * nb);
            for (int i = 0; !err && i < nb; ++i) {
                // Download the files
                QFile::remove(fileName);
                QString cmd = "boobill download " % id % " \"" % fileName % '"';
                QProcess p;
                p.start(cmd);
                if (!p.waitForFinished(60000) || p.exitCode() != 0) {
                    err.setReturnCode(ERR_FAIL).setMessage(i18nc("Error message",  "The following command line failed:\n'%1'", cmd));
                } else {
                    IFOKDO(err, m_currentDocument->stepForward(2 * i))

                    IFOKDO(err, selection[i].setProperty(i18nc("Noun", "Bill"), id, fileName))
                    QStringList importedBills = SKGServices::splitCSVLine(m_currentDocument->getParameter("SKG_IMPORTED_BILLS"));
                    importedBills.push_back(id);
                    IFOKDO(err, m_currentDocument->setParameter("SKG_IMPORTED_BILLS", SKGServices::stringsToCsv(importedBills)))
                    IFOKDO(err, m_currentDocument->stepForward(2 * i + 1))

                    QFile::remove(fileName);
                }
            }
        }
    }

    // status bar
    IFOK(err) {
        err = SKGError(0, i18nc("The user defined property was successfully created", "Property created"));
    }
    SKGMainPanel::displayErrorMessage(err);
}


void SKGPropertiesPlugin::onShowAddPropertyMenu()
{
    if (m_addPropertyMenu && m_currentDocument) {
        m_addPropertyMenu->clear();

        // Get selection
        SKGObjectBase::SKGListSKGObjectBase sels = SKGMainPanel::getMainPanel()->getSelectedObjects();
        if (sels.count()) {
            // Get the table of the selection
            QString table = sels.at(0).getRealTable();

            // Get list of more used properties for this table
            SKGStringListList listTmp;
            m_currentDocument->executeSelectSqliteOrder(
                "SELECT t_name, t_value FROM (SELECT t_name, t_value, COUNT(1) AS nb FROM parameters WHERE (t_uuid_parent like '%-" % table % "' OR t_uuid_parent like '%-sub" % table % "') AND t_name NOT LIKE 'SKG_%' AND b_blob IS NULL GROUP BY t_name, t_value) ORDER BY nb DESC LIMIT 7",
                listTmp);

            // Create actions
            int nb = listTmp.count();
            KIcon iconp("feed-subscribe");
            for (int i = 1; i < nb; ++i) {
                // Should the string below be translated ??? It contains no word...
                QAction* act = m_addPropertyMenu->addAction(iconp, i18nc("Add a property (attribute=value)", "Add %1=%2", listTmp.at(i).at(0), listTmp.at(i).at(1)));
                if (act) {
                    act->setData(listTmp.at(i));
                    connect(act, SIGNAL(triggered()), this, SLOT(onAddProperty()));
                }
            }

            // Check if the sub process is still running
            if (m_billsProcess.state() == QProcess::Running) {
                // Create separator
                {
                    QAction* act = m_addPropertyMenu->addAction("");
                    act->setSeparator(true);
                }

                // Add download on going
                QAction* act = m_addPropertyMenu->addAction(i18nc("Message", "Download list of available bills on going..."));
                if (act) {
                    act->setEnabled(false);
                }

            } else {
                // Check if some bills can be downloaded
                int nb2 = m_bills.count();
                if (nb2) {
                    // Create separator
                    {
                        QAction* act = m_addPropertyMenu->addAction("");
                        act->setSeparator(true);
                    }

                    // Create action
                    QStringList importedBills = SKGServices::splitCSVLine(m_currentDocument->getParameter("SKG_IMPORTED_BILLS"));

                    KMenu* menuMore = NULL;
                    KIcon icond("feed-subscribe", NULL, QStringList() << "download");
                    QSet<QString> backendDone;
                    for (int j = 1; j < nb2; ++j) {
                        // id;date;format;label;idparent;price;currency;deadline;startdate;finishdate
                        QStringList fields = SKGServices::splitCSVLine(m_bills.at(j));
                        if (fields.count() && fields.count() > 3 && !importedBills.contains(fields.at(0))) {
                            QStringList ids = SKGServices::splitCSVLine(fields.at(0), '@');
                            if (ids.count() == 2) {
                                QString backend = ids.at(1);

                                // Selection of the menu where the item must be added
                                KMenu* menu;
                                if (!backendDone.contains(backend)) {
                                    // This item must be added in root menu
                                    menu = m_addPropertyMenu;
                                    backendDone.insert(backend);
                                } else {
                                    // This item must be added in "More..." menu
                                    if (menuMore == NULL) {
                                        menuMore = new KMenu(i18nc("Noun", "More..."), m_addPropertyMenu);
                                    }
                                    menu = menuMore;
                                }

                                // Should the string below be translated ??? It contains no word...
                                QAction* act = menu->addAction(icond, i18nc("Add a property (attribute=value)", "Download and add %1 (%2)", fields[3] % '.' % fields[2], fields[0]));
                                if (act) {
                                    act->setToolTip(fields[0]);
                                    act->setData(fields);
                                    connect(act, SIGNAL(triggered()), this, SLOT(onDownloadAndAddBills()));
                                }
                            }
                        }
                    }

                    // Add "More..." menu
                    if (menuMore) {
                        m_addPropertyMenu->addMenu(menuMore);
                    }
                }
            }
        }
    }
}

void SKGPropertiesPlugin::refresh()
{
    SKGTRACEINFUNC(10);
    if (m_dockContent) {
        m_dockContent->refresh();
    }
    if (m_addPropertyAction && SKGMainPanel::getMainPanel()) {
        m_addPropertyAction->setEnabled(SKGMainPanel::getMainPanel()->getSelectedObjects().count() > 0);
    }
}

QDockWidget* SKGPropertiesPlugin::getDockWidget()
{
    return m_dockWidget;
}

QString SKGPropertiesPlugin::title() const
{
    return i18nc("Noun, an item's properties", "Properties");
}

int SKGPropertiesPlugin::getOrder() const
{
    return 6;
}

QStringList SKGPropertiesPlugin::tips() const
{
    QStringList output;
    output.push_back(i18nc("Description of a tip", "<p>... you can manage properties on all objects.</p>"));
    output.push_back(i18nc("Description of a tip", "<p>... you can add files or Internet links as property.</p>"));
    output.push_back(i18nc("Description of a tip", "<p>... you can automatically download and add bills as properties by using %1.</p>", "weboob"));
    return output;
}

#include "skgpropertiesplugin.moc"
