/***************************************************************************
 *   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 "skgcategoriesplugin.h"
#include "skgcategoriespluginwidget.h"
#include "skgcategoriesboardwidget.h"
#include "skgtraces.h"
#include "skgmainpanel.h"
#include "skgtransactionmng.h"
#include "skgcategoryobject.h"
#include "skgdocumentbank.h"

#include <kmessagebox.h>
#include <kactioncollection.h>
#include <kaction.h>
#include <kaboutdata.h>

/**
 * This plugin factory.
 */
K_PLUGIN_FACTORY(SKGCategoriesPluginFactory, registerPlugin<SKGCategoriesPlugin>(););
/**
 * This plugin export.
 */
K_EXPORT_PLUGIN(SKGCategoriesPluginFactory("skrooge_categories", "skrooge_categories"));

SKGCategoriesPlugin::SKGCategoriesPlugin(QObject* iParent, const QVariantList& /*iArg*/)
    : SKGInterfacePlugin(iParent), m_currentBankDocument(NULL), m_importStdCatAction(NULL)
{
    SKGTRACEIN(10, "SKGCategoriesPlugin::SKGCategoriesPlugin");
}

SKGCategoriesPlugin::~SKGCategoriesPlugin()
{
    SKGTRACEIN(10, "SKGCategoriesPlugin::~SKGCategoriesPlugin");
    m_currentBankDocument = NULL;
    m_importStdCatAction = NULL;
}

bool SKGCategoriesPlugin::setupActions(SKGDocument* iDocument, const QStringList& iArgument)
{
    SKGTRACEIN(10, "SKGCategoriesPlugin::setupActions");
    Q_UNUSED(iArgument);
    m_currentBankDocument = qobject_cast<SKGDocumentBank*>(iDocument);
    if (m_currentBankDocument == NULL) return false;

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

    //Import categories
    QStringList overlaycategories;
    overlaycategories.push_back("skrooge_category");

    m_importStdCatAction = new KAction(KIcon("document-import", NULL, overlaycategories), i18nc("Verb", "Import standard categories"), this);
    connect(m_importStdCatAction, SIGNAL(triggered(bool)), SLOT(importStandardCategories()));
    actionCollection()->addAction(QLatin1String("import_standard_categories"), m_importStdCatAction);

    if (SKGMainPanel::getMainPanel()) SKGMainPanel::getMainPanel()->registerGlobalAction("import_standard_categories", m_importStdCatAction);

    KAction* deleteUnusedCategoriesAction = new KAction(KIcon("edit-delete"), i18nc("Verb", "Delete unused categories"), this);
    connect(deleteUnusedCategoriesAction, SIGNAL(triggered(bool)), SLOT(deleteUnusedCategories()));
    actionCollection()->addAction(QLatin1String("edit_delete_unused_categories"), deleteUnusedCategoriesAction);

    if (SKGMainPanel::getMainPanel()) SKGMainPanel::getMainPanel()->registerGlobalAction("edit_delete_unused_categories", deleteUnusedCategoriesAction);
    return true;
}

int SKGCategoriesPlugin::getNbDashboardWidgets()
{
    SKGTRACEIN(1, "SKGCategoriesPlugin::getNbDashboardWidgets");
    return 3;
}

QString SKGCategoriesPlugin::getDashboardWidgetTitle(int iIndex)
{
    SKGTRACEIN(1, "SKGCategoriesPlugin::getDashboardWidgetTitle");
    if (iIndex == 0) return i18nc("Report header",  "5 main categories of expenditure");
    else if (iIndex == 1) return i18nc("Report header",  "5 main variations");
    else if (iIndex == 2) return i18nc("Report header",  "Budget");
    return "";
}

SKGWidget* SKGCategoriesPlugin::getDashboardWidget(int iIndex)
{
    SKGWidget* w = new SKGCategoriesBoardWidget(m_currentBankDocument);

    QDomDocument doc("SKGML");
    QDomElement root = doc.createElement("parameters");
    doc.appendChild(root);
    root.setAttribute("mode", SKGServices::intToString(iIndex));

    w->setState(doc.toString());
    return w;
}

void SKGCategoriesPlugin::refresh()
{
    SKGTRACEIN(10, "SKGCategoriesPlugin::refresh");
    if (m_currentBankDocument) {
        bool test = (m_currentBankDocument->getDatabase() != NULL);
        if (m_importStdCatAction) m_importStdCatAction->setEnabled(test);

        //Automatic categories creation
        if (m_currentBankDocument->getDatabase() != NULL) {
            QString doc_id = m_currentBankDocument->getUniqueIdentifier();
            if (m_docUniqueIdentifier != doc_id) {
                m_docUniqueIdentifier = doc_id;

                bool exist = false;
                SKGError err = m_currentBankDocument->existObjects("category", "", exist);
                if (!err && !exist) {
                    importStandardCategories();

                    //The file is considered has not modified
                    m_currentBankDocument->setFileNotModified();
                }
            }
        }
    }
}

void SKGCategoriesPlugin::importStandardCategories()
{
    SKGTRACEIN(10, "SKGCategoriesPlugin::importStandardCategories");
    SKGError err;
    {
        QString cats = i18nc("List of categories.It is not needed to translate each item. You can set the list you want. ';' must be used to separate categories. ' > ' must be used to separate categorie and sub caterogie (no limit of level).",
                             "Alimony;Auto;Auto > Fuel;Auto > Insurance;Auto > Lease;Auto > Loan;Auto > Registration;Auto > Service;Bank Charges;Bank Charges > Interest Paid;Bank Charges > Service Charge;Bills;Bills > Electricity;"
                             "Bills > Fuel Oil;Bills > Local Taxes;Bills > Mortgage;Bills > Natural Gas;Bills > Rent;Bills > TV;Bills > Telephone;Bills > Water & Sewage;Bonus;Business;Business > Auto;Business > Capital Goods;Business > Legal Expenses;Business > Office Rent;"
                             "Business > Office Supplies;Business > Other;Business > Revenue;Business > Taxes;Business > Travel;Business > Utilities;Business > Wages & Salary;Car;Car > Fuel;Car > Insurance;Car > Lease;Car > Loan;Car > Registration;Car > Service;"
                             "Cash Withdrawal;Charity;Charity > Donations;Child Care;Child Support;Clothing;Disability;Div Income;Div Income > Ord dividend;Div Income > Stock dividend;Education;Education > Board;Education > Books;Education > Fees;Education > Loans;"
                             "Education > Tuition;Employment;Employment > Benefits;Employment > Foreign;Employment > Lump sums;Employment > Other employ;Employment > Salary & wages;Food;Food > Dining Out;Food > Groceries;Gardening;"
                             "Gift Received;Gifts;Healthcare;Healthcare > Dental;Healthcare > Doctor;Healthcare > Hospital;Healthcare > Optician;Healthcare > Prescriptions;Holidays;Holidays > Accomodation;Holidays > Travel;Household;"
                             "Household > Furnishings;Household > Repairs;Insurance;Insurance > Auto;Insurance > Disability;Insurance > Home and Contents;Insurance > Life;Insurance > Medical;Int Inc;Int Inc > Bank Interest;Int Inc > Gross;Int Inc > Net;"
                             "Int Inc > Other savings;Invest. income;Invest. income > 1st option;Invest. income > Dividend;Invest. income > Foreign;Invest. income > Other savings;Invest. income > Other trusts;Invest. income > Other trusts#Capital;"
                             "Invest. income > Other trusts#Dist. rec'd;Invest. income > Other trusts#Estate;Investment Income;Investment Income > Dividends;Investment Income > Interest;Investment Income > Long-Term Capital Gains;"
                             "Investment Income > Short-Term Capital Gains;Investment Income > Tax-Exempt Interest;Job Expense;Job Expense > Non-Reimbursed;Job Expense > Reimbursed;Legal Fees;Leisure;Leisure > Books & Magazines;Leisure > Entertaining;"
                             "Leisure > Films & Video Rentals;Leisure > Hobbies;Leisure > Sporting Events;Leisure > Sports Goods;Leisure > Tapes & CDs;Leisure > Theatre & Concerts etc;Leisure > Toys & Games;Loan;Loan > Loan Interest;Long-Term Capital gains;Mortgage;Mortgage > Interest;Mortgage > PMI;Mortgage > Principle;Motor;Motor > Fuel;Motor > Loan;Motor > Service;Other Expense;Other Expense > Unknown;Other Income;Other Income > Child Support;"
                             "Other Income > Employee Share Option;Other Income > Gifts Received;Other Income > Loan Principal Received;Other Income > Lottery or Premium Bond Prizes;Other Income > Student loan;Other Income > Tax Refund;"
                             "Other Income > Unemployment Benefit;Pension;Pension > Employer;Personal Care;Pet Care;Pet Care > Food;Pet Care > Supplies;Pet Care > Vet's Bills;Recreation;Retirement Accounts;Retirement Accounts > 401(k)403(b) Plan Contributions;"
                             "Retirement Accounts > 529 Plan Contributions;Retirement Accounts > IRA Contributions;Retirement Income;Retirement Income > 401(k);Retirement Income > 401(k) > 403(b) Distributions;Retirement Income > IRA Distributions;"
                             "Retirement Income > Pensions & Annuities;Retirement Income > State Pension Benefits;Short-Term Capital gains;Social Security Benefits;Taxes;Taxes > AMT;Taxes > Federal Tax;Taxes > Federal Taxes;Taxes > Local Tax;Taxes > Local Taxes;"
                             "Taxes > Other Invest;Taxes > Other Tax;Taxes > Property Taxes;Taxes > Social Security;Taxes > State Tax;Taxes > State Taxes;Travel;Travel > Accomodations;Travel > Car Rental;Travel > Fares;Utilities;Utilities > Electricity;"
                             "Utilities > Garbage & Recycling;Utilities > Gas;Utilities > Sewer;Utilities > Telephone;Utilities > Water;Wages & Salary;Wages & Salary > Benefits;Wages & Salary > Bonus;Wages & Salary > Commission;"
                             "Wages & Salary > Employer Pension Contributions;Wages & Salary > Gross Pay;Wages & Salary > Net Pay;Wages & Salary > Overtime;Wages & Salary > Workman's Comp");

        SKGBEGINTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Import standard categories"), err);

        foreach(const QString & item, SKGServices::splitCSVLine(cats, ';')) {
            QString line = item.trimmed();
            if (!line.isEmpty()) {
                SKGCategoryObject cat;
                err = SKGCategoryObject::createPathCategory(m_currentBankDocument, line, cat);
            }
        }
    }


    //status
    if (!err)  err = SKGError(0, i18nc("Successful message after an user action", "Standard categories imported."));
    else err.addError(ERR_FAIL, i18nc("Error message", "Importing standard categories failed."));

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

SKGTabPage* SKGCategoriesPlugin::getWidget()
{
    SKGTRACEIN(10, "SKGCategoriesPlugin::getWidget");
    return new SKGCategoriesPluginWidget(m_currentBankDocument);
}

QString SKGCategoriesPlugin::title() const
{
    return i18nc("Noun, categories of items", "Categories");
}

QString SKGCategoriesPlugin::icon() const
{
    return "skrooge_category";
}

QString SKGCategoriesPlugin::toolTip() const
{
    return i18nc("A tool tip", "Categories management");
}

QStringList SKGCategoriesPlugin::tips() const
{
    QStringList output;
    output.push_back(i18nc("Description of a tips", "<p>... categories can be reorganized by drag & drop.</p>"));
    return output;
}

int SKGCategoriesPlugin::getOrder() const
{
    return 30;
}

bool SKGCategoriesPlugin::isInPagesChooser() const
{
    return true;
}

SKGAdviceList SKGCategoriesPlugin::advices() const
{
    SKGTRACEIN(10, "SKGCategoriesPlugin::advices");
    SKGAdviceList output;
    //Check unused categies
    bool exist = false;
    m_currentBankDocument->existObjects("category", "id IN (SELECT id FROM v_category_display WHERE i_SUMNBOPERATIONS=0)", exist);
    if (exist) {
        SKGAdvice ad;
        ad.setUUID("skgcategoriesplugin_unused");
        ad.setPriority(5);
        ad.setShortMessage(i18nc("Advice on making the best (short)", "Many unused categories"));
        ad.setLongMessage(i18nc("Advice on making the best (long)", "You can improve performances by removing categories that have no operations."));
        QStringList autoCorrections;
        autoCorrections.push_back(i18nc("Advice on making the best (action)", "Delete unused categories"));
        ad.setAutoCorrections(autoCorrections);
        output.push_back(ad);
    }

    //Check operations not validated
    QString month = QDate::currentDate().toString("yyyy-MM");
    QDate datepreviousmonth = QDate::currentDate().addDays(-QDate::currentDate().day());
    QString previousmonth = datepreviousmonth.toString("yyyy-MM");

    QStringList listCategories;
    QStringList listVariations = qobject_cast< SKGDocumentBank* >(m_currentBankDocument)->get5MainCategoriesVariationList(month, previousmonth, true, &listCategories);

    int nb = listVariations.count();
    for (int i = 0; i < nb; ++i) {
        SKGAdvice ad;
        ad.setUUID("skgmonthlyplugin_maincategoriesvariation|" % listCategories.at(i));
        ad.setPriority(7);
        ad.setShortMessage(i18nc("Advice on making the best (short)", "Important variation for '%1'", listCategories.at(i)));
        ad.setLongMessage(listVariations.at(i));
        QStringList autoCorrections;
        autoCorrections.push_back(i18nc("Advice on making the best (action)", "Open sub operations with category containing '%1'", listCategories.at(i)));
        ad.setAutoCorrections(autoCorrections);
        output.push_back(ad);
    }
    return output;
}

SKGError SKGCategoriesPlugin::executeAdviceCorrection(const QString& iAdviceIdentifier, int iSolution) const
{
    if (iAdviceIdentifier == "skgcategoriesplugin_unused") {
        deleteUnusedCategories();
        return SKGError();
    } else if (m_currentBankDocument && iAdviceIdentifier.startsWith(QLatin1String("skgmonthlyplugin_maincategoriesvariation|"))) {
        //Get parameters
        QString category = iAdviceIdentifier.right(iAdviceIdentifier.length() - 41);
        QString month = QDate::currentDate().toString("yyyy-MM");

        //Call operation plugin
        QDomDocument doc("SKGML");
        doc.setContent(m_currentBankDocument->getParameter("SKGOPERATION_CONSOLIDATED_DEFAULT_PARAMETERS"));
        QDomElement root = doc.documentElement();
        if (root.isNull()) {
            root = doc.createElement("parameters");
            doc.appendChild(root);
        }

        root.setAttribute("operationTable", "v_operation_consolidated");
        root.setAttribute("operationWhereClause", "d_DATEMONTH='" % month % "' AND t_REALCATEGORY='" % SKGServices::stringToSqlString(category) % '\'');
        root.setAttribute("title", i18nc("Noun, a list of items", "Sub operations with category containing '%1'",  category));
        root.setAttribute("title_icon", "skrooge_category");
        root.setAttribute("currentPage", "-1");

        SKGMainPanel::getMainPanel()->openPage(SKGMainPanel::getMainPanel()->getPluginByName("Skrooge operation plugin"), -1, doc.toString());
        return SKGError();
    }
    return SKGInterfacePlugin::executeAdviceCorrection(iAdviceIdentifier, iSolution);
}

void SKGCategoriesPlugin::deleteUnusedCategories() const
{
    SKGError err;
    _SKGTRACEINRC(10, "SKGCategoriesPlugin::deleteUnusedCategories", err);
    if (m_currentBankDocument) {
        SKGBEGINTRANSACTION(*m_currentBankDocument, i18nc("Noun, name of the user action", "Delete unused categories")  , err);

        QStringList categoriesUsed;
        err = m_currentBankDocument->getDistinctValues("category", "t_fullname", "t_fullname in ("
                "SELECT category.t_fullname FROM category, suboperation WHERE suboperation.r_category_id=category.id UNION "
                "SELECT category.t_fullname FROM category, budget WHERE budget.rc_category_id=category.id UNION "
                "SELECT category.t_fullname FROM category, budgetrule WHERE budgetrule.rc_category_id=category.id UNION "
                "SELECT category.t_fullname FROM category, budgetrule WHERE budgetrule.rc_category_id_target=category.id)", categoriesUsed);

        for (int i = 0; i < categoriesUsed.count(); ++i) { //Warning categoriesUsed is modified in the loop
            QString cat = categoriesUsed.at(i);
            categoriesUsed[i] = SKGServices::stringToSqlString(cat);
            int pos = cat.lastIndexOf(OBJECTSEPARATOR);
            if (pos != -1) categoriesUsed.push_back(cat.left(pos));
        }

        if (!err) {
            QString sql;
            if (categoriesUsed.count())  sql = "DELETE FROM category WHERE t_fullname NOT IN ('" % categoriesUsed.join("','") % "')";
            else sql = "DELETE FROM category";
            err = m_currentBankDocument->executeSqliteOrder(sql);
        }
    }

    //status bar
    if (!err) err = SKGError(0, i18nc("Successful message after an user action", "Unused categories deleted"));
    else err.addError(ERR_FAIL, i18nc("Error message", "Unused categories deletion failed"));

    //Display error
    SKGMainPanel::displayErrorMessage(err);
}
#include "skgcategoriesplugin.moc"
