/***************************************************************************
 *   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 Skrooge plugin to generate categories.
 *
 * @author Stephane MANKOWSKI / Guillaume DE BURE
 */
#include "skgcategoriespluginwidget.h"

#include <KLocale>
#include <KAction>

#include <QDomDocument>
#include <QtGui/QWidget>
#include <QGraphicsScene>
#include <QHeaderView>
#include <QKeyEvent>

#include "skgmainpanel.h"
#include "skgtraces.h"
#include "skgobjectmodel.h"
#include "skgsortfilterproxymodel.h"
#include "skgdocumentbank.h"
#include "skgcategoryobject.h"
#include "skgtransactionmng.h"

SKGCategoriesPluginWidget::SKGCategoriesPluginWidget(SKGDocumentBank* iDocument)
    : SKGTabPage(iDocument)
{
    SKGTRACEINFUNC(10);
    if (!iDocument) {
        return;
    }

    ui.setupUi(this);

    // Set show widget
    ui.kCategoriesView->getShowWidget()->addGroupedItem("all", i18n("All"), "", "", "", Qt::META + Qt::Key_A);
    ui.kCategoriesView->getShowWidget()->addGroupedItem("income", i18n("Income"), "list-add", "f_REALCURRENTAMOUNT>=0", "", Qt::META + Qt::Key_Plus);
    ui.kCategoriesView->getShowWidget()->addGroupedItem("expenditure", i18n("Expenditure"), "list-remove", "f_REALCURRENTAMOUNT<=0", "", Qt::META + Qt::Key_Minus);
    ui.kCategoriesView->getShowWidget()->addGroupedItem("highlighted", i18n("Highlighted"), "bookmarks", "t_HASBOOKMARKEDCHILD<>'N'", "", Qt::META + Qt::Key_H);
    ui.kCategoriesView->getShowWidget()->setDefaultState("all");

    ui.kAdd->setMaximumWidth(ui.kAdd->height());

    ui.kNameLbl->setText(i18n("%1:", iDocument->getDisplay("t_name")));

    ui.kModifyCategoryButton->setIcon(KIcon("dialog-ok-apply"));
    ui.kDeleteUnusedButton->setIcon(KIcon("edit-delete"));

    ui.kCategoriesView->setModel(new SKGObjectModel(static_cast<SKGDocumentBank*>(getDocument()), "v_category_display", "1=0", this, "rd_category_id", false));
    ui.kCategoriesView->getView()->setRootIsDecorated(true);
    ui.kCategoriesView->getView()->setAnimated(false);  // Not compatible with double click
    ui.kCategoriesView->getView()->resizeColumnToContents(0);
    ui.kCategoriesView->getView()->header()->setStretchLastSection(false);

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

        QStringList overlaycategories;
        overlaycategories.push_back("skrooge_category");
        KAction* addCategoryAction = new KAction(KIcon("list-add", NULL, overlaycategories), i18nc("Verb", "Add category"), this);
        connect(addCategoryAction, SIGNAL(triggered(bool)), this, SLOT(onAddCategory()));

        ui.kAdd->setIcon(KIcon("list-add", NULL, overlaycategories));

        ui.kCategoriesView->getView()->insertAction(0, addCategoryAction);
    }

    connect(getDocument(), SIGNAL(tableModified(QString,int,bool)), this, SLOT(dataModified(QString,int,bool)), Qt::QueuedConnection);
    connect(ui.kCategoriesView->getView(), SIGNAL(clickEmptyArea()), this, SLOT(cleanEditor()));
    connect(ui.kCategoriesView->getView(), SIGNAL(doubleClicked(QModelIndex)), SKGMainPanel::getMainPanel()->getGlobalAction("open"), SLOT(trigger()));
    connect(ui.kCategoriesView->getView(), SIGNAL(selectionChangedDelayed()), this, SLOT(onSelectionChanged()));

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

    dataModified("", 0);
}

SKGCategoriesPluginWidget::~SKGCategoriesPluginWidget()
{
    SKGTRACEINFUNC(10);
}

bool SKGCategoriesPluginWidget::eventFilter(QObject* iObject, QEvent* iEvent)
{
    if (iEvent && iEvent->type() == QEvent::KeyPress) {
        QKeyEvent* keyEvent = static_cast<QKeyEvent*>(iEvent);
        if ((keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) && iObject == this) {
            if (QApplication::keyboardModifiers() &Qt::ControlModifier && ui.kAdd->isEnabled()) {
                ui.kAdd->click();
            } else if (QApplication::keyboardModifiers() &Qt::ShiftModifier && ui.kModifyCategoryButton->isEnabled()) {
                ui.kModifyCategoryButton->click();
            }
        }
    }

    return false;
}

void SKGCategoriesPluginWidget::dataModified(const QString& iTableName, int iIdTransaction, bool iLightTransaction)
{
    SKGTRACEINFUNC(10);
    Q_UNUSED(iIdTransaction);

    if (!iLightTransaction) {
        if (iTableName == "category" || iTableName.isEmpty()) {
            // Set completions
            SKGMainPanel::fillWithDistinctValue(ui.kNameInput1, getDocument(), "category", "t_name", "", true);

            onSelectionChanged();
        }
    }
}

void SKGCategoriesPluginWidget::onSelectionChanged()
{
    SKGTRACEINFUNC(10);
    // Clean widgets
    int nb = ui.kLayout->count();
    for (int i = 0; i < nb; ++i) {
        QLayoutItem* item = ui.kLayout->itemAt(0);
        if (item) {
            ui.kLayout->removeItem(item);
            delete item->widget();
            delete item;
        }
    }

    int nbSelect = getNbSelectedObjects();
    if (nbSelect == 1) {
        SKGCategoryObject obj(getFirstSelectedObject());
        ui.kNameInput1->setText(obj.getName());

        SKGCategoryObject parentCat;
        obj.getParentCategory(parentCat);
        QString parentName = parentCat.getFullName();

        QStringList items = SKGServices::splitCSVLine(parentName, QString(OBJECTSEPARATOR).trimmed().at(0));
        int nbItems = items.count();
        QString fullname;
        for (int i = 0; i < nbItems; ++i) {
            KPushButton* btn = new KPushButton(ui.kFrame);
            btn->setFlat(true);
            btn->setText(items.at(i).trimmed());
            if (!fullname.isEmpty()) {
                fullname += OBJECTSEPARATOR;
            }
            fullname += items.at(i).trimmed();
            btn->setProperty("FULLNAME", fullname);
            connect(btn, SIGNAL(clicked()), this, SLOT(changeSelection()));
            ui.kLayout->addWidget(btn);

            QLabel* lbl = new QLabel(ui.kFrame);
            lbl->setText(OBJECTSEPARATOR);
            ui.kLayout->addWidget(lbl);
        }
    } else if (nbSelect > 1) {
        ui.kNameInput1->setText(NOUPDATE);
    }

    onEditorModified();
    Q_EMIT selectionChanged();
}

void SKGCategoriesPluginWidget::changeSelection()
{
    QString fullname = sender()->property("FULLNAME").toString();
    SKGObjectBase::SKGListSKGObjectBase list;
    getDocument()->getObjects("v_category", "t_fullname='" % SKGServices::stringToSqlString(fullname) % '\'', list);

    if (list.count()) {
        ui.kCategoriesView->getView()->selectObject(list.at(0).getUniqueID());
        onSelectionChanged();
    }
}

QString SKGCategoriesPluginWidget::getState()
{
    SKGTRACEINFUNC(10);
    QDomDocument doc("SKGML");
    QDomElement root = doc.createElement("parameters");
    doc.appendChild(root);

    // Memorize table settings
    root.setAttribute("view", ui.kCategoriesView->getState());
    return doc.toString();
}

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

    ui.kCategoriesView->setFilter(KIcon(root.attribute("title_icon")), root.attribute("title"), root.attribute("whereClause"));
    ui.kCategoriesView->setState(root.attribute("view"));
}

QString SKGCategoriesPluginWidget::getDefaultStateAttribute()
{
    return "SKGCATEGORIES_DEFAULT_PARAMETERS";
}

QWidget* SKGCategoriesPluginWidget::mainWidget()
{
    return ui.kCategoriesView->getView();
}

void SKGCategoriesPluginWidget::onEditorModified()
{
    _SKGTRACEINFUNC(10);
    int nb = getNbSelectedObjects();
    ui.kModifyCategoryButton->setEnabled(!ui.kNameInput1->text().isEmpty() && nb >= 1);
}

void SKGCategoriesPluginWidget::onAddCategory()
{
    SKGError err;
    _SKGTRACEINFUNCRC(10, err);
    SKGCategoryObject cat;
    QString name = ui.kNameInput1->text();
    if (name.isEmpty()) {
        name = i18nc("Noun, default name for a new category", "New category");
    }
    {
        // Get Selection
        SKGObjectBase::SKGListSKGObjectBase selection = getSelectedObjects();

        int nb = selection.count();
        SKGBEGINTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Category creation '%1'", name)  , err);

        if (nb == 1) {
            SKGCategoryObject parentCat(selection[0]);
            name = parentCat.getFullName() % OBJECTSEPARATOR % name;
        }
        IFOKDO(err, SKGCategoryObject::createPathCategory(static_cast<SKGDocumentBank*>(getDocument()), name, cat, false, true))

        // Send message
        IFOKDO(err, cat.getDocument()->sendMessage(i18nc("An information message", "The category '%1' has been created", cat.getDisplayName()), SKGDocument::Hidden));
    }

// status bar
    IFOK(err) {
        ui.kCategoriesView->getView()->selectObject(cat.getUniqueID());
        err = SKGError(0, i18nc("Successful message after an user action", "Category '%1' created", name));
    } else {
        err.addError(ERR_FAIL, i18nc("Error message", "Category creation failed"));
    }

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

void SKGCategoriesPluginWidget::onUpdateCategory()
{
    SKGError err;
    _SKGTRACEINFUNCRC(10, err);
    // Get Selection
    SKGObjectBase::SKGListSKGObjectBase selection = getSelectedObjects();

    int nb = selection.count();
    {
        QString name = ui.kNameInput1->text();
        SKGBEGINPROGRESSTRANSACTION(*getDocument(), i18nc("Noun, name of the user action", "Category update")  , err, nb);
        if (nb > 1 && name != NOUPDATE && !name.startsWith(QLatin1String("="))) {
            getDocument()->sendMessage(i18nc("Information message", "You tried to modify all names of selected categories. Categories have been merged."));

            // Do the merge
            SKGCategoryObject catObj1(selection[0]);
            for (int i = 1; !err && i < nb; ++i) {
                SKGCategoryObject catObj(selection[i]);

                // Send message
                IFOKDO(err, catObj.getDocument()->sendMessage(i18nc("An information message", "The category '%1' has been merged with category '%2'", catObj1.getDisplayName(), catObj.getDisplayName()), SKGDocument::Hidden));

                IFOKDO(err, catObj1.merge(catObj))

                IFOKDO(err, getDocument()->stepForward(i))
            }

            // Change selection for the rest of the operation
            selection.clear();
            selection.push_back(catObj1);
            nb = 1;
        }

        for (int i = 0; !err && i < nb; ++i) {
            // Modification of object
            SKGCategoryObject cat(selection[i]);
            err = cat.setName(name);
            IFOKDO(err, cat.save())

            // Send message
            IFOKDO(err, cat.getDocument()->sendMessage(i18nc("An information message", "The category '%1' has been updated", cat.getDisplayName()), SKGDocument::Hidden));
        }
    }
    // status bar
    IFOKDO(err, SKGError(0, i18nc("Successful message after an user action", "Category updated")))
    else {
        err.addError(ERR_FAIL, i18nc("Error message", "Category update failed"));
    }

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

void SKGCategoriesPluginWidget::onDeleteUnused()
{
    QAction* act = SKGMainPanel::getMainPanel()->getGlobalAction("clean_delete_unused_categories");
    if (act) {
        act->trigger();
    }
}

void SKGCategoriesPluginWidget::cleanEditor()
{
    if (getNbSelectedObjects() == 0) {
        ui.kNameInput1->setText("");
    }
}
void SKGCategoriesPluginWidget::activateEditor()
{
    ui.kNameInput1->setFocus();
}

bool SKGCategoriesPluginWidget::isEditor()
{
    return true;
}

#include "skgcategoriespluginwidget.moc"
