/***************************************************************************
 *   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
 * This file is plugin for advice.
 *
 * @author Stephane MANKOWSKI / Guillaume DE BURE
 */
#include "skgadviceboardwidget.h"
#include "skgdocumentbank.h"
#include "skgmainpanel.h"
#include "skgtraces.h"
#include "skgservices.h"
#include "skginterfaceplugin.h"
#include "skgtransactionmng.h"

#include <KMenu>

#include <QDomDocument>
#include <QLayoutItem>
#include <QToolButton>
#include <QPushButton>

SKGAdviceBoardWidget::SKGAdviceBoardWidget(SKGDocument* iDocument)
    : SKGWidget(iDocument), m_maxAdvice(7), m_refreshNeeded(true)
{
    SKGTRACEIN(10, "SKGAdviceBoardWidget::SKGAdviceBoardWidget");

    ui.setupUi(this);

    //Create menu
    setContextMenuPolicy(Qt::ActionsContextMenu);

    KAction* menuResetAdvices = new KAction(KIcon("edit-undo"), i18nc("Noun, a user action", "Activate all advices"), this);
    connect(menuResetAdvices, SIGNAL(triggered(bool)), this, SLOT(activateAllAdvices()));
    addAction(menuResetAdvices);

    //Refresh
    connect((const QObject*) getDocument(), SIGNAL(transactionSuccessfullyEnded(int)), this, SLOT(dataModified()), Qt::QueuedConnection);
    connect(SKGMainPanel::getMainPanel(), SIGNAL(currentPageChanged()), this, SLOT(pageChanged()), Qt::QueuedConnection);
    connect(this, SIGNAL(refreshNeeded()), this, SLOT(dataModified()), Qt::QueuedConnection);
}

SKGAdviceBoardWidget::~SKGAdviceBoardWidget()
{
    SKGTRACEIN(10, "SKGAdviceBoardWidget::~SKGAdviceBoardWidget");
}

QString SKGAdviceBoardWidget::getState()
{
    QDomDocument doc("SKGML");
    QDomElement root = doc.createElement("parameters");
    doc.appendChild(root);
    root.setAttribute("maxAdvice", SKGServices::intToString(m_maxAdvice));
    return doc.toString();
}

void SKGAdviceBoardWidget::setState(const QString& iState)
{
    QDomDocument doc("SKGML");
    doc.setContent(iState);
    QDomElement root = doc.documentElement();

    QString maxAdviceS = root.attribute("maxAdvice");
    if (maxAdviceS.isEmpty()) maxAdviceS = '7';
    m_maxAdvice = SKGServices::stringToInt(maxAdviceS);

    dataModified(true);
}

void SKGAdviceBoardWidget::pageChanged()
{
    if (m_refreshNeeded) dataModified();
}

void SKGAdviceBoardWidget::dataModified(bool iForce)
{
    SKGTRACEIN(10, "SKGAdviceBoardWidget::dataModified");
    SKGTabPage* page = SKGTabPage::parentTabPage(this);
    if (!iForce && page != NULL && page != SKGMainPanel::getMainPanel()->currentPage()) {
        m_refreshNeeded = true;
        return;
    }
    QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
    m_refreshNeeded = false;

    //Remove all item of the layout
    QLayoutItem* child = NULL;
    while ((child = ui.layout->takeAt(0)) != 0) {
        QWidget* w = child->widget();
        delete w;
        delete child;
    }

    //Get list of advices
    SKGAdviceList globalAdvicesList = SKGMainPanel::getMainPanel()->getAdvices();

    //Fill layout
    int nbDisplayedAdvice = 0;
    int nb = globalAdvicesList.count();
    for (int i = 0; i < m_maxAdvice && i < nb; ++i) {
        //Get advice
        SKGAdvice ad = globalAdvicesList.at(i);

        //Create icon
        QString iconName = (ad.getPriority() == -1 ? "dialog-information" : ad.getPriority() >= 8 ? "security-low" : ad.getPriority() <= 4 ? "security-high" : "security-medium");
        QString toolTip = i18n("<p><b>Priority %1:</b>%2</p>", SKGServices::intToString(ad.getPriority()), ad.getLongMessage());

        //Add ignored action
        QStringList autoCorrections = ad.getAutoCorrections();
        autoCorrections.push_back(i18nc("Dismiss an advice provided", "Dismiss"));
        autoCorrections.push_back(i18nc("Dismiss an advice provided", "Dismiss during current month"));
        autoCorrections.push_back(i18nc("Dismiss an advice provided", "Dismiss this kind"));
        autoCorrections.push_back(i18nc("Dismiss an advice provided", "Dismiss this kind during current month"));

        int nbSolution = autoCorrections.count();

        //Build button
        QStringList overlays;
        overlays.push_back(nbSolution > 2 ? "system-run" : "edit-delete");
        QToolButton*  icon = new QToolButton(this);
        icon->setObjectName(ad.getUUID());
        icon->setIcon(KIcon(iconName, NULL, overlays));
        icon->setIconSize(QSize(22, 22));
        icon->setMaximumSize(QSize(22, 22));
        icon->setCursor(Qt::PointingHandCursor);
        icon->setAutoRaise(true);

        KMenu* menu = new KMenu(this);
        menu->setIcon(icon->icon());
        for (int k = 0; k < nbSolution; ++k) {
            QAction* act = menu->addAction(KIcon(k < nbSolution - 4 ?  "system-run" : "edit-delete"), autoCorrections.at(k), this, SLOT(adviceClicked()));
            if (act) {
                act->setProperty("id", ad.getUUID());
                act->setProperty("solution", k < nbSolution - 4 ? k : k - nbSolution);
            }
        }

        icon->setMenu(menu);
        icon->setPopupMode(QToolButton::InstantPopup);

        icon->setToolTip(toolTip);

        //Create text
        QLabel* label = new QLabel(this);
        label->setText(ad.getShortMessage());
        label->setToolTip(toolTip);

        //Add them
        ui.layout->addRow(icon, label);

        ++nbDisplayedAdvice;
    }

    //Add more
    if (nb > m_maxAdvice) {
        QPushButton*  more = new QPushButton(this);
        more->setIcon(KIcon("arrow-down-double"));
        more->setIconSize(QSize(22, 22));
        more->setMaximumSize(QSize(22, 22));
        more->setCursor(Qt::PointingHandCursor);
        connect(more, SIGNAL(clicked(bool)), this, SLOT(moreAdvice()), Qt::QueuedConnection);

        ui.layout->addRow(more, new QLabel(this));
    } else if (nbDisplayedAdvice > 7) {
        //Add less
        QPushButton*  less = new QPushButton(this);
        less->setIcon(KIcon("arrow-up-double"));
        less->setIconSize(QSize(22, 22));
        less->setMaximumSize(QSize(22, 22));
        less->setCursor(Qt::PointingHandCursor);
        connect(less, SIGNAL(clicked(bool)), this, SLOT(lessAdvice()), Qt::QueuedConnection);

        ui.layout->addRow(less, new QLabel(this));
    }


    //Add spacer
    ui.layout->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding));
    QApplication::restoreOverrideCursor();
}

void SKGAdviceBoardWidget::moreAdvice()
{
    m_maxAdvice = 9999999;
    dataModified();
}

void SKGAdviceBoardWidget::lessAdvice()
{
    m_maxAdvice = 7;
    dataModified();
}

void SKGAdviceBoardWidget::activateAllAdvices()
{
    SKGError err;
    {
        SKGBEGINTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Activate all advices"), err);
        err = getDocument()->executeSqliteOrder("DELETE FROM parameters WHERE t_uuid_parent='advices'");
    }

    //status bar
    if (!err) err = SKGError(0, i18nc("Successful message after an user action", "Advices activated."));
    else err.addError(ERR_FAIL, i18nc("Error message",  "Advices activation failed"));

    SKGMainPanel::displayErrorMessage(err);
}

void SKGAdviceBoardWidget::adviceClicked()
{
    //Get advice identifier
    QString uuid = sender()->property("id").toString();
    if (!uuid.isEmpty()) {
        //Get solution clicker
        int solution = sender()->property("solution").toInt();

        if (solution < 0) {
            //We have to ignore this advice
            SKGError err;
            {
                SKGBEGINLIGHTTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Dismiss advice"), err);
                QString currentMonth = QDate::currentDate().toString("yyyy-MM");

                //Create dismiss
                if (solution == -1 || solution == -2) uuid = SKGServices::splitCSVLine(uuid, '|').at(0);
                err = getDocument()->setParameter(uuid, solution == -2 || solution == -4 ? "I" : QString("I_" % currentMonth), QVariant(), "advices");

                //Delete useless dismiss
                if (!err)err = getDocument()->executeSqliteOrder("DELETE FROM parameters WHERE t_uuid_parent='advices' AND t_value like 'I_ % ' AND t_value!='I_" % currentMonth % '\'');
            }

            //status bar
            if (!err) err = SKGError(0, i18nc("Successful message after an user action", "Advice dismissed."));
            else err.addError(ERR_FAIL, i18nc("Error message",  "Advice dismiss failed"));
        } else {
            //Get last transaction id
            int previous = getDocument()->getTransactionToProcess();

            //Execute the advice correction on all plugin
            QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
            int index = 0;
            while (index >= 0) {
                SKGInterfacePlugin* plugin = SKGMainPanel::getMainPanel()->getPluginByIndex(index);
                if (plugin) {
                    SKGError err = plugin->executeAdviceCorrection(uuid, solution);
                    if (!err || err.getReturnCode() != ERR_NOTIMPL) {
                        //The correction has been done or failed. This is the end.
                        index = -2;
                    }
                } else index = -2;
                ++index;
            }

            //Get last transaction id
            int next = getDocument()->getTransactionToProcess();

            //If this is the same transaction, it means that an action has been done outside the document ==> a refresh is needed
            if (next == previous) emit refreshNeeded();

            QApplication::restoreOverrideCursor();
        }
    }
}

#include "skgadviceboardwidget.moc"
