/***************************************************************************
 *   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 skrooge plugin to manage scheduled operations.
 *
 * @author Stephane MANKOWSKI
 */
#include "skgscheduledpluginwidget.h"
#include "skgmainpanel.h"
#include "skgtraces.h"
#include "skgdocumentbank.h"
#include "skgobjectmodel.h"
#include "skgrecurrentoperationobject.h"
#include "skgtransactionmng.h"
#include <skgoperationobject.h>

#include <klineedit.h>

#include <QDomDocument>
#include <QHeaderView>
#include <QKeyEvent>

SKGScheduledPluginWidget::SKGScheduledPluginWidget(SKGDocumentBank* iDocument)
    : SKGTabPage(iDocument)
{
    SKGTRACEIN(1, "SKGScheduledPluginWidget::SKGScheduledPluginWidget");
    if (!iDocument) return;

    ui.setupUi(this);

    ui.kView->setModel(new SKGObjectModel(static_cast<SKGDocumentBank*>(getDocument()), "v_recurrentoperation_display", "", this, "", false));

    connect(ui.kView->getView(), SIGNAL(doubleClicked(QModelIndex)), this, SLOT(onDoubleClick()));
    connect(ui.kView->getView(), SIGNAL(selectionChangedDelayed()), this, SLOT(onSelectionChanged()));

    //Add registered global action in contextual menu
    if (SKGMainPanel::getMainPanel()) {
        ui.kView->getView()->insertGlobalAction("edit_delete");
        ui.kView->getView()->insertGlobalAction();

        m_jumpAction = new KAction(KIcon("skg_open"), ui.kJumpBtn->text(), this);
        connect(m_jumpAction, SIGNAL(triggered(bool)), this, SLOT(onJumpToTheOperation()));

        ui.kView->getView()->insertAction(0, m_jumpAction);
    }

    //Add Standard KDE Icons to buttons to Operations
    ui.kModifyBtn->setIcon(KIcon("dialog-ok-apply"));
    ui.kProcessBtn->setIcon(KIcon("system-run"));
    ui.kJumpBtn->setIcon(KIcon("skg_open"));

    ui.kTitle->setPixmap(KIcon("dialog-information").pixmap(22, 22), KTitleWidget::ImageLeft);

    //Set Event filters to catch CTRL+ENTER or SHIFT+ENTER
    this->installEventFilter(this);
}

SKGScheduledPluginWidget::~SKGScheduledPluginWidget()
{
    SKGTRACEIN(1, "SKGScheduledPluginWidget::~SKGScheduledPluginWidget");
}

bool SKGScheduledPluginWidget::eventFilter(QObject* object, QEvent* event)
{
    if (event && event->type() == QEvent::KeyPress) {
        QKeyEvent* keyEvent = (QKeyEvent*) event;
        if ((keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) && object == this) {
            if (QApplication::keyboardModifiers() &Qt::ShiftModifier && ui.kModifyBtn->isEnabled()) {
                ui.kModifyBtn->click();
            }
        }
    }

    return false;
}

QString SKGScheduledPluginWidget::getState()
{
    SKGTRACEIN(10, "SKGScheduledPluginWidget::getState");
    QDomDocument doc("SKGML");
    QDomElement root = doc.createElement("parameters");
    doc.appendChild(root);
    root.setAttribute("view", ui.kView->getState());
    return doc.toString();
}

void SKGScheduledPluginWidget::setState(const QString& iState)
{
    SKGTRACEIN(10, "SKGScheduledPluginWidget::setState");
    QDomDocument doc("SKGML");
    doc.setContent(iState);
    QDomElement root = doc.documentElement();
    ui.kView->setState(root.attribute("view"));
}

QString SKGScheduledPluginWidget::getDefaultStateAttribute()
{
    return "SKGSCHEDULED_DEFAULT_PARAMETERS";
}

QWidget* SKGScheduledPluginWidget::mainWidget() const
{
    return ui.kView->getView();
}

void SKGScheduledPluginWidget::onDoubleClick()
{
    _SKGTRACEIN(10, "SKGScheduledPluginWidget::onDoubleClick");

    //Get selection
    SKGObjectBase::SKGListSKGObjectBase selection = getSelectedObjects();
    if (selection.count() == 1) {
        SKGRecurrentOperationObject recOp(selection.at(0));

        //Build where clause and title
        QString wc = "EXISTS(SELECT 1 FROM recurrentoperation s WHERE s.rd_operation_id=v_operation_display.id and s.id=" % SKGServices::intToString(recOp.getID()) % ") OR r_recurrentoperation_id=" % SKGServices::intToString(recOp.getID());
        QString title = i18nc("Noun, a list of items", "Recurrent operations");

        //Open
        if (QApplication::keyboardModifiers() &Qt::ControlModifier && QApplication::keyboardModifiers() &Qt::ShiftModifier) {
            //Call debug plugin
            QDomDocument doc("SKGML");
            QDomElement root = doc.createElement("parameters");
            doc.appendChild(root);
            root.setAttribute("sqlOrder", "SELECT * from v_operation_display WHERE " % wc);

            SKGMainPanel::getMainPanel()->openPage(SKGMainPanel::getMainPanel()->getPluginByName("Debug plugin"), -1, doc.toString());
        } else {
            //Call operation plugin
            QDomDocument doc("SKGML");
            doc.setContent(getDocument()->getParameter("SKGOPERATION_DEFAULT_PARAMETERS"));
            QDomElement root = doc.documentElement();
            if (root.isNull()) {
                root = doc.createElement("parameters");
                doc.appendChild(root);
            }

            root.setAttribute("operationTable", "v_operation_display");
            root.setAttribute("operationWhereClause", wc);
            root.setAttribute("title", title);
            root.setAttribute("title_icon", "chronometer");
            root.setAttribute("currentPage", "-1");

            SKGMainPanel::getMainPanel()->openPage(SKGMainPanel::getMainPanel()->getPluginByName("Skrooge operation plugin"), -1, doc.toString());
        }
    }
}

void SKGScheduledPluginWidget::onJumpToTheOperation()
{
    //Get selection
    SKGObjectBase::SKGListSKGObjectBase selection = getSelectedObjects();
    if (selection.count() == 1) {
        SKGRecurrentOperationObject recOp(selection.at(0));

        SKGOperationObject op;
        recOp.getParentOperation(op);

        //Build where clause and title
        QString wc = "id=" % SKGServices::intToString(op.getID());
        QString title = i18nc("Noun, a list of items", "Operation of the schedule");

        //Open
        if (QApplication::keyboardModifiers() &Qt::ControlModifier && QApplication::keyboardModifiers() &Qt::ShiftModifier) {
            //Call debug plugin
            QDomDocument doc("SKGML");
            QDomElement root = doc.createElement("parameters");
            doc.appendChild(root);
            root.setAttribute("sqlOrder", "SELECT * from v_operation_display WHERE " % wc);

            SKGMainPanel::getMainPanel()->openPage(SKGMainPanel::getMainPanel()->getPluginByName("Debug plugin"), -1, doc.toString());
        } else {
            //Call operation plugin
            QDomDocument doc("SKGML");
            doc.setContent(getDocument()->getParameter("SKGOPERATION_DEFAULT_PARAMETERS"));
            QDomElement root = doc.documentElement();
            if (root.isNull()) {
                root = doc.createElement("parameters");
                doc.appendChild(root);
            }

            root.setAttribute("operationTable", "v_operation_display");
            root.setAttribute("operationWhereClause", wc);
            root.setAttribute("modeTemplate", op.isTemplate() ?  "Y" : "N");
            root.setAttribute("currentPage", "1");
            root.setAttribute("selection", op.getUniqueID());
            root.setAttribute("title", title);
            root.setAttribute("title_icon", "chronometer");

            SKGMainPanel::getMainPanel()->openPage(SKGMainPanel::getMainPanel()->getPluginByName("Skrooge operation plugin"), -1, doc.toString());
        }
    }
}

void SKGScheduledPluginWidget::onSelectionChanged()
{
    SKGTRACEIN(10, "SKGScheduledPluginWidget::onSelectionChanged");

    int nb = getNbSelectedObjects();
    ui.kFirstOccurenceDate->setEnabled(nb <= 1);
    ui.kModifyBtn->setEnabled(nb);
    ui.kProcessBtn->setEnabled(nb);
    ui.kJumpBtn->setEnabled(nb == 1);
    m_jumpAction->setEnabled(nb == 1);

    if (nb == 1) {
        SKGRecurrentOperationObject recOp = ui.kView->getView()->getFirstSelectedObject();

        ui.kFirstOccurenceDate->setDate(recOp.getDate());
        ui.kOnceEveryVal->setValue(recOp.getPeriodIncrement());
        ui.kOnceEveryUnit->setCurrentIndex((int) recOp.getPeriodUnit());

        ui.kRemindMeVal->setValue(recOp.getWarnDays());
        ui.kRemindMe->setCheckState(recOp.isWarnEnabled() ? Qt::Checked : Qt::Unchecked);

        ui.kAutoWriteVal->setValue(recOp.getAutoWriteDays());
        ui.kAutoWrite->setCheckState(recOp.isAutoWriteEnabled() ? Qt::Checked : Qt::Unchecked);

        ui.kNbTimesVal->setValue(recOp.getTimeLimit());
        ui.kNbTimes->setCheckState(recOp.hasTimeLimit() ? Qt::Checked : Qt::Unchecked);
    }

    Q_EMIT selectionChanged();
}

void SKGScheduledPluginWidget::onNbOccurrenceChanged()
{
    QDate firstDate = ui.kFirstOccurenceDate->date();
    SKGRecurrentOperationObject::PeriodUnit punit = (SKGRecurrentOperationObject::PeriodUnit) ui.kOnceEveryUnit->currentIndex();
    int p = ui.kOnceEveryVal->value();

    if (ui.kLastOccurenceDate == this->sender()) {
        //End date has been modified.
        //We must set the number of occurrence
        QDate lastDate = ui.kLastOccurenceDate->date();
        if (lastDate <= firstDate) {
            ui.kLastOccurenceDate->setDate(firstDate);
            ui.kNbTimesVal->setValue(1);
        } else {
            int nbd = firstDate.daysTo(lastDate);
            if (punit == SKGRecurrentOperationObject::DAY) nbd = nbd / p;
            else if (punit == SKGRecurrentOperationObject::MONTH) {
                nbd = (lastDate.day() >= firstDate.day() ? 0 : -1) + (lastDate.year() - firstDate.year()) * 12 + (lastDate.month() - firstDate.month());
            } else if (punit == SKGRecurrentOperationObject::YEAR) nbd = nbd / (365 * p);

            bool previous = ui.kNbTimesVal->blockSignals(true);
            ui.kNbTimesVal->setValue(nbd + 1);
            ui.kNbTimesVal->blockSignals(previous);
        }

    } else {
        //We must compute the date
        p *= (ui.kNbTimesVal->value() - 1);
        if (punit == SKGRecurrentOperationObject::DAY) firstDate = firstDate.addDays(p);
        else if (punit == SKGRecurrentOperationObject::MONTH) firstDate = firstDate.addMonths(p);
        else if (punit == SKGRecurrentOperationObject::YEAR) firstDate = firstDate.addYears(p);

        bool previous = ui.kLastOccurenceDate->blockSignals(true);
        ui.kLastOccurenceDate->setDate(firstDate);
        ui.kLastOccurenceDate->blockSignals(previous);
    }
}

void SKGScheduledPluginWidget::onUpdate()
{
    SKGError err;
    SKGTRACEINRC(10, "SKGScheduledPluginWidget::onUpdate", err);
    {
        //Get Selection
        SKGObjectBase::SKGListSKGObjectBase selection = getSelectedObjects();

        int nb = selection.count();
        SKGBEGINPROGRESSTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Recurrent operation update"), err, nb);
        for (int i = 0; !err && i < nb; ++i) {
            //Get the real object, not the object from the view
            SKGRecurrentOperationObject recOp = SKGRecurrentOperationObject(selection.at(i).getDocument(), selection.at(i).getID());

            //Update it
            if (nb == 1) err = recOp.setDate(ui.kFirstOccurenceDate->date());
            if (!err) err = recOp.setPeriodIncrement(ui.kOnceEveryVal->value());
            if (!err) err = recOp.setPeriodUnit((SKGRecurrentOperationObject::PeriodUnit) ui.kOnceEveryUnit->currentIndex());
            if (!err) err = recOp.setWarnDays(ui.kRemindMeVal->value());
            if (!err) err = recOp.warnEnabled(ui.kRemindMe->checkState() == Qt::Checked);
            if (!err) err = recOp.setAutoWriteDays(ui.kAutoWriteVal->value());
            if (!err) err = recOp.autoWriteEnabled(ui.kAutoWrite->checkState() == Qt::Checked);
            if (!err) err = recOp.setTimeLimit(ui.kNbTimesVal->value());
            if (!err) err = recOp.timeLimit(ui.kNbTimes->checkState() == Qt::Checked);
            if (!err) err = recOp.save();

            if (!err) err = getDocument()->stepForward(i + 1);
        }
    }
    //status bar
    if (!err) err = SKGError(0, i18nc("Successful message after an user action", "Recurrent operation updated."));
    else err.addError(ERR_FAIL, i18nc("Error message",  "Update failed"));

    //Display error
    SKGMainPanel::displayErrorMessage(err);
}

void SKGScheduledPluginWidget::onProcess()
{
    SKGError err;
    SKGTRACEINRC(10, "SKGScheduledPluginWidget::onProcess", err);
    {
        //Get Selection
        SKGObjectBase::SKGListSKGObjectBase selection = getSelectedObjects();

        int nb = selection.count();
        SKGBEGINPROGRESSTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Insert recurrent operations"), err, nb);
        for (int i = 0; !err && i < nb; ++i) {
            //Get the real object, not the object from the view
            SKGRecurrentOperationObject recOp = SKGRecurrentOperationObject(selection.at(i).getDocument(), selection.at(i).getID());

            //Process it
            int nbi = 0;
            err = recOp.process(nbi, true);
            if (!err) err = getDocument()->stepForward(i + 1);
        }
    }
    //status bar
    if (!err) err = SKGError(0, i18nc("Successful message after an user action", "Recurrent operation inserted."));
    else err.addError(ERR_FAIL, i18nc("Error message",  "Insertion failed"));

    //Display error
    SKGMainPanel::displayErrorMessage(err);
}

#include "skgscheduledpluginwidget.moc"


