/***************************************************************************
 *   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 a test script.
 *
 * @author Stephane MANKOWSKI / Guillaume DE BURE
 */
#include "skgtestmacro.h"
#include "skgbankincludes.h"

/**
 * The main function of the unit test
 * @param argc the number of arguments
 * @param argv the list of arguments
 */
int main(int argc, char** argv)
{
    Q_UNUSED(argc);
    Q_UNUSED(argv);

    // Init test
    SKGINITTEST(true);

    {
        // Test category
        SKGDocumentBank document1;
        SKGTESTERROR("document1.initialize()", document1.initialize(), true);
        SKGError err;
        SKGCategoryObject parent2;
        {
            // Scope of the transaction
            SKGBEGINTRANSACTION(document1, "CAT_T1", err);

            // Create category 0
            SKGCategoryObject cat0(&document1);
            SKGTESTERROR("CAT:setName+invalid name", cat0.setName('a' % OBJECTSEPARATOR % 'b'), false);
            SKGTESTBOOL("CAT:exist", cat0.exist(), false);
            SKGTESTERROR("CAT:save", cat0.save(), false);

            // Create category 1
            SKGCategoryObject cat1(&document1);

            SKGCategoryObject cat1_1;
            SKGTESTERROR("CAT:addCategory", cat1.addCategory(cat1_1), false);
            SKGTESTERROR("CAT:setParentCategory", cat1.setParentCategory(cat1_1), false);

            SKGTESTERROR("CAT:setName", cat1.setName("root1"), true);
            SKGTESTBOOL("CAT:getFullName", cat1.isBookmarked(), false);
            SKGTESTERROR("CAT:bookmark", cat1.bookmark(true), true);
            SKGTESTBOOL("CAT:getFullName", cat1.isBookmarked(), true);
            SKGTESTERROR("CAT:save", cat1.save(), true);
            SKGTEST("CAT:getFullName", cat1.getFullName(), "root1");
            SKGTESTERROR("CAT:load", cat1.load(), true);
            SKGTEST("CAT:getFullName", cat1.getFullName(), "root1");

            SKGObjectBase obj1 = static_cast<SKGObjectBase>(cat1);
            SKGCategoryObject cat11(obj1);

            // Update with bad name
            SKGTESTERROR("CAT:setName", cat1.setName("root1" % OBJECTSEPARATOR % 'A'), false);
            SKGTESTERROR("CAT:load", cat1.load(), true);
            SKGTEST("CAT:getFullName", cat1.getFullName(), "root1");

            // Create category 1.1
            SKGTESTERROR("CAT:addCategory", cat1.addCategory(cat1_1), true);
            SKGTESTERROR("CAT:setName", cat1_1.setName("cat1"), true);
            SKGTESTERROR("CAT:save", cat1_1.save(), true);
            SKGTEST("CAT:getFullName", cat1_1.getFullName(), "root1" % OBJECTSEPARATOR % "cat1");

            // Update cat1_1
            SKGTESTERROR("CAT:setName", cat1_1.setName("CAT1"), true);
            SKGTESTERROR("CAT:save", cat1_1.save(), true);
            SKGTEST("CAT:getFullName", cat1_1.getFullName(), "root1" % OBJECTSEPARATOR % "CAT1");

            // Update cat1
            SKGTESTERROR("CAT:setName", cat1.setName("ROOT1"), true);
            SKGTESTERROR("CAT:save", cat1.save(), true);
            SKGTEST("CAT:getFullName", cat1.getFullName(), "ROOT1");

            SKGTESTERROR("CAT:load", cat1_1.load(), true);
            SKGTEST("CAT:getFullName", cat1_1.getFullName(), "ROOT1" % OBJECTSEPARATOR % "CAT1");

            // Create category 1.2
            SKGCategoryObject cat1_2;
            SKGTESTERROR("CAT:addCategory", cat1.addCategory(cat1_2), true);
            SKGTESTERROR("CAT:setName", cat1_2.setName("CAT2"), true);
            SKGTESTERROR("CAT:save", cat1_2.save(), true);
            SKGTEST("CAT:getFullName", cat1_2.getFullName(), "ROOT1" % OBJECTSEPARATOR % "CAT2");

            // Create category end
            SKGCategoryObject end1;
            SKGTESTERROR("CAT:addCategory", cat1_1.addCategory(end1), true);
            SKGTESTERROR("CAT:setName", end1.setName("END"), true);
            SKGTESTERROR("CAT:save", end1.save(), true);
            SKGTEST("CAT:getFullName", end1.getFullName(), "ROOT1" % OBJECTSEPARATOR % "CAT1" % OBJECTSEPARATOR % "END");

            // Create category end
            SKGCategoryObject end2;
            SKGTESTERROR("CAT:addCategory", cat1_2.addCategory(end2), true);
            SKGTESTERROR("CAT:setName", end2.setName("END"), true);
            SKGTESTERROR("CAT:save", end2.save(), true);
            SKGTEST("CAT:getFullName", end2.getFullName(), "ROOT1" % OBJECTSEPARATOR % "CAT2" % OBJECTSEPARATOR % "END");

            SKGCategoryObject end2_1;
            SKGTESTERROR("CAT:addCategory", end2.addCategory(end2_1), true);
            SKGTESTERROR("CAT:setName", end2_1.setName("REALEND"), true);
            SKGTESTERROR("CAT:save", end2_1.save(), true);
            SKGTEST("CAT:getFullName", end2_1.getFullName(), "ROOT1" % OBJECTSEPARATOR % "CAT2" % OBJECTSEPARATOR % "END" % OBJECTSEPARATOR % "REALEND");

            // Get parent
            SKGCategoryObject parent1;
            SKGTESTERROR("CAT:getParentCategory", end2.getParentCategory(parent1), true);
            SKGTEST("CAT:getFullName", parent1.getFullName(), "ROOT1" % OBJECTSEPARATOR % "CAT2");

            // Get parent
            SKGTESTERROR("CAT:getParentCategory", parent1.getParentCategory(parent2), true);
            SKGTEST("CAT:getFullName", parent2.getFullName(), "ROOT1");

            SKGCategoryObject root;
            SKGTESTERROR("CAT:getRootCategory", end2_1.getRootCategory(root), true);
            SKGTEST("CAT:getFullName", root.getFullName(), "ROOT1");

            // Get children
            SKGObjectBase::SKGListSKGObjectBase CategoryList;
            SKGTESTERROR("CAT:getCategories", parent2.getCategories(CategoryList), true);
            SKGTEST("CAT:nb categories", CategoryList.size(), 2);

            // Simple delete
            SKGTESTERROR("CAT:delete", end1.remove(), true);
            QStringList oResult;
            SKGTESTERROR("CAT:getDistinctValues", document1.getDistinctValues("category", "id", oResult), true);
            SKGTEST("CAT:oResult.size", oResult.size(), 5);
        }
        {
            // Scope of the transaction
            SKGBEGINTRANSACTION(document1, "CAT_T2", err);

            // Cascading delete
            SKGTESTERROR("CAT:delete", parent2.remove(), true);
            QStringList oResult;
            SKGTESTERROR("CAT:getDistinctValues", document1.getDistinctValues("category", "id", oResult), true);
            SKGTEST("CAT:oResult.size", oResult.size(), 0);
        }

        // Undo
        SKGTESTERROR("CAT:undoRedoTransaction", document1.undoRedoTransaction(), true);
        QStringList oResult;
        SKGTESTERROR("CAT:getDistinctValues", document1.getDistinctValues("category", "id", oResult), true);
        SKGTEST("CAT:oResult.size", oResult.size(), 5);

        SKGTESTERROR("CAT:undoRedoTransaction", document1.undoRedoTransaction(), true);
        SKGTESTERROR("CAT:getDistinctValues", document1.getDistinctValues("category", "id", oResult), true);
        SKGTEST("CAT:oResult.size", oResult.size(), 0);

        // Redo
        SKGTESTERROR("CAT:undoRedoTransaction(SKGDocument::REDO)", document1.undoRedoTransaction(SKGDocument::REDO), true);
        SKGTESTERROR("CAT:getDistinctValues", document1.getDistinctValues("category", "id", oResult), true);
        SKGTEST("CAT:oResult.size", oResult.size(), 5);

        SKGTESTERROR("CAT:undoRedoTransaction(SKGDocument::REDO)", document1.undoRedoTransaction(SKGDocument::REDO), true);
        SKGTESTERROR("CAT:getDistinctValues", document1.getDistinctValues("category", "id", oResult), true);
        SKGTEST("CAT:oResult.size", oResult.size(), 0);
    }

    {
        SKGDocumentBank document1;
        SKGTESTERROR("document1.initialize()", document1.initialize(), true);
        SKGError err;
        {
            // Scope of the transaction
            SKGBEGINTRANSACTION(document1, "CAT_T1", err);

            SKGCategoryObject cat;
            SKGTESTERROR("CAT:createPathCategory", SKGCategoryObject::createPathCategory(&document1, "", cat), true);
            SKGTESTERROR("CAT:createPathCategory", SKGCategoryObject::createPathCategory(&document1, 'A' % OBJECTSEPARATOR % 'A', cat, true), true);
            SKGTEST("CAT:getName", cat.getName(), "A");

            QStringList oResult;
            SKGTESTERROR("CAT:getDistinctValues", document1.getDistinctValues("category", "id", oResult), true);
            SKGTEST("CAT:oResult.size", oResult.size(), 2);

            SKGTESTERROR("CAT:createPathCategory", SKGCategoryObject::createPathCategory(&document1, 'A' % OBJECTSEPARATOR % 'B', cat, true, true), true);
            SKGTEST("CAT:getName", cat.getName(), "B");
            SKGTESTERROR("CAT:createPathCategory", SKGCategoryObject::createPathCategory(&document1, 'A' % OBJECTSEPARATOR % 'B', cat, true, true), true);
            SKGTEST("CAT:getName", cat.getName(), "B (2)");

            SKGTESTERROR("CAT:createPathCategory", SKGCategoryObject::createPathCategory(&document1, "C", cat, true, true), true);
            SKGTEST("CAT:getName", cat.getName(), "C");
            SKGTESTERROR("CAT:createPathCategory", SKGCategoryObject::createPathCategory(&document1, "C", cat, true, true), true);
            SKGTEST("CAT:getName", cat.getName(), "C (2)");
        }
    }

    {
        SKGDocumentBank document1;
        SKGTESTERROR("document1.initialize()", document1.initialize(), true);
        SKGError err;
        {
            // Scope of the transaction
            SKGBEGINTRANSACTION(document1, "NODE_T1", err);

            SKGCategoryObject categoryB;
            SKGTESTERROR("NOD:createPathCategory", SKGCategoryObject::createPathCategory(&document1, 'A' % OBJECTSEPARATOR % 'B', categoryB), true);
            SKGCategoryObject categoryC;
            SKGTESTERROR("NOD:createPathCategory", SKGCategoryObject::createPathCategory(&document1, "C", categoryC), true);
            SKGCategoryObject categoryA;
            SKGTESTERROR("NOD:getParentCategory", categoryB.getParentCategory(categoryA), true);

            SKGTESTERROR("NOD:setParentCategory", categoryA.setParentCategory(categoryB), false);
            SKGTESTERROR("NOD:setParentCategory", categoryA.setParentCategory(categoryA), false);
            SKGTESTERROR("NOD:setParentCategory", categoryB.setParentCategory(categoryB), false);
            SKGTESTERROR("NOD:setParentCategory", categoryC.setParentCategory(categoryB), true);
            SKGTESTERROR("NOD:removeParentCategory", categoryB.removeParentCategory(), true);
        }
    }

    // Bug 245254
    {
        SKGDocumentBank document1;
        SKGTESTERROR("document1.initialize()", document1.initialize(), true);
        SKGError err;
        {
            // Scope of the transaction
            SKGBEGINTRANSACTION(document1, "NODE_T1", err);

            SKGCategoryObject categoryB;
            SKGTESTERROR("NOD:createPathCategory", SKGCategoryObject::createPathCategory(&document1, 'A' % OBJECTSEPARATOR % 'B', categoryB), true);
            SKGCategoryObject categoryC;
            SKGTESTERROR("NOD:createPathCategory", SKGCategoryObject::createPathCategory(&document1, "C", categoryC), true);
            SKGCategoryObject categoryA;
            SKGTESTERROR("NOD:createPathCategory", SKGCategoryObject::createPathCategory(&document1, 'C' % OBJECTSEPARATOR % 'A', categoryA), true);

            QStringList oResult;
            SKGTESTERROR("CAT:getDistinctValues", document1.getDistinctValues("category", "id", oResult), true);
            SKGTEST("CAT:oResult.size", oResult.size(), 4);

            // Merge
            SKGTESTERROR("CAT:merge", categoryB.merge(categoryA), true);
        }
    }

    // Cascading delete
    {
        SKGDocumentBank document1;
        SKGTESTERROR("document1.initialize()", document1.initialize(), true);
        SKGError err;
        {
            // Scope of the transaction
            SKGBEGINTRANSACTION(document1, "NODE_T1", err);

            SKGCategoryObject categoryA;
            SKGTESTERROR("NOD:createPathCategory", SKGCategoryObject::createPathCategory(&document1, "A" , categoryA), true);
            SKGCategoryObject categoryC;
            SKGTESTERROR("NOD:createPathCategory", SKGCategoryObject::createPathCategory(&document1, 'A' % OBJECTSEPARATOR % 'B' % OBJECTSEPARATOR % 'C', categoryC), true);

            QStringList oResult;
            SKGTESTERROR("CAT:getDistinctValues", document1.getDistinctValues("category", "id", oResult), true);
            SKGTEST("CAT:oResult.size", oResult.size(), 3);

            // Delete
            SKGTESTERROR("CAT:remove", categoryA.remove(), true);

            SKGTESTERROR("CAT:getDistinctValues", document1.getDistinctValues("category", "id", oResult), true);
            SKGTEST("CAT:oResult.size", oResult.size(), 0);
        }
    }
    // End test
    SKGENDTEST();
}
