/* This file is part of the KDE project
   Copyright (C) 2006-2010 Dag Andersen <danders@get2net.dk>

   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.
*/
// clazy:excludeall=qstring-arg
#include "ResourceTester.h"
#include "DateTimeTester.h"

#include <kptresource.h>
#include <kptcalendar.h>
#include <kptcommand.h>
#include <kptdatetime.h>
#include <kptduration.h>
#include <kptmap.h>


#include <QTest>

#include "kptglobal.h"
#include "kptxmlloaderobject.h"
#include "XmlSaveContext.h"

#include <KoXmlReader.h>

#include "debug.cpp"

#include <QDomDocument>
#include <QDomElement>

namespace KPlato
{

void ResourceTester::testAvailable()
{
    Resource r;
    QVERIFY(! r.availableFrom().isValid());
    QVERIFY(! r.availableUntil().isValid());
    
    QDateTime qt = QDateTime::currentDateTime();
    DateTime dt = DateTime(qt);
    qDebug()<<"dt"<<dt;
    
    r.setAvailableFrom(qt);
    Debug::print(&r, "Test setAvailableFrom with QDateTime");
    DateTime x = r.availableFrom();
    qDebug()<<"------"<<x;
    QCOMPARE(x, dt);
    qDebug()<<"----------------";
    r.setAvailableUntil(qt.addDays(1));
    Debug::print(&r, "Test setAvailableUntil with QDateTime");
    QCOMPARE(r.availableUntil(), DateTime(dt.addDays(1)));
    qDebug()<<"----------------";
}

void ResourceTester::testSingleDay() {
    Calendar t("Test");
    QDate wdate(2006,1,2);
    DateTime before = DateTime(wdate.addDays(-1), QTime());
    DateTime after = DateTime(wdate.addDays(1), QTime());
    QTime t1(8,0,0);
    QTime t2(10,0,0);
    DateTime wdt1(wdate, t1);
    DateTime wdt2(wdate, t2);
    int length = t1.msecsTo(t2);
    CalendarDay *day = new CalendarDay(wdate, CalendarDay::Working);
    day->addInterval(TimeInterval(t1, length));
    t.addDay(day);
    QVERIFY(t.findDay(wdate) == day);
    
    Resource r;
    r.setAvailableFrom(before);
    r.setAvailableUntil(after);
    r.setCalendar(&t);
    
    Debug::print(&r, "Test single resource, no group, no project", true);

    QVERIFY(r.availableAfter(after, DateTime(after.addDays(1))).isValid() == false);
    QVERIFY(r.availableBefore(before, DateTime(before.addDays(-1))).isValid() == false);
    
    QVERIFY(r.availableAfter(before, after).isValid());
    
    QVERIFY((r.availableAfter(after, DateTime(after.addDays(10)))).isValid() == false);
    QVERIFY((r.availableBefore(before, DateTime(before.addDays(-10)))).isValid() == false);
    
    QCOMPARE(r.availableAfter(before,after), wdt1);
    QCOMPARE(r.availableBefore(after, before), wdt2);
    
    Duration e(0, 2, 0);
    QCOMPARE(r.effort(before, Duration(2, 0, 0)).toString(), e.toString());

}

void ResourceTester::team()
{
    Resource team;
    team.setId("team");
    Resource tm1, tm2;
    tm1.setId("tm1");
    tm2.setId("tm2");

    QVERIFY(team.teamMemberIds().isEmpty());
    team.addTeamMemberId(tm1.id());
    QVERIFY(team.teamMemberIds().count() == 1);
    team.removeTeamMemberId(tm1.id());
    QVERIFY(team.teamMemberIds().isEmpty());
    team.addTeamMemberId(tm1.id());
    team.addTeamMemberId(tm2.id());
    QVERIFY(team.teamMemberIds().count() == 2);
    team.addTeamMemberId(tm2.id());
    QVERIFY(team.teamMemberIds().count() == 2);
    team.removeTeamMemberId(tm1.id());
    team.removeTeamMemberId(tm2.id());
    QVERIFY(team.teamMemberIds().isEmpty());

    AddResourceTeamCmd ac(&team, tm1.id());
    ac.execute();
    QVERIFY(team.teamMemberIds().count() == 1);
    ac.unexecute();
    QVERIFY(team.teamMemberIds().isEmpty());
    ac.execute();
    RemoveResourceTeamCmd rc(&team, tm1.id());
    rc.execute();
    QVERIFY(team.teamMemberIds().isEmpty());
    rc.unexecute();
    QVERIFY(team.teamMemberIds().count() == 1);

    {
        Project p1;

        AddResourceGroupCmd *c1 = new AddResourceGroupCmd(&p1, new ResourceGroup());
        c1->redo();
        ResourceGroup *g = p1.resourceGroups().at(0);
        QVERIFY(g);
        delete c1;

        AddResourceCmd *c2 = new AddResourceCmd(g, new Resource());
        c2->redo();
        Resource *r1 = g->resourceAt(0);
        QVERIFY(r1);
        delete c2;
        c2 = new AddResourceCmd(g, new Resource());
        c2->redo();
        Resource *r2 = g->resourceAt(1);
        QVERIFY(r2);
        delete c2;
        c2 = new AddResourceCmd(g, new Resource());
        c2->redo();
        Resource *r3 = g->resourceAt(2);
        QVERIFY(r3);
        delete c2;

        AddResourceTeamCmd *c3 = new AddResourceTeamCmd(r1, r2->id());
        c3->redo();
        delete c3;
        QCOMPARE(r1->teamMemberIds().count(), 1);
        QCOMPARE(r1->teamMembers().count(), 1);
        QCOMPARE(r1->teamMembers().at(0), r2);

        c3 = new AddResourceTeamCmd(r1, r3->id());
        c3->redo();
        delete c3;
        QCOMPARE(r1->teamMemberIds().count(), 2);
        QCOMPARE(r1->teamMembers().count(), 2);
        QCOMPARE(r1->teamMembers().at(1), r3);

        RemoveResourceTeamCmd *c4 = new RemoveResourceTeamCmd(r1, r2->id());
        c4->redo();
        delete c4;
        QCOMPARE(r1->teamMemberIds().count(), 1);
        QCOMPARE(r1->teamMembers().count(), 1);
        QCOMPARE(r1->teamMembers().at(0), r3);
    }

    {
        Project p1;
        p1.setId("p1");

        AddResourceGroupCmd *c1 = new AddResourceGroupCmd(&p1, new ResourceGroup());
        c1->redo();
        ResourceGroup *g = p1.resourceGroups().at(0);
        QVERIFY(g);
        delete c1;

        Resource *r1 = new Resource();
        r1->setType(Resource::Type_Team);
        AddResourceCmd *c2 = new AddResourceCmd(g, r1);
        c2->redo();
        r1 = g->resourceAt(0);
        QVERIFY(r1);
        delete c2;
        c2 = new AddResourceCmd(g, new Resource());
        c2->redo();
        Resource *r2 = g->resourceAt(1);
        QVERIFY(r2);
        delete c2;
        c2 = new AddResourceCmd(g, new Resource());
        c2->redo();
        Resource *r3 = g->resourceAt(2);
        QVERIFY(r3);
        delete c2;

        AddResourceTeamCmd *c3 = new AddResourceTeamCmd(r1, r2->id());
        c3->redo();
        delete c3;
        QCOMPARE(r1->teamMemberIds().count(), 1);
        QCOMPARE(r1->teamMembers().count(), 1);
        QCOMPARE(r1->teamMembers().at(0), r2);

        c3 = new AddResourceTeamCmd(r1, r3->id());
        c3->redo();
        delete c3;
        QCOMPARE(r1->teamMemberIds().count(), 2);
        QCOMPARE(r1->teamMembers().count(), 2);
        QCOMPARE(r1->teamMembers().at(1), r3);

        // copy
        Project p2;

        c1 = new AddResourceGroupCmd(&p2, new ResourceGroup(g));
        c1->redo();
        ResourceGroup *g2 = p2.resourceGroups().at(0);
        QVERIFY(g2);
        delete c1;

        c2 = new AddResourceCmd(g2, new Resource(r1));
        c2->redo();
        Resource *r11 = g2->resourceAt(0);
        QVERIFY(r11);
        delete c2;
        c2 = new AddResourceCmd(g2, new Resource(r2));
        c2->redo();
        Resource *r12 = g->resourceAt(1);
        QVERIFY(r12);
        delete c2;
        c2 = new AddResourceCmd(g2, new Resource(r3));
        c2->redo();
        Resource *r13 = g->resourceAt(2);
        QVERIFY(r13);
        delete c2;

        QCOMPARE(r1->teamMemberIds().count(), 2);
        QCOMPARE(r1->teamMembers().count(), 2);
        QCOMPARE(r1->teamMembers().at(0), r12);
        QCOMPARE(r1->teamMembers().at(1), r13);

        // xml
        QDomDocument qdoc;
        QDomElement e = qdoc.createElement("plan");
        qdoc.appendChild(e);
        p1.save(e, XmlSaveContext());

        KoXmlDocument xdoc;
        xdoc.setContent(qdoc.toString());
        XMLLoaderObject sts;

        Project p3;
        sts.setProject(&p3);
        sts.setVersion(PLAN_FILE_SYNTAX_VERSION);
        KoXmlElement xe = xdoc.documentElement().firstChildElement();
        p3.load(xe, sts);

        QCOMPARE(p3.numResourceGroups(), 1);
        ResourceGroup *g3 = p3.resourceGroupAt(0);
        QCOMPARE(g3->numResources(), 3);
        Resource *r21 = g3->resourceAt(0);
        QCOMPARE(r21->type(), Resource::Type_Team);
        QCOMPARE(r21->teamMemberIds().count(), 2);
        QCOMPARE(r21->teamMembers().count(), 2);
        QCOMPARE(r21->teamMembers().at(0), g3->resourceAt(1));
        QCOMPARE(r21->teamMembers().at(1), g3->resourceAt(2));
    }
    {
        // team members in different group
        Project p1;
        p1.setId("p1");

        AddResourceGroupCmd *c1 = new AddResourceGroupCmd(&p1, new ResourceGroup());
        c1->redo();
        ResourceGroup *g = p1.resourceGroups().at(0);
        QVERIFY(g);
        delete c1;
        ResourceGroup *mg = new ResourceGroup();
        c1 = new AddResourceGroupCmd(&p1, mg);
        c1->redo();
        QCOMPARE(mg, p1.resourceGroups().at(1));
        delete c1;

        Resource *r1 = new Resource();
        r1->setType(Resource::Type_Team);
        AddResourceCmd *c2 = new AddResourceCmd(g, r1);
        c2->redo();
        QCOMPARE(r1, g->resourceAt(0));
        delete c2;
        Resource *r2 = new Resource();
        c2 = new AddResourceCmd(mg, r2);
        c2->redo();
        QCOMPARE(r2, mg->resourceAt(0));
        delete c2;
        Resource *r3 = new Resource();
        c2 = new AddResourceCmd(mg, r3);
        c2->redo();
        QCOMPARE(r3, mg->resourceAt(1));
        delete c2;

        AddResourceTeamCmd *c3 = new AddResourceTeamCmd(r1, r2->id());
        c3->redo();
        delete c3;
        QCOMPARE(r1->teamMemberIds().count(), 1);
        QCOMPARE(r1->teamMembers().count(), 1);
        QCOMPARE(r1->teamMembers().at(0), r2);

        c3 = new AddResourceTeamCmd(r1, r3->id());
        c3->redo();
        delete c3;
        QCOMPARE(r1->teamMemberIds().count(), 2);
        QCOMPARE(r1->teamMembers().count(), 2);
        QCOMPARE(r1->teamMembers().at(0), r2);
        QCOMPARE(r1->teamMembers().at(1), r3);

        // copy
        Project p2;

        c1 = new AddResourceGroupCmd(&p2, new ResourceGroup(g));
        c1->redo();
        ResourceGroup *g2 = p2.resourceGroups().at(0);
        QVERIFY(g2);
        delete c1;

        c1 = new AddResourceGroupCmd(&p2, new ResourceGroup(mg));
        c1->redo();
        ResourceGroup *mg2 = p2.resourceGroups().at(1);
        QVERIFY(mg2);
        delete c1;

        c2 = new AddResourceCmd(g2, new Resource(r1));
        c2->redo();
        Resource *r11 = g2->resourceAt(0);
        QVERIFY(r11);
        delete c2;
        c2 = new AddResourceCmd(mg2, new Resource(r2));
        c2->redo();
        Resource *r12 = mg2->resourceAt(0);
        QVERIFY(r12);
        delete c2;
        c2 = new AddResourceCmd(mg2, new Resource(r3));
        c2->redo();
        Resource *r13 = mg2->resourceAt(1);
        QVERIFY(r13);
        delete c2;

        QCOMPARE(r11->teamMemberIds().count(), 2);
        QCOMPARE(r11->teamMembers().count(), 2);
        QCOMPARE(r11->teamMembers().at(0), r12);
        QCOMPARE(r11->teamMembers().at(1), r13);

        // xml
        QDomDocument qdoc;
        QDomElement e = qdoc.createElement("plan");
        qdoc.appendChild(e);
        p1.save(e, XmlSaveContext());

        KoXmlDocument xdoc;
        xdoc.setContent(qdoc.toString());
        XMLLoaderObject sts;

        Project p3;
        sts.setProject(&p3);
        sts.setVersion(PLAN_FILE_SYNTAX_VERSION);
        KoXmlElement xe = xdoc.documentElement().firstChildElement();
        p3.load(xe, sts);

        QCOMPARE(p3.numResourceGroups(), 2);
        ResourceGroup *g3 = p3.resourceGroupAt(0);
        QCOMPARE(g3->numResources(), 1);
        ResourceGroup *mg3 = p3.resourceGroupAt(1);
        QCOMPARE(mg3->numResources(), 2);
        Resource *r21 = g3->resourceAt(0);
        QCOMPARE(r21->type(), Resource::Type_Team);
        QCOMPARE(r21->teamMemberIds().count(), 2);
        QCOMPARE(r21->teamMembers().count(), 2);
        QCOMPARE(r21->teamMembers().at(0), mg3->resourceAt(0));
        QCOMPARE(r21->teamMembers().at(1), mg3->resourceAt(1));
    }

}

void ResourceTester::required()
{
    Project p;
    AddResourceGroupCmd *c1 = new AddResourceGroupCmd(&p, new ResourceGroup());
    c1->redo();

    ResourceGroup *g = p.resourceGroups().at(0);
    QVERIFY(g);
    delete c1;

    AddResourceCmd *c2 = new AddResourceCmd(g, new Resource());
    c2->redo();
    Resource *r1 = g->resourceAt(0);
    QVERIFY(r1);
    delete c2;
    c2 = new AddResourceCmd(g, new Resource());
    c2->redo();
    Resource *r2 = g->resourceAt(1);
    QVERIFY(r2);
    delete c2;
    c2 = new AddResourceCmd(g, new Resource());
    c2->redo();
    Resource *r3 = g->resourceAt(2);
    QVERIFY(r3);
    delete c2;

    QVERIFY(r1->requiredIds().isEmpty());
    QVERIFY(r1->requiredResources().isEmpty());

    r1->addRequiredId(""); // not allowed to add empty id
    QVERIFY(r1->requiredIds().isEmpty());

    r1->addRequiredId(r2->id());
    QCOMPARE(r1->requiredIds().count(), 1);
    QCOMPARE(r1->requiredResources().count(), 1);
    QCOMPARE(r1->requiredResources().at(0), r2);

    r1->addRequiredId(r3->id());
    QCOMPARE(r1->requiredIds().count(), 2);
    QCOMPARE(r1->requiredResources().count(), 2);
    QCOMPARE(r1->requiredResources().at(0), r2);
    QCOMPARE(r1->requiredResources().at(1), r3);

    r1->addRequiredId(r2->id()); // not allowed to add existing id
    QCOMPARE(r1->requiredIds().count(), 2);
    QCOMPARE(r1->requiredResources().count(), 2);
    QCOMPARE(r1->requiredResources().at(0), r2);
    QCOMPARE(r1->requiredResources().at(1), r3);

    QStringList lst;
    r1->setRequiredIds(lst);
    QCOMPARE(r1->requiredIds().count(), 0);
    QCOMPARE(r1->requiredIds().count(), 0);

    lst << r2->id() << r3->id();
    r1->setRequiredIds(lst);
    QCOMPARE(r1->requiredIds().count(), 2);
    QCOMPARE(r1->requiredResources().count(), 2);
    QCOMPARE(r1->requiredResources().at(0), r2);
    QCOMPARE(r1->requiredResources().at(1), r3);

    // copy to different project
    Project p2;
    c1 = new AddResourceGroupCmd(&p2, new ResourceGroup(g));
    c1->redo();
    delete c1;

    ResourceGroup *g1 = p2.resourceGroupAt(0);
    c2 = new AddResourceCmd(g1, new Resource(r1));
    c2->redo();
    Resource *r4 = g1->resourceAt(0);
    QVERIFY(r4);
    delete c2;
    c2 = new AddResourceCmd(g1, new Resource(r2));
    c2->redo();
    Resource *r5 = g1->resourceAt(1);
    QVERIFY(r5);
    delete c2;
    c2 = new AddResourceCmd(g1, new Resource(r3));
    c2->redo();
    Resource *r6 = g1->resourceAt(2);
    QVERIFY(r6);
    delete c2;

    QCOMPARE(r4->requiredIds().count(), 2);
    QCOMPARE(r4->requiredResources().count(), 2);
    QCOMPARE(r4->requiredResources().at(0), r5);
    QCOMPARE(r4->requiredResources().at(1), r6);

    // using xml
    {
        QDomDocument qdoc;
        QDomElement e = qdoc.createElement("plan");
        qdoc.appendChild(e);
        p2.setId("p2");
        p2.save(e, XmlSaveContext());

        KoXmlDocument xdoc;
        xdoc.setContent(qdoc.toString());
        XMLLoaderObject sts;
        sts.setProject(&p);
        sts.setVersion(PLAN_FILE_SYNTAX_VERSION);

        Project p3;
        KoXmlElement xe = xdoc.documentElement().firstChildElement();
        p3.load(xe, sts);

        ResourceGroup *g2 = p3.resourceGroupAt(0);
        QVERIFY(g2);
        QCOMPARE(g2->numResources(), 3);

        Resource *r7 = g2->resourceAt(0);
        QVERIFY(r7);
        Resource *r8 = g2->resourceAt(1);
        QVERIFY(r8);
        Resource *r9 = g2->resourceAt(2);
        QVERIFY(r9);

        QCOMPARE(r7->requiredIds().count(), 2);
        QCOMPARE(r7->requiredResources().count(), 2);
        QCOMPARE(r7->requiredResources().at(0), r8);
        QCOMPARE(r7->requiredResources().at(1), r9);
    }
    {
        // required in different group
        Project p4;
        p4.setId("p4");

        c1 = new AddResourceGroupCmd(&p4, new ResourceGroup());
        c1->redo();
        delete c1;

        ResourceGroup *m = new ResourceGroup();
        m->setType(ResourceGroup::Type_Material);
        c1 = new AddResourceGroupCmd(&p4, m);
        c1->redo();
        delete c1;

        ResourceGroup *g3 = p4.resourceGroupAt(0);
        c2 = new AddResourceCmd(g3, new Resource());
        c2->redo();
        Resource *r10 = g3->resourceAt(0);
        QVERIFY(r4);
        delete c2;

        Resource *r11 = new Resource();
        r11->setType(Resource::Type_Material);
        c2 = new AddResourceCmd(m, r11);
        c2->redo();
        QVERIFY(m->resourceAt(0) == r11);
        delete c2;
        Resource *r12 = new Resource();
        r12->setType(Resource::Type_Material);
        c2 = new AddResourceCmd(m, r12);
        c2->redo();
        QVERIFY(m->resourceAt(1) == r12);
        delete c2;

        r10->addRequiredId(r11->id());
        r10->addRequiredId(r12->id());
        QCOMPARE(r10->requiredIds().count(), 2);
        QCOMPARE(r10->requiredResources().count(), 2);
        QCOMPARE(r10->requiredResources().at(0), r11);
        QCOMPARE(r10->requiredResources().at(1), r12);

        // using xml
        QDomDocument qdoc;
        QDomElement e = qdoc.createElement("plan");
        qdoc.appendChild(e);
        p4.save(e, XmlSaveContext());

        KoXmlDocument xdoc;
        xdoc.setContent(qdoc.toString());
        XMLLoaderObject sts;
        sts.setProject(&p4);
        sts.setVersion(PLAN_FILE_SYNTAX_VERSION);

        Project p5;
        KoXmlElement xe = xdoc.documentElement().firstChildElement();
        p5.load(xe, sts);

        ResourceGroup *g4 = p5.resourceGroupAt(0);
        QVERIFY(g4);
        QCOMPARE(g4->numResources(), 1);

        ResourceGroup *g5 = p5.resourceGroupAt(1);
        QVERIFY(g5);
        QCOMPARE(g5->numResources(), 2);

        Resource *r13 = g4->resourceAt(0);
        QVERIFY(r13);
        QCOMPARE(r13->id(), r10->id());
        Resource *r14 = g5->resourceAt(0);
        QVERIFY(r14);
        QCOMPARE(r14->id(), r11->id());
        Resource *r15 = g5->resourceAt(1);
        QVERIFY(r15);
        QCOMPARE(r15->id(), r12->id());

        QCOMPARE(r13->requiredIds().count(), 2);
        QCOMPARE(r13->requiredResources().count(), 2);
        QCOMPARE(r13->requiredResources().at(0), r14);
        QCOMPARE(r13->requiredResources().at(1), r15);
    }
}

} //namespace KPlato

QTEST_GUILESS_MAIN(KPlato::ResourceTester)
