/* This file is part of the KDE project
   Copyright (C) 2008 Dag Andersen <danders@get2net.dk>
   Copyright (C) 2016 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 "AppointmentIntervalTester.h"
#include <kptappointment.h>
#include <kptdatetime.h>
#include <kptduration.h>

#include <QTest>

#include <QMultiMap>

#include "DateTimeTester.h"
#include "debug.cpp"

namespace KPlato
{

void AppointmentIntervalTester::interval()
{
    DateTime dt1 = DateTime(QDate(2011, 01, 02), QTime(7, 0, 0));
    DateTime dt2 = DateTime(QDate(2011, 01, 02), QTime(8, 0, 0));
    DateTime dt3 = DateTime(QDate(2011, 01, 02), QTime(9, 0, 0));
    DateTime dt4 = DateTime(QDate(2011, 01, 02), QTime(10, 0, 0));

    AppointmentInterval i1(dt1, dt2, 1);
    AppointmentInterval i2(dt1, dt2, 1);

    QVERIFY(! (i1 < i2));
    QVERIFY(! (i2 < i1));

    QVERIFY(i1.intersects(i2));
    QVERIFY(i2.intersects(i1));

    AppointmentInterval i3(dt2, dt3, 1);

    QVERIFY(i1 < i3);
    QVERIFY(! (i3 < i1));

    QVERIFY(! i1.intersects(i3));
    QVERIFY(! i3.intersects(i1));

    AppointmentInterval i4(dt2, dt4, 1);

    QVERIFY(i1 < i4);
    QVERIFY(i2 < i4);
    QVERIFY(i3 < i4);

    QVERIFY(! i1.intersects(i4));
    QVERIFY(! i4.intersects(i1));
    QVERIFY(i3.intersects(i4));
    QVERIFY(i4.intersects(i3));

    AppointmentInterval i5(dt3, dt4, 1);
    QVERIFY(! i1.intersects(i4));
    QVERIFY(! i4.intersects(i1));

}

void AppointmentIntervalTester::addInterval()
{
    AppointmentIntervalList lst;
    DateTime dt1 = DateTime(QDate(2011, 01, 02), QTime(7, 0, 0));
    DateTime dt2 = dt1 + Duration(0, 1, 0);
    double load = 1;
    
    qDebug()<<"Add an interval"<<dt1<<dt2;
    qDebug()<<endl<<lst;
    lst.add(dt1, dt2, load);
    qDebug()<<endl<<lst;

    QCOMPARE(dt1, lst.map().values().first().startTime());
    QCOMPARE(dt2, lst.map().values().first().endTime());
    QCOMPARE(load, lst.map().values().first().load());
    
    qDebug()<<"add load";
    qDebug()<<endl<<lst;
    lst.add(dt1, dt2, load);
    qDebug()<<endl<<lst;

    QCOMPARE(dt1, lst.map().values().first().startTime());
    QCOMPARE(dt2, lst.map().values().first().endTime());
    QCOMPARE(load*2, lst.map().values().first().load());
    
    DateTime dt3 = dt2 + Duration(0, 4, 0);
    DateTime dt4 = dt3 + Duration(0, 1, 0);
    qDebug()<<"Add an interval after:"<<dt3<<dt4;
    
    qDebug()<<endl<<lst;
    lst.add(dt3, dt4, load);
    qDebug()<<endl<<lst;

    QCOMPARE(dt1, lst.map().values().first().startTime());
    QCOMPARE(dt2, lst.map().values().first().endTime());
    QCOMPARE(load*2, lst.map().values().first().load());

    QCOMPARE(dt3, lst.map().values().last().startTime());
    QCOMPARE(dt4, lst.map().values().last().endTime());
    QCOMPARE(load, lst.map().values().last().load());

    DateTime dt5 = dt2 + Duration(0, 2, 0);
    DateTime dt6 = dt5 + Duration(0, 1, 0);
    qDebug()<<"Add an interval in between:"<<dt5<<dt6;

    qDebug()<<endl<<lst;
    lst.add(dt5, dt6, load);
    qDebug()<<endl<<lst;
{
    QMap<QDate, AppointmentInterval>::const_iterator i(lst.map().constBegin());

    QCOMPARE(dt1, i.value().startTime());
    QCOMPARE(dt2, i.value().endTime());
    QCOMPARE(load*2, i.value().load());
    ++i;
    QCOMPARE(dt5, i.value().startTime());
    QCOMPARE(dt6, i.value().endTime());
    QCOMPARE(load, i.value().load());
    ++i;
    QCOMPARE(dt3, i.value().startTime());
    QCOMPARE(dt4, i.value().endTime());
    QCOMPARE(load, i.value().load());
}    
    DateTime dt7 = dt1 - Duration(0, 1, 0);
    DateTime dt8 = dt7 + Duration(0, 2, 0);
    qDebug()<<"Add an overlapping interval at start:"<<dt7<<dt8;
    
    qDebug()<<endl<<lst;
    lst.add(dt7, dt8, load);
    qDebug()<<endl<<lst;
{
    QMap<QDate, AppointmentInterval>::const_iterator i(lst.map().constBegin());

    QCOMPARE(dt7, i.value().startTime());
    QCOMPARE(dt1, i.value().endTime());
    QCOMPARE(load, i.value().load());
    ++i;
    QCOMPARE(dt1, i.value().startTime());
    QCOMPARE(dt8, i.value().endTime());
    QCOMPARE(load*3, i.value().load());
    ++i;
    QCOMPARE(dt5, i.value().startTime());
    QCOMPARE(dt6, i.value().endTime());
    QCOMPARE(load, i.value().load());
    ++i;
    QCOMPARE(dt3, i.value().startTime());
    QCOMPARE(dt4, i.value().endTime());
    QCOMPARE(load, i.value().load());
}
    DateTime dt9 = dt7 +  Duration(0, 0, 30);
    DateTime dt10 = dt9 + Duration(0, 0, 30);
    qDebug()<<"Add an overlapping interval at start > start, end == end"<<dt9<<dt10;
    
    qDebug()<<endl<<lst;
    lst.add(dt9, dt10, load);
    qDebug()<<endl<<lst;
{
    QMap<QDate, AppointmentInterval>::const_iterator i(lst.map().constBegin());

    QCOMPARE(dt7, i.value().startTime());
    QCOMPARE(dt9, i.value().endTime());
    QCOMPARE(load, i.value().load());
    ++i;
    QCOMPARE(dt9, i.value().startTime());
    QCOMPARE(dt10, i.value().endTime());
    QCOMPARE(load*2, i.value().load());
    ++i;
    QCOMPARE(dt1, i.value().startTime());
    QCOMPARE(dt8, i.value().endTime());
    QCOMPARE(load*3, i.value().load());
    ++i;
    QCOMPARE(dt5, i.value().startTime());
    QCOMPARE(dt6, i.value().endTime());
    QCOMPARE(load, i.value().load());
    ++i;
    QCOMPARE(dt3, i.value().startTime());
    QCOMPARE(dt4, i.value().endTime());
    QCOMPARE(load, i.value().load());
}
    DateTime dt11 = dt3 +  Duration(0, 0, 10);
    DateTime dt12 = dt11 + Duration(0, 0, 30);
    qDebug()<<"Add an overlapping interval at start > start, end < end:"<<dt11<<dt12;
    
    qDebug()<<endl<<lst;
    lst.add(dt11, dt12, load);
    qDebug()<<endl<<lst;
{
    QCOMPARE(lst.map().count(), 7);
    QMap<QDate, AppointmentInterval>::const_iterator i(lst.map().constBegin());

    QCOMPARE(dt7, i.value().startTime());
    QCOMPARE(dt9, i.value().endTime());
    QCOMPARE(load, i.value().load());
    ++i;
    QCOMPARE(dt9, i.value().startTime());
    QCOMPARE(dt10, i.value().endTime());
    QCOMPARE(load*2, i.value().load());
    ++i;
    QCOMPARE(dt1, i.value().startTime());
    QCOMPARE(dt8, i.value().endTime());
    QCOMPARE(load*3, i.value().load());
    ++i;
    QCOMPARE(dt5, i.value().startTime());
    QCOMPARE(dt6, i.value().endTime());
    QCOMPARE(load, i.value().load());
    ++i;
    QCOMPARE(dt3, i.value().startTime());
    QCOMPARE(dt11, i.value().endTime());
    QCOMPARE(load, i.value().load());
    ++i;
    QCOMPARE(dt11, i.value().startTime());
    QCOMPARE(dt12, i.value().endTime());
    QCOMPARE(load*2, i.value().load());
    ++i;
    QCOMPARE(dt12, i.value().startTime());
    QCOMPARE(dt4, i.value().endTime());
    QCOMPARE(load, i.value().load());
}
    qDebug()<<"Add an interval overlapping 2 intervals at start == start.1, end == end.2"<<dt1<<dt4;
    lst.clear();
    
    qDebug()<<endl<<lst;
    lst.add(dt1, dt2, load);
    qDebug()<<endl<<lst;
    lst.add(dt3, dt4, load);
    qDebug()<<endl<<lst;
    lst.add(dt1, dt4, load);
    qDebug()<<endl<<lst;
{
    QCOMPARE(lst.map().count(), 3);
    QMap<QDate, AppointmentInterval>::const_iterator i(lst.map().constBegin());

    QCOMPARE(dt1, i.value().startTime());
    QCOMPARE(dt2, i.value().endTime());
    QCOMPARE(load*2, i.value().load());
    ++i;
    QCOMPARE(dt2, i.value().startTime());
    QCOMPARE(dt3, i.value().endTime());
    QCOMPARE(load, i.value().load());
    ++i;
    QCOMPARE(dt3, i.value().startTime());
    QCOMPARE(dt4, i.value().endTime());
    QCOMPARE(load*2, i.value().load());
}
    lst.clear();
    dt5 = dt1 - Duration(0, 1, 0);
    qDebug()<<"Add an interval overlapping 2 intervals at start < start.1, end == end.2"<<dt5<<dt4;

    qDebug()<<endl<<lst;
    lst.add(dt1, dt2, load);
    qDebug()<<endl<<lst;
    lst.add(dt3, dt4, load);
    qDebug()<<endl<<lst;
    lst.add(dt5, dt4, load);
    qDebug()<<endl<<lst;
{
    QCOMPARE(lst.map().count(), 4);
    QMap<QDate, AppointmentInterval>::const_iterator i(lst.map().constBegin());

    QCOMPARE(dt5, i.value().startTime());
    QCOMPARE(dt1, i.value().endTime());
    QCOMPARE(load, i.value().load());
    ++i;
    QCOMPARE(dt1, i.value().startTime());
    QCOMPARE(dt2, i.value().endTime());
    QCOMPARE(load*2, i.value().load());
    ++i;
    QCOMPARE(dt2, i.value().startTime());
    QCOMPARE(dt3, i.value().endTime());
    QCOMPARE(load, i.value().load());
    ++i;
    QCOMPARE(dt3, i.value().startTime());
    QCOMPARE(dt4, i.value().endTime());
    QCOMPARE(load*2, i.value().load());
}
    // Add an interval overlapping 2 intervals at start < start.1, end > end.2
    lst.clear();
    dt5 = dt1 - Duration(0, 1, 0);
    dt6 = dt4 + Duration(0, 1, 0);
    lst.add(dt1, dt2, load);
    lst.add(dt3, dt4, load);
    lst.add(dt5, dt6, load);
{
    QMap<QDate, AppointmentInterval>::const_iterator i(lst.map().constBegin());

    QCOMPARE(dt5, i.value().startTime());
    QCOMPARE(dt1, i.value().endTime());
    QCOMPARE(load, i.value().load());
    ++i;
    QCOMPARE(dt1, i.value().startTime());
    QCOMPARE(dt2, i.value().endTime());
    QCOMPARE(load*2, i.value().load());
    ++i;
    QCOMPARE(dt2, i.value().startTime());
    QCOMPARE(dt3, i.value().endTime());
    QCOMPARE(load, i.value().load());
    ++i;
    QCOMPARE(dt3, i.value().startTime());
    QCOMPARE(dt4, i.value().endTime());
    QCOMPARE(load*2, i.value().load());
    ++i;
    QCOMPARE(dt4, i.value().startTime());
    QCOMPARE(dt6, i.value().endTime());
    QCOMPARE(load, i.value().load());
}
    // Add an interval overlapping 2 intervals at start < start.1, end < end.2
    lst.clear();
    dt5 = dt1 - Duration(0, 1, 0);
    dt6 = dt4 - Duration(0, 0, 30);
    lst.add(dt1, dt2, load);
    lst.add(dt3, dt4, load);
    lst.add(dt5, dt6, load);
{
    QMap<QDate, AppointmentInterval>::const_iterator i(lst.map().constBegin());

    QCOMPARE(dt5, i.value().startTime());
    QCOMPARE(dt1, i.value().endTime());
    QCOMPARE(load, i.value().load());
    ++i;
    QCOMPARE(dt1, i.value().startTime());
    QCOMPARE(dt2, i.value().endTime());
    QCOMPARE(load*2, i.value().load());
    ++i;
    QCOMPARE(dt2, i.value().startTime());
    QCOMPARE(dt3, i.value().endTime());
    QCOMPARE(load, i.value().load());
    ++i;
    QCOMPARE(dt3, i.value().startTime());
    QCOMPARE(dt6, i.value().endTime());
    QCOMPARE(load*2, i.value().load());
    ++i;
    QCOMPARE(dt6, i.value().startTime());
    QCOMPARE(dt4, i.value().endTime());
    QCOMPARE(load, i.value().load());
}
    // Add an interval overlapping 2 intervals at start > start.1, end < end.2
    lst.clear();
    dt5 = dt1 + Duration(0, 0, 30);
    dt6 = dt4 - Duration(0, 0, 30);
    lst.add(dt1, dt2, load);
    lst.add(dt3, dt4, load);
    lst.add(dt5, dt6, load);
{
    QMap<QDate, AppointmentInterval>::const_iterator i(lst.map().constBegin());

    QCOMPARE(dt1, i.value().startTime());
    QCOMPARE(dt5, i.value().endTime());
    QCOMPARE(load, i.value().load());
    ++i;
    QCOMPARE(dt5, i.value().startTime());
    QCOMPARE(dt2, i.value().endTime());
    QCOMPARE(load*2, i.value().load());
    ++i;
    QCOMPARE(dt2, i.value().startTime());
    QCOMPARE(dt3, i.value().endTime());
    QCOMPARE(load, i.value().load());
    ++i;
    QCOMPARE(dt3, i.value().startTime());
    QCOMPARE(dt6, i.value().endTime());
    QCOMPARE(load*2, i.value().load());
    ++i;
    QCOMPARE(dt6, i.value().startTime());
    QCOMPARE(dt4, i.value().endTime());
    QCOMPARE(load, i.value().load());
}
    // Add an interval overlapping 2 intervals at start > start.1, end == end.2
    lst.clear();
    dt5 = dt1 + Duration(0, 0, 30);
    dt6 = dt4;
    lst.add(dt1, dt2, load);
    lst.add(dt3, dt4, load);
    lst.add(dt5, dt6, load);
{
    QMap<QDate, AppointmentInterval>::const_iterator i(lst.map().constBegin());

    QCOMPARE(dt1, i.value().startTime());
    QCOMPARE(dt5, i.value().endTime());
    QCOMPARE(load, i.value().load());
    ++i;
    QCOMPARE(dt5, i.value().startTime());
    QCOMPARE(dt2, i.value().endTime());
    QCOMPARE(load*2, i.value().load());
    ++i;
    QCOMPARE(dt2, i.value().startTime());
    QCOMPARE(dt3, i.value().endTime());
    QCOMPARE(load, i.value().load());
    ++i;
    QCOMPARE(dt3, i.value().startTime());
    QCOMPARE(dt6, i.value().endTime());
    QCOMPARE(load*2, i.value().load());
}
    // Add an interval overlapping 2 intervals at start > start.1, end > end.2
    lst.clear();
    dt5 = dt1 + Duration(0, 0, 30);
    dt6 = dt4 + Duration(0, 0, 30);
    lst.add(dt1, dt2, load);
    lst.add(dt3, dt4, load);
    lst.add(dt5, dt6, load);
{
    QMap<QDate, AppointmentInterval>::const_iterator i(lst.map().constBegin());

    QCOMPARE(dt1, i.value().startTime());
    QCOMPARE(dt5, i.value().endTime());
    QCOMPARE(load, i.value().load());
    ++i;
    QCOMPARE(dt5, i.value().startTime());
    QCOMPARE(dt2, i.value().endTime());
    QCOMPARE(load*2, i.value().load());
    ++i;
    QCOMPARE(dt2, i.value().startTime());
    QCOMPARE(dt3, i.value().endTime());
    QCOMPARE(load, i.value().load());
    ++i;
    QCOMPARE(dt3, i.value().startTime());
    QCOMPARE(dt4, i.value().endTime());
    QCOMPARE(load*2, i.value().load());
    ++i;
    QCOMPARE(dt4, i.value().startTime());
    QCOMPARE(dt6, i.value().endTime());
    QCOMPARE(load, i.value().load());
}

}

void AppointmentIntervalTester::addTangentIntervals()
{
    // Add an interval overlapping 2 intervals at start > start.1, end > end.2
    AppointmentIntervalList lst;

    DateTime dt1(QDate(2010, 1, 1), QTime(0, 0, 0));
    DateTime dt2(QDate(2010, 1, 1), QTime(12, 0, 0));
    double load = 1.;

    qDebug()<<endl<<lst;
    lst.add(dt2, dt1.addDays(1), load);
    qDebug()<<endl<<lst;
    QCOMPARE(lst.map().count(), 1);

    lst.add(dt1, dt2, load);
    QCOMPARE(lst.map().count(), 2);
    QCOMPARE(lst.map().values().at(0).startTime(), dt1);
    QCOMPARE(lst.map().values().at(1).endTime(), DateTime(dt1.addDays(1)));
    
    // add with a 12 hours hole
    lst.add(dt2.addDays(1), dt1.addDays(2), load);
    QCOMPARE(lst.map().count(), 3);
    
    // fill the hole
    lst.add(dt1.addDays(1), dt2.addDays(1), load);
    QCOMPARE(lst.map().count(), 4);
}

void AppointmentIntervalTester::addAppointment()
{
    Appointment app1, app2;

    DateTime dt1 = DateTime(QDate(2011, 01, 02), QTime(7, 0, 0));
    DateTime dt2 = dt1 + Duration(0, 1, 0);
    double load = 1;
    
    app2.addInterval(dt1, dt2, load);
    app1 += app2;
    QCOMPARE(dt1, app1.intervals().map().values().first().startTime());
    QCOMPARE(dt2, app1.intervals().map().values().first().endTime());
    QCOMPARE(load, app1.intervals().map().values().first().load());

    app1 += app2;
    qDebug()<<load<<app1.intervals().map().values().first().load();
    QCOMPARE(dt1, app1.intervals().map().values().first().startTime());
    QCOMPARE(dt2, app1.intervals().map().values().first().endTime());
    QCOMPARE(load*2, app1.intervals().map().values().first().load());
}

void AppointmentIntervalTester::subtractList()
{
    QString s;

    AppointmentIntervalList lst1;
    AppointmentIntervalList lst2;
    DateTime dt1 = DateTime(QDate(2011, 01, 02), QTime(7, 0, 0));
    DateTime dt2 = dt1 + Duration(0, 3, 0);
    double load = 100;
    
    lst1.add(dt1, dt2, load);
    QCOMPARE(dt1, lst1.map().values().first().startTime());
    QCOMPARE(dt2, lst1.map().values().first().endTime());
    QCOMPARE(load, lst1.map().values().first().load());
    
    lst2 += lst1;
    QCOMPARE(dt1, lst2.map().values().first().startTime());
    QCOMPARE(dt2, lst2.map().values().first().endTime());
    QCOMPARE(load, lst2.map().values().first().load());
    QCOMPARE(lst2.map().count(), 1);
    
    lst2 -= lst1;
    QVERIFY(lst2.isEmpty());
    
    lst2.add(dt1, dt2, load * 2.);
    lst2 -= lst1;
    QCOMPARE(dt1, lst2.map().values().first().startTime());
    QCOMPARE(dt2, lst2.map().values().first().endTime());
    QCOMPARE(load, lst2.map().values().first().load());
    QCOMPARE(lst2.map().count(), 1);
    
    lst1.clear();
    DateTime dt3 = dt2 + Duration(0, 6, 0);
    DateTime dt4 = dt3 + Duration(0, 1, 0);
    lst1.add(dt3, dt4, load);
    qDebug()<<"Subtract non-overlapping intervals:";

    qDebug()<<endl<<lst2<<endl<<"minus"<<endl<<lst1;
    lst2 -= lst1;
    qDebug()<<endl<<"result:"<<endl<<lst2;
    QCOMPARE(dt1, lst2.map().values().first().startTime());
    QCOMPARE(dt2, lst2.map().values().first().endTime());
    QCOMPARE(load, lst2.map().values().first().load());
    QCOMPARE(lst2.map().count(), 1);
    
    DateTime dt5 = dt1 - Duration(0, 6, 0);
    DateTime dt6 = dt5 + Duration(0, 1, 0);
    lst1.add(dt5, dt6, load);

    qDebug()<<"-------- lst2 -= lst1";
    qDebug()<<endl<<lst2<<endl<<lst1;
    lst2 -= lst1;
    qDebug()<<endl<<lst2;
    QCOMPARE(dt1, lst2.map().values().first().startTime());
    QCOMPARE(dt2, lst2.map().values().first().endTime());
    QCOMPARE(load, lst2.map().values().first().load());
    QCOMPARE(lst2.map().count(), 1);

    s = "Subtract tangent intervals";
    qDebug()<<s;
    lst1.clear();
    lst1.add(dt1.addDays(-1), dt1, load); // before
    Debug::print(lst2, "List2: " + s);
    Debug::print(lst1, "List1: " + s);

    lst2 -= lst1;
    Debug::print(lst2, "Result: " + s);
    
    QCOMPARE(dt1, lst2.map().values().first().startTime());
    QCOMPARE(dt2, lst2.map().values().first().endTime());
    QCOMPARE(load, lst2.map().values().first().load());
    QCOMPARE(lst2.map().count(), 1);

    lst1.clear();
    lst1.add(dt2, dt2.addDays(1), load); // after

    lst2 -= lst1;
    QCOMPARE(dt1, lst2.map().values().first().startTime());
    QCOMPARE(dt2, lst2.map().values().first().endTime());
    QCOMPARE(load, lst2.map().values().first().load());
    QVERIFY(lst2.map().count() == 1);
    
    // Subtract overlapping intervals
    lst1.clear();
    dt3 = dt1 + Duration(0, 1, 0);
    // starts at start, end in the middle
    lst1.add(dt1, dt3, load / 2.);

    s = "Subtract half the load of the first hour of the interval";
    qDebug()<<s;
    Debug::print(lst2, "List2: " + s);
    Debug::print(lst1, "List1: " + s);

    lst2 -= lst1;
    Debug::print(lst2, s);

    QCOMPARE(lst2.map().count(), 2);
    QCOMPARE(dt1, lst2.map().values().first().startTime());
    QCOMPARE(dt3, lst2.map().values().first().endTime());
    QCOMPARE(load / 2., lst2.map().values().first().load());

    QCOMPARE(dt3, lst2.map().values().at(1).startTime());
    QCOMPARE(dt2, lst2.map().values().at(1).endTime());
    QCOMPARE(load, lst2.map().values().at(1).load());

    s = "Subtract all load from first interval";
    qDebug()<<s;
    lst2 -= lst1; // remove first interval
    QCOMPARE(lst2.map().count(), 1);
    QCOMPARE(dt3, lst2.map().values().at(0).startTime());
    QCOMPARE(dt2, lst2.map().values().at(0).endTime());
    QCOMPARE(load, lst2.map().values().at(0).load());

    s = "Subtract half the load from last hour of the interval";
    qDebug()<<s;
    lst1.clear();
    dt4 = dt2 - Duration(0, 1, 0);
    lst1.add(dt4, dt2, 50.);
    
    Debug::print(lst1, "List1: " + s);
    Debug::print(lst2, "List2: " + s);
    lst2 -= lst1;
    
    QCOMPARE(lst2.map().count(), 2);
    QCOMPARE(dt3, lst2.map().values().at(0).startTime());
    QCOMPARE(dt4, lst2.map().values().at(0).endTime());
    QCOMPARE(load, lst2.map().values().at(0).load());

    QCOMPARE(dt4, lst2.map().values().at(1).startTime());
    QCOMPARE(dt2, lst2.map().values().at(1).endTime());
    QCOMPARE(50., lst2.map().values().at(1).load());

    s = "Subtract all load from last interval";
    qDebug()<<s;
    Debug::print(lst1, "List1: " + s);
    Debug::print(lst2, "List2: " + s);

    AppointmentInterval i = lst2.map().values().at(0);
    lst2 -= lst1;
    Debug::print(lst2, "Result: " + s);

    QCOMPARE(lst2.map().count(), 1);
    QCOMPARE(i.startTime(), lst2.map().values().at(0).startTime());
    QCOMPARE(i.endTime(), lst2.map().values().at(0).endTime());
    QCOMPARE(i.load(), lst2.map().values().at(0).load());

    // Subtract overlapping intervals (start < start, end > end)
    lst1.clear();
    lst2.clear();
    lst2.add(dt1, dt2, 100.);

    dt3 = dt1 + Duration(0, 1, 0);
    // starts before start, end in the middle
    lst1.add(dt1.addSecs(-10), dt3, load / 2.);

    s = "Subtract half the load of the first hour of the interval";
    qDebug()<<s;
    Debug::print(lst2, "List2: " + s);
    Debug::print(lst1, "List1: " + s);

    lst2 -= lst1;
    Debug::print(lst2, s);

    QCOMPARE(lst2.map().count(), 2);
    QCOMPARE(dt1, lst2.map().values().first().startTime());
    QCOMPARE(dt3, lst2.map().values().first().endTime());
    QCOMPARE(load / 2., lst2.map().values().first().load());

    QCOMPARE(dt3, lst2.map().values().at(1).startTime());
    QCOMPARE(dt2, lst2.map().values().at(1).endTime());
    QCOMPARE(load, lst2.map().values().at(1).load());

    s = "Subtract all load from first interval";
    qDebug()<<s;
    lst2 -= lst1; // remove first interval
    QCOMPARE(lst2.map().count(), 1);
    QCOMPARE(dt3, lst2.map().values().at(0).startTime());
    QCOMPARE(dt2, lst2.map().values().at(0).endTime());
    QCOMPARE(load, lst2.map().values().at(0).load());

    s = "Subtract half the load from last hour of the interval";
    qDebug()<<s;
    lst1.clear();
    dt4 = dt2 - Duration(0, 1, 0);
    lst1.add(dt4, dt2.addSecs(10), 50.);
    
    Debug::print(lst2, "List2: " + s);
    Debug::print(lst1, "List1: " + s);
    lst2 -= lst1;
    
    Debug::print(lst2, "Result: " + s);

    QCOMPARE(lst2.map().count(), 2);
    QCOMPARE(dt3, lst2.map().values().at(0).startTime());
    QCOMPARE(dt4, lst2.map().values().at(0).endTime());
    QCOMPARE(load, lst2.map().values().at(0).load());

    QCOMPARE(dt4, lst2.map().values().at(1).startTime());
    QCOMPARE(dt2, lst2.map().values().at(1).endTime());
    QCOMPARE(50., lst2.map().values().at(1).load());

    s = "Subtract all load from last interval";
    qDebug()<<s;
    Debug::print(lst1, "List1: " + s);
    Debug::print(lst2, "List2: " + s);

    i = lst2.map().values().at(0);
    qDebug()<<"i:"<<i;
    lst2 -= lst1;
    Debug::print(lst2, "Result: " + s);

    QCOMPARE(lst2.map().count(), 1);
    QCOMPARE(i.startTime(), lst2.map().values().at(0).startTime());
    QCOMPARE(i.endTime(), lst2.map().values().at(0).endTime());
    QCOMPARE(i.load(), lst2.map().values().at(0).load());
}

void AppointmentIntervalTester::subtractListMidnight()
{
    QString s;

    AppointmentIntervalList lst1;
    AppointmentIntervalList lst2;
    DateTime dt1 = DateTime(QDate(2011, 01, 02), QTime(22, 0, 0));
    DateTime dt2 = dt1 + Duration(0, 3, 0);
    double load = 100;
    
    lst1.add(dt1, dt2, load);
    QCOMPARE(lst1.map().count(), 2);
    QCOMPARE(dt1, lst1.map().values().first().startTime());
    QCOMPARE(dt2, lst1.map().values().last().endTime());
    QCOMPARE(load, lst1.map().values().first().load());
    QCOMPARE(load, lst1.map().values().last().load());
    
    lst2 += lst1;
    QCOMPARE(lst2.map().count(), 2);
    QCOMPARE(dt1, lst2.map().values().first().startTime());
    QCOMPARE(dt2, lst2.map().values().last().endTime());
    QCOMPARE(load, lst2.map().values().first().load());
    QCOMPARE(load, lst2.map().values().last().load());
    
    lst2 -= lst1;
    QVERIFY(lst2.isEmpty());
    
    lst2.add(dt1, dt2, load * 2.);
    lst2 -= lst1;
    QCOMPARE(lst2.map().count(), 2);
    QCOMPARE(dt1, lst2.map().values().first().startTime());
    QCOMPARE(dt2, lst2.map().values().last().endTime());
    QCOMPARE(load, lst2.map().values().first().load());
    QCOMPARE(load, lst2.map().values().last().load());
    
    lst1.clear();
    DateTime dt3 = dt2 + Duration(0, 6, 0);
    DateTime dt4 = dt3 + Duration(0, 1, 0);
    lst1.add(dt3, dt4, load);
    qDebug()<<"Subtract non-overlapping intervals:";

    qDebug()<<endl<<lst2<<endl<<"minus"<<endl<<lst1;
    lst2 -= lst1;
    qDebug()<<endl<<"result:"<<endl<<lst2;
    QCOMPARE(lst2.map().count(), 2);
    QCOMPARE(dt1, lst2.map().values().first().startTime());
    QCOMPARE(dt2, lst2.map().values().last().endTime());
    QCOMPARE(load, lst2.map().values().first().load());
    QCOMPARE(load, lst2.map().values().last().load());
    
    DateTime dt5 = dt1 - Duration(0, 6, 0);
    DateTime dt6 = dt5 + Duration(0, 1, 0);
    lst1.add(dt5, dt6, load);

    qDebug()<<"-------- lst2 -= lst1";
    qDebug()<<endl<<lst2<<endl<<lst1;
    lst2 -= lst1;
    qDebug()<<endl<<lst2;
    QCOMPARE(lst2.map().count(), 2);
    QCOMPARE(dt1, lst2.map().values().first().startTime());
    QCOMPARE(dt2, lst2.map().values().last().endTime());
    QCOMPARE(load, lst2.map().values().first().load());
    QCOMPARE(load, lst2.map().values().last().load());

    s = "Subtract tangent intervals";
    qDebug()<<s;
    lst1.clear();
    lst1.add(dt1.addDays(-1), dt1, load); // before
    Debug::print(lst2, "List2: " + s);
    Debug::print(lst1, "List1: " + s);

    lst2 -= lst1;
    Debug::print(lst2, "Result: " + s);
    
    QCOMPARE(lst2.map().count(), 2);
    QCOMPARE(dt1, lst2.map().values().first().startTime());
    QCOMPARE(dt2, lst2.map().values().last().endTime());
    QCOMPARE(load, lst2.map().values().first().load());
    QCOMPARE(load, lst2.map().values().last().load());

    lst1.clear();
    lst1.add(dt2, dt2.addDays(1), load); // after

    lst2 -= lst1;
    QCOMPARE(lst2.map().count(), 2);
    QCOMPARE(dt1, lst2.map().values().first().startTime());
    QCOMPARE(dt2, lst2.map().values().last().endTime());
    QCOMPARE(load, lst2.map().values().first().load());
    QCOMPARE(load, lst2.map().values().last().load());
    
    // Subtract overlapping intervals
    lst1.clear();
    dt3 = dt1 + Duration(0, 1, 0);
    // starts at start, end in the middle (at 23:00)
    lst1.add(dt1, dt3, load / 2.);

    s = "Subtract half the load of the first hour of the interval";
    qDebug()<<s;
    Debug::print(lst2, "List2: " + s);
    Debug::print(lst1, "List1: " + s);

    lst2 -= lst1;
    Debug::print(lst2, s);

    QCOMPARE(lst2.map().count(), 3);
    QCOMPARE(dt1, lst2.map().values().first().startTime());
    QCOMPARE(dt3, lst2.map().values().first().endTime());
    QCOMPARE(load / 2., lst2.map().values().first().load());

    QCOMPARE(dt3, lst2.map().values().at(1).startTime());
    QCOMPARE(dt2, lst2.map().values().at(2).endTime());
    QCOMPARE(load, lst2.map().values().at(1).load());
    QCOMPARE(load, lst2.map().values().at(2).load());

    s = "Subtract all load from first interval";
    qDebug()<<s;
    lst2 -= lst1; // remove first interval
    QCOMPARE(lst2.map().count(), 2);
    QCOMPARE(dt3, lst2.map().values().at(0).startTime());
    QCOMPARE(dt2, lst2.map().values().at(1).endTime());
    QCOMPARE(load, lst2.map().values().at(0).load());
    QCOMPARE(load, lst2.map().values().at(1).load());

    s = "Subtract half the load from last 30 min of the last interval";
    qDebug()<<s;
    lst1.clear();
    dt4 = dt2 - Duration(0, 0, 30);
    lst1.add(dt4, dt2, 50.);
    
    Debug::print(lst1, "List1: " + s);
    Debug::print(lst2, "List2: " + s);
    lst2 -= lst1;
    
    QCOMPARE(lst2.map().count(), 3);
    QCOMPARE(dt3, lst2.map().values().at(0).startTime());
    QCOMPARE(dt4, lst2.map().values().at(1).endTime());
    QCOMPARE(load, lst2.map().values().at(0).load());
    QCOMPARE(load, lst2.map().values().at(1).load());

    QCOMPARE(dt4, lst2.map().values().at(2).startTime());
    QCOMPARE(dt2, lst2.map().values().at(2).endTime());
    QCOMPARE(50., lst2.map().values().at(2).load());

    s = "Subtract all load from last interval";
    qDebug()<<s;
    Debug::print(lst1, "List1: " + s);
    Debug::print(lst2, "List2: " + s);

    lst2 -= lst1;
    Debug::print(lst2, "Result: " + s);

    QCOMPARE(lst2.map().count(), 2);
    QCOMPARE(dt3, lst2.map().values().at(0).startTime());
    QCOMPARE(dt4, lst2.map().values().at(1).endTime());
    QCOMPARE(load, lst2.map().values().at(0).load());
    QCOMPARE(load, lst2.map().values().at(1).load());

}

} //namespace KPlato

QTEST_GUILESS_MAIN(KPlato::AppointmentIntervalTester)
