/* This file is part of the KDE project
 * Copyright ( C ) 2007 Thorsten Zachmann <zachmann@kde.org>
 * SPDX-FileCopyrightText: 2009 Fredy Yanardi <fyanardi@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or ( at your option ) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "TestPAPageMoveCommand.h"

#include "KoPAMasterPage.h"
#include "KoPAPageMoveCommand.h"

#include <QTest>

void TestPAPageMoveCommand::initTestCase()
{
    for (int i = 0; i < 5; ++i) {
        m_pages.insert(i, new KoPAMasterPage());
    }
    m_doc.insertPage(m_pages[0], -1);
}

void TestPAPageMoveCommand::cleanupTestCase()
{
}

void TestPAPageMoveCommand::init()
{
    for (int i = 1; i < 5; ++i) {
        m_doc.insertPage(m_pages[i], -1);
    }
}

void TestPAPageMoveCommand::cleanup()
{
    for (int i = 1; i < 5; ++i) {
        m_doc.takePage(m_pages[i]);
    }
}

void TestPAPageMoveCommand::redoUndoAfter()
{
    KoPAPageMoveCommand cmd1(&m_doc, m_pages[0], m_pages[1]);

    QList<KoPAMasterPage *> pages1;
    pages1.insert(0, m_pages[1]);
    pages1.insert(1, m_pages[0]);
    pages1.insert(2, m_pages[2]);
    pages1.insert(3, m_pages[3]);
    pages1.insert(4, m_pages[4]);

    cmd1.redo();
    checkOrder(pages1);

    KoPAPageMoveCommand cmd2(&m_doc, m_pages[1], m_pages[2]);

    QList<KoPAMasterPage *> pages2;
    pages2.insert(0, m_pages[0]);
    pages2.insert(1, m_pages[2]);
    pages2.insert(2, m_pages[1]);
    pages2.insert(3, m_pages[3]);
    pages2.insert(4, m_pages[4]);

    cmd2.redo();
    checkOrder(pages2);

    KoPAPageMoveCommand cmd3(&m_doc, m_pages[1], m_pages[4]);

    QList<KoPAMasterPage *> pages3;
    pages3.insert(0, m_pages[0]);
    pages3.insert(1, m_pages[2]);
    pages3.insert(2, m_pages[3]);
    pages3.insert(3, m_pages[4]);
    pages3.insert(4, m_pages[1]);

    cmd3.redo();
    checkOrder(pages3);

    // Moving multiple consecutive pages
    QList<KoPAPageBase *> multiPages1;
    multiPages1.insert(0, m_pages[3]);
    multiPages1.insert(1, m_pages[4]);
    QList<KoPAMasterPage *> pages4;
    pages4.insert(0, m_pages[0]);
    pages4.insert(1, m_pages[3]);
    pages4.insert(2, m_pages[4]);
    pages4.insert(3, m_pages[2]);
    pages4.insert(4, m_pages[1]);

    KoPAPageMoveCommand cmd4(&m_doc, multiPages1, m_pages[0]);
    cmd4.redo();
    checkOrder(pages4);

    // Moving multiple non-consecutive pages
    QList<KoPAPageBase *> multiPages2;
    multiPages2.insert(0, m_pages[4]);
    multiPages2.insert(1, m_pages[1]);
    QList<KoPAMasterPage *> pages5;
    pages5.insert(0, m_pages[0]);
    pages5.insert(1, m_pages[4]);
    pages5.insert(2, m_pages[1]);
    pages5.insert(3, m_pages[3]);
    pages5.insert(4, m_pages[2]);

    KoPAPageMoveCommand cmd5(&m_doc, multiPages2, m_pages[0]);
    cmd5.redo();
    checkOrder(pages5);

    cmd5.undo();
    checkOrder(pages4);

    cmd4.undo();
    checkOrder(pages3);

    cmd3.undo();
    checkOrder(pages2);

    cmd2.undo();
    checkOrder(pages1);

    cmd1.undo();
    checkOrder(m_pages);
}

void TestPAPageMoveCommand::redoUndoBefore()
{
    KoPAPageMoveCommand cmd1(&m_doc, m_pages[1], nullptr);

    QList<KoPAMasterPage *> pages1;
    pages1.insert(0, m_pages[1]);
    pages1.insert(1, m_pages[0]);
    pages1.insert(2, m_pages[2]);
    pages1.insert(3, m_pages[3]);
    pages1.insert(4, m_pages[4]);

    cmd1.redo();
    checkOrder(pages1);

    KoPAPageMoveCommand cmd2(&m_doc, m_pages[2], m_pages[1]);

    QList<KoPAMasterPage *> pages2;
    pages2.insert(0, m_pages[1]);
    pages2.insert(1, m_pages[2]);
    pages2.insert(2, m_pages[0]);
    pages2.insert(3, m_pages[3]);
    pages2.insert(4, m_pages[4]);

    cmd2.redo();
    checkOrder(pages2);

    KoPAPageMoveCommand cmd3(&m_doc, m_pages[4], m_pages[1]);

    QList<KoPAMasterPage *> pages3;
    pages3.insert(0, m_pages[1]);
    pages3.insert(1, m_pages[4]);
    pages3.insert(2, m_pages[2]);
    pages3.insert(3, m_pages[0]);
    pages3.insert(4, m_pages[3]);

    cmd3.redo();
    checkOrder(pages3);

    // Moving multiple consecutive pages
    QList<KoPAPageBase *> multiPages1;
    multiPages1.insert(0, m_pages[4]);
    multiPages1.insert(1, m_pages[2]);
    QList<KoPAMasterPage *> pages4;
    pages4.insert(0, m_pages[1]);
    pages4.insert(1, m_pages[0]);
    pages4.insert(2, m_pages[4]);
    pages4.insert(3, m_pages[2]);
    pages4.insert(4, m_pages[3]);

    KoPAPageMoveCommand cmd4(&m_doc, multiPages1, m_pages[0]);
    cmd4.redo();
    checkOrder(pages4);

    // Moving multiple non-consecutive pages
    QList<KoPAPageBase *> multiPages2;
    multiPages2.insert(0, m_pages[1]);
    multiPages2.insert(1, m_pages[4]);
    QList<KoPAMasterPage *> pages5;
    pages5.insert(0, m_pages[0]);
    pages5.insert(1, m_pages[2]);
    pages5.insert(2, m_pages[3]);
    pages5.insert(3, m_pages[1]);
    pages5.insert(4, m_pages[4]);

    KoPAPageMoveCommand cmd5(&m_doc, multiPages2, m_pages[3]);
    cmd5.redo();
    checkOrder(pages5);

    cmd5.undo();
    checkOrder(pages4);

    cmd4.undo();
    checkOrder(pages3);

    cmd3.undo();
    checkOrder(pages2);

    cmd2.undo();
    checkOrder(pages1);

    cmd1.undo();
}

void TestPAPageMoveCommand::redoUndoStart()
{
    KoPAPageMoveCommand cmd1(&m_doc, m_pages[4], nullptr);

    QList<KoPAMasterPage *> pages1;
    pages1.insert(0, m_pages[4]);
    pages1.insert(1, m_pages[0]);
    pages1.insert(2, m_pages[1]);
    pages1.insert(3, m_pages[2]);
    pages1.insert(4, m_pages[3]);

    cmd1.redo();
    checkOrder(pages1);

    KoPAPageMoveCommand cmd2(&m_doc, m_pages[1], nullptr);

    QList<KoPAMasterPage *> pages2;
    pages2.insert(0, m_pages[1]);
    pages2.insert(1, m_pages[4]);
    pages2.insert(2, m_pages[0]);
    pages2.insert(3, m_pages[2]);
    pages2.insert(4, m_pages[3]);

    cmd2.redo();
    checkOrder(pages2);

    KoPAPageMoveCommand cmd3(&m_doc, m_pages[4], nullptr);

    QList<KoPAMasterPage *> pages3;
    pages3.insert(0, m_pages[4]);
    pages3.insert(1, m_pages[1]);
    pages3.insert(2, m_pages[0]);
    pages3.insert(3, m_pages[2]);
    pages3.insert(4, m_pages[3]);

    cmd3.redo();
    checkOrder(pages3);

    // Moving multiple consecutive pages
    QList<KoPAPageBase *> multiPages1;
    multiPages1.insert(0, m_pages[1]);
    multiPages1.insert(1, m_pages[0]);
    QList<KoPAMasterPage *> pages4;
    pages4.insert(0, m_pages[1]);
    pages4.insert(1, m_pages[0]);
    pages4.insert(2, m_pages[4]);
    pages4.insert(3, m_pages[2]);
    pages4.insert(4, m_pages[3]);

    KoPAPageMoveCommand cmd4(&m_doc, multiPages1, nullptr);
    cmd4.redo();
    checkOrder(pages4);

    // Moving multiple non-consecutive pages
    QList<KoPAPageBase *> multiPages2;
    multiPages2.insert(0, m_pages[0]);
    multiPages2.insert(1, m_pages[2]);
    QList<KoPAMasterPage *> pages5;
    pages5.insert(0, m_pages[0]);
    pages5.insert(1, m_pages[2]);
    pages5.insert(2, m_pages[1]);
    pages5.insert(3, m_pages[4]);
    pages5.insert(4, m_pages[3]);

    KoPAPageMoveCommand cmd5(&m_doc, multiPages2, nullptr);
    cmd5.redo();
    checkOrder(pages5);

    cmd5.undo();
    checkOrder(pages4);

    cmd4.undo();
    checkOrder(pages3);

    cmd3.undo();
    checkOrder(pages2);

    cmd2.undo();
    checkOrder(pages1);

    cmd1.undo();
    checkOrder(m_pages);
}

void TestPAPageMoveCommand::redoUndoEnd()
{
    KoPAPageMoveCommand cmd1(&m_doc, m_pages[0], m_pages[4]);

    QList<KoPAMasterPage *> pages1;
    pages1.insert(0, m_pages[1]);
    pages1.insert(1, m_pages[2]);
    pages1.insert(2, m_pages[3]);
    pages1.insert(3, m_pages[4]);
    pages1.insert(4, m_pages[0]);

    cmd1.redo();
    checkOrder(pages1);

    KoPAPageMoveCommand cmd2(&m_doc, m_pages[3], m_pages[0]);

    QList<KoPAMasterPage *> pages2;
    pages2.insert(0, m_pages[1]);
    pages2.insert(1, m_pages[2]);
    pages2.insert(2, m_pages[4]);
    pages2.insert(3, m_pages[0]);
    pages2.insert(4, m_pages[3]);

    cmd2.redo();
    checkOrder(pages2);

    KoPAPageMoveCommand cmd3(&m_doc, m_pages[0], m_pages[3]);

    QList<KoPAMasterPage *> pages3;
    pages3.insert(0, m_pages[1]);
    pages3.insert(1, m_pages[2]);
    pages3.insert(2, m_pages[4]);
    pages3.insert(3, m_pages[3]);
    pages3.insert(4, m_pages[0]);

    cmd3.redo();
    checkOrder(pages3);

    // Moving multiple consecutive pages
    QList<KoPAPageBase *> multiPages1;
    multiPages1.insert(0, m_pages[2]);
    multiPages1.insert(1, m_pages[4]);
    QList<KoPAMasterPage *> pages4;
    pages4.insert(0, m_pages[1]);
    pages4.insert(1, m_pages[3]);
    pages4.insert(2, m_pages[0]);
    pages4.insert(3, m_pages[2]);
    pages4.insert(4, m_pages[4]);

    KoPAPageMoveCommand cmd4(&m_doc, multiPages1, m_pages[0]);
    cmd4.redo();
    checkOrder(pages4);

    // Moving multiple non-consecutive pages
    QList<KoPAPageBase *> multiPages2;
    multiPages2.insert(0, m_pages[1]);
    multiPages2.insert(1, m_pages[0]);
    QList<KoPAMasterPage *> pages5;
    pages5.insert(0, m_pages[3]);
    pages5.insert(1, m_pages[2]);
    pages5.insert(2, m_pages[4]);
    pages5.insert(3, m_pages[1]);
    pages5.insert(4, m_pages[0]);

    KoPAPageMoveCommand cmd5(&m_doc, multiPages2, m_pages[4]);
    cmd5.redo();
    checkOrder(pages5);

    cmd5.undo();
    checkOrder(pages4);

    cmd4.undo();
    checkOrder(pages3);

    cmd3.undo();
    checkOrder(pages2);

    cmd2.undo();
    checkOrder(pages1);

    cmd1.undo();
    checkOrder(m_pages);
}

// Moving multiple pages, where those pages are split into two sets, one set contains pages before "after"
// and the other set contains pages after "after"
void TestPAPageMoveCommand::redoUndoAfterInBetween()
{
    QList<KoPAPageBase *> multiPages;
    multiPages.insert(0, m_pages[1]);
    multiPages.insert(1, m_pages[3]);
    QList<KoPAMasterPage *> pages1;
    pages1.insert(0, m_pages[0]);
    pages1.insert(1, m_pages[2]);
    pages1.insert(2, m_pages[1]);
    pages1.insert(3, m_pages[3]);
    pages1.insert(4, m_pages[4]);

    KoPAPageMoveCommand cmd(&m_doc, multiPages, m_pages[2]);
    cmd.redo();
    checkOrder(pages1);

    cmd.undo();
    checkOrder(m_pages);
}

void TestPAPageMoveCommand::checkOrder(QList<KoPAMasterPage *> &pages)
{
    for (int i = 0; i < pages.size(); ++i) {
        QVERIFY(pages[i] == m_doc.pageByIndex(i, true));
    }
}

QTEST_MAIN(TestPAPageMoveCommand)
