/***************************************************************************
 *   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 implements classes SKGCategoryObject.
 *
 * @author Stephane MANKOWSKI / Guillaume DE BURE
 */
#include "skgcategoryobject.h"
#include "skgsuboperationobject.h"
#include "skgdocumentbank.h"
#include "skgtraces.h"

#include <klocale.h>

SKGCategoryObject::SKGCategoryObject(SKGDocument* iDocument, int iID) : SKGNamedObject(iDocument, "v_category", iID)
{
}

SKGCategoryObject::~SKGCategoryObject()
{
}

SKGCategoryObject::SKGCategoryObject(const SKGCategoryObject& iObject)
    : SKGNamedObject(iObject)
{
}

SKGCategoryObject::SKGCategoryObject(const SKGObjectBase& iObject)

{
    if (iObject.getRealTable() == "category") {
        copyFrom(iObject);
    } else {
        *this = SKGNamedObject(iObject.getDocument(), "v_category", iObject.getID());
    }
}

const SKGCategoryObject& SKGCategoryObject::operator= (const SKGObjectBase& iObject)
{
    copyFrom(iObject);
    return *this;
}

SKGError SKGCategoryObject::setName(const QString& iName)
{
    SKGError err;
    if (iName.contains(OBJECTSEPARATOR)) err = SKGError(ERR_FAIL,  i18nc("Error message", "Invalid name '%1' because of the name cannot contain '%2'" , iName, QString(OBJECTSEPARATOR)));
    else err = SKGNamedObject::setName(iName);
    return err;
}

QString SKGCategoryObject::getWhereclauseId() const
{
    //Could we use the id
    QString output = SKGObjectBase::getWhereclauseId();
    if (output.isEmpty()) {
        if (!(getAttribute("t_name").isEmpty())) {
            output = "t_name='" % SKGServices::stringToSqlString(getAttribute("t_name")) % '\'';
        }
        QString rd_category_id = getAttribute("rd_category_id");
        if (!output.isEmpty()) output += " AND ";
        if (rd_category_id.isEmpty()) output += "(rd_category_id=0 OR rd_category_id IS NULL OR rd_category_id='')";
        else output += "rd_category_id=" % rd_category_id;
    }
    return output;
}

QString SKGCategoryObject::getFullName() const
{
    return getAttribute("t_fullname");
}

SKGError SKGCategoryObject::createPathCategory(SKGDocumentBank* iDocument,
        const QString& iFullPath,
        SKGCategoryObject& oCategory,
        bool iSendPopupMessageOnCreation,
        bool iRenameIfAlreadyExist)
{
    SKGError err;
    SKGTRACEINRC(10, "SKGCategoryObject::createPathCategory", err);

    //Check if category is already existing
    if (iFullPath.isEmpty()) {
        oCategory = SKGCategoryObject(NULL, 0);
    } else if (iDocument) {

        if (!iRenameIfAlreadyExist && iDocument) iDocument->getObject("v_category", "t_fullname='" % SKGServices::stringToSqlString(iFullPath) % '\'', oCategory);
        if (oCategory.getID() == 0) {
            //No, we have to create it
            //Search category separator
            int posSeparator = iFullPath.lastIndexOf(OBJECTSEPARATOR);
            if (posSeparator == -1) {
                oCategory = SKGCategoryObject(iDocument);
                err = oCategory.setName(iFullPath);

                //Check if already existing
                if (!err && iRenameIfAlreadyExist) {
                    int index = 1;
                    while (!err && oCategory.exist()) {
                        index++;
                        err = oCategory.setName(iFullPath % " (" % SKGServices::intToString(index) % ')');
                    }
                }

                if (!err) err = oCategory.save();
            } else {
                //Get first and second parts of the branch
                QString first = iFullPath.mid(0, posSeparator);
                QString second = iFullPath.mid(posSeparator + QString(OBJECTSEPARATOR).length(), iFullPath.length() - posSeparator - QString(OBJECTSEPARATOR).length());

                //Get first category
                SKGCategoryObject FirstCategory;
                err = SKGCategoryObject::createPathCategory(iDocument, first, FirstCategory);

                if (!err) {
                    //Get second category
                    err = FirstCategory.addCategory(oCategory);

                    //Add second under first
                    if (!err) err = oCategory.setName(second);

                    //Check if already existing
                    if (!err && iRenameIfAlreadyExist) {
                        int index = 2;
                        while (!err && oCategory.exist()) {
                            err = oCategory.setName(second % " (" % SKGServices::intToString(index) % ')');
                            ++index;
                        }
                    }

                    //save
                    if (!err) err = oCategory.save();
                }
            }

            if (!err && iSendPopupMessageOnCreation && iDocument) {
                iDocument->sendMessage(i18nc("Information message", "Category '%1' has been created" , iFullPath), true);
            }
        }
    }

    return err;
}

SKGError SKGCategoryObject::addCategory(SKGCategoryObject& oCategory)
{
    SKGError err;
    SKGTRACEINRC(10, "SKGCategoryObject::addCategory", err);
    if (getID() == 0)  err = SKGError(ERR_FAIL,  i18nc("Error message", "%1 failed because linked object is not yet saved in the database." , QString("SKGCategoryObject::addCategory")));
    else {
        oCategory = SKGCategoryObject(static_cast<SKGDocumentBank*>(getDocument()));
        err = oCategory.setAttribute("rd_category_id", SKGServices::intToString(getID()));
    }
    return err;
}

SKGError SKGCategoryObject::setParentCategory(const SKGCategoryObject& iCategory)
{
    SKGError err;
    SKGTRACEINRC(10, "SKGCategoryObject::setParentCategory", err);
    if (iCategory.getID() == 0) err = SKGError(ERR_FAIL,  i18nc("Error message", "%1 failed because linked object is not yet saved in the database." , QString("SKGCategoryObject::setParentCategory")));
    else {
        //Check if it's a loop
        SKGCategoryObject current = iCategory;
        do {
            if (current == *this) {
                err = SKGError(ERR_FAIL,  i18nc("Error message", "You cannot create a loop."));
            } else {
                SKGCategoryObject parent;
                current.getParentCategory(parent);
                current = parent;
            }
        } while (!err && current.getID() != 0);

        if (!err) err = setAttribute("rd_category_id", SKGServices::intToString(iCategory.getID()));
    }
    return err;
}

SKGError SKGCategoryObject::removeParentCategory()
{
    return setAttribute("rd_category_id", "");
}

SKGError SKGCategoryObject::getParentCategory(SKGCategoryObject& oCategory) const
{
    SKGError err;
    QString parent_id = getAttribute("rd_category_id");
    if (!parent_id.isEmpty() && parent_id != "0") err = getDocument()->getObject("v_category", "id=" % parent_id , oCategory);
    return err;
}

SKGError SKGCategoryObject::getRootCategory(SKGCategoryObject& oCategory) const
{
    SKGError err;
    SKGCategoryObject parent;
    err = getParentCategory(parent);
    if (!err) {
        if (!parent.exist()) {
            //No parent
            oCategory = *this;
        } else {
            //Parent exist
            err = parent.getRootCategory(oCategory);
        }
    }
    return err;
}


SKGError SKGCategoryObject::getCategories(SKGListSKGObjectBase& oCategoryList) const
{
    return getDocument()->getObjects("v_category",
                                     "rd_category_id=" % SKGServices::intToString(getID()),
                                     oCategoryList);
}

double SKGCategoryObject::getCurrentAmount() const
{
    SKGNamedObject cat(getDocument(), "v_category_display", getID());
    return SKGServices::stringToDouble(cat.getAttribute("f_SUMCURRENTAMOUNT"));
}

SKGError SKGCategoryObject::getSubOperations(SKGListSKGObjectBase& oSubOperations) const
{
    SKGError err = getDocument()->getObjects("v_suboperation",
                   "r_category_id=" % SKGServices::intToString(getID()) ,
                   oSubOperations);
    return err;
}

SKGError SKGCategoryObject::bookmark(bool iBookmark)
{
    return setAttribute("t_bookmarked", iBookmark ? "Y" : "N");

}

bool SKGCategoryObject::isBookmarked() const
{
    return (getAttribute("t_bookmarked") == "Y" ? true : false);
}

SKGError SKGCategoryObject::merge(const SKGCategoryObject& iCategory)
{
    SKGError err;

    SKGObjectBase::SKGListSKGObjectBase ops;
    if (!err) err = iCategory.getSubOperations(ops);
    int nb = ops.count();
    for (int i = 0; !err && i < nb; ++i) {
        SKGSubOperationObject op = ops.at(i);
        err = op.setCategory(*this);
        if (!err) err = op.save(true, false);
    }

    SKGObjectBase::SKGListSKGObjectBase cats;
    if (!err) err = iCategory.getCategories(cats);
    nb = cats.count();
    for (int i = 0; !err && i < nb; ++i) {
        SKGCategoryObject cat = cats.at(i);
        err = cat.setParentCategory(*this);
        if (!err) err = cat.save(true, false);
    }

    if (!err) err = iCategory.remove();
    return err;
}

#include "skgcategoryobject.moc"
