// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only

#include <QtTest/QtTest>
#include <QtCharts/QChartView>
#include <QtCharts/QChart>
#include <QtCharts/QPieSeries>
#include <QtCharts/QPieSlice>
#include <QtCharts/QPieModelMapper>
#include <QtGui/QStandardItemModel>
#include <tst_definitions.h>

QT_USE_NAMESPACE

Q_DECLARE_METATYPE(QPieSlice*)
Q_DECLARE_METATYPE(QList<QPieSlice*>)

class tst_qpieseries : public QObject
{
    Q_OBJECT

public slots:
    void initTestCase();
    void cleanupTestCase();
    void init();
    void cleanup();

private slots:
    void properties();
    void append();
    void appendAnimated();
    void insert();
    void insertAnimated();
    void remove();
    void removeAnimated();
    void take();
    void takeAnimated();
    void calculatedValues();
    void clickedSignal();
    void hoverSignal();
    void sliceSeries();
    void destruction();
    void pressedSignal();
    void releasedSignal();
    void doubleClickedSignal();

private:
    void verifyCalculatedData(const QPieSeries &series, bool *ok);
    QList<QPoint> slicePoints(QRectF rect);

private:
    QChartView *m_view;
    QPieSeries *m_series;
};

void tst_qpieseries::initTestCase()
{
    qRegisterMetaType<QPieSlice*>("QPieSlice*");
    qRegisterMetaType<QList<QPieSlice*> >("QList<QPieSlice*>");
}

void tst_qpieseries::cleanupTestCase()
{
    QTest::qWait(1); // Allow final deleteLaters to run
}

void tst_qpieseries::init()
{
    m_view = new QChartView();
    m_view->resize(200, 200);
    m_series = new QPieSeries(m_view);
    m_view->show();
    QVERIFY(QTest::qWaitForWindowExposed(m_view));

}

void tst_qpieseries::cleanup()
{
    delete m_view;
    m_view = 0;
    m_series = 0;
}

void tst_qpieseries::properties()
{
    QSignalSpy countSpy(m_series, SIGNAL(countChanged()));
    QSignalSpy sumSpy(m_series, SIGNAL(sumChanged()));
    QSignalSpy opacitySpy(m_series, SIGNAL(opacityChanged()));

    QVERIFY(m_series->type() == QAbstractSeries::SeriesTypePie);
    QVERIFY(m_series->count() == 0);
    QVERIFY(m_series->isEmpty());
    QCOMPARE(m_series->sum(), 0.0);
    QCOMPARE(m_series->horizontalPosition(), 0.5);
    QCOMPARE(m_series->verticalPosition(), 0.5);
    QCOMPARE(m_series->pieSize(), 0.7);
    QCOMPARE(m_series->pieStartAngle(), 0.0);
    QCOMPARE(m_series->pieEndAngle(), 360.0);
    QCOMPARE(m_series->opacity(), 1.0);

    m_series->append("s1", 1);
    m_series->append("s2", 1);
    m_series->append("s3", 1);
    m_series->insert(1, new QPieSlice("s4", 1));
    m_series->remove(m_series->slices().first());
    QCOMPARE(m_series->count(), 3);
    QCOMPARE(m_series->sum(), 3.0);
    m_series->clear();
    QCOMPARE(m_series->count(), 0);
    QCOMPARE(m_series->sum(), 0.0);
    QCOMPARE(countSpy.size(), 6);
    QCOMPARE(sumSpy.size(), 6);

    m_series->setPieSize(-1.0);
    QCOMPARE(m_series->pieSize(), 0.0);
    m_series->setPieSize(0.0);
    m_series->setPieSize(0.9);
    m_series->setPieSize(2.0);
    QCOMPARE(m_series->pieSize(), 1.0);

    m_series->setPieSize(0.7);
    QCOMPARE(m_series->pieSize(), 0.7);

    m_series->setHoleSize(-1.0);
    QCOMPARE(m_series->holeSize(), 0.0);
    m_series->setHoleSize(0.5);
    QCOMPARE(m_series->holeSize(), 0.5);

    m_series->setHoleSize(0.8);
    QCOMPARE(m_series->holeSize(), 0.8);
    QCOMPARE(m_series->pieSize(), 0.8);

    m_series->setPieSize(0.4);
    QCOMPARE(m_series->pieSize(), 0.4);
    QCOMPARE(m_series->holeSize(), 0.4);

    m_series->setPieStartAngle(0);
    m_series->setPieStartAngle(-180);
    m_series->setPieStartAngle(180);
    QCOMPARE(m_series->pieStartAngle(), 180.0);

    m_series->setPieEndAngle(360);
    m_series->setPieEndAngle(-180);
    m_series->setPieEndAngle(180);
    QCOMPARE(m_series->pieEndAngle(), 180.0);

    m_series->setHorizontalPosition(0.5);
    m_series->setHorizontalPosition(-1.0);
    QCOMPARE(m_series->horizontalPosition(), 0.0);
    m_series->setHorizontalPosition(1.0);
    m_series->setHorizontalPosition(2.0);
    QCOMPARE(m_series->horizontalPosition(), 1.0);

    m_series->setVerticalPosition(0.5);
    m_series->setVerticalPosition(-1.0);
    QCOMPARE(m_series->verticalPosition(), 0.0);
    m_series->setVerticalPosition(1.0);
    m_series->setVerticalPosition(2.0);
    QCOMPARE(m_series->verticalPosition(), 1.0);

    m_series->setOpacity(0.5);
    QCOMPARE(m_series->opacity(), 0.5);
    QCOMPARE(opacitySpy.size(), 1);
    m_series->setOpacity(0.0);
    QCOMPARE(m_series->opacity(), 0.0);
    QCOMPARE(opacitySpy.size(), 2);
    m_series->setOpacity(1.0);
    QCOMPARE(m_series->opacity(), 1.0);
    QCOMPARE(opacitySpy.size(), 3);
}

void tst_qpieseries::append()
{
    m_view->chart()->addSeries(m_series);
    QSignalSpy addedSpy(m_series, SIGNAL(added(QList<QPieSlice*>)));

    // append pointer
    QPieSlice *slice1 = 0;
    QVERIFY(!m_series->append(slice1));
    slice1 = new QPieSlice("slice 1", 1);
    QVERIFY(m_series->append(slice1));
    QVERIFY(!m_series->append(slice1));
    QCOMPARE(m_series->count(), 1);
    QCOMPARE(addedSpy.size(), 1);
    QList<QPieSlice*> added = qvariant_cast<QList<QPieSlice*> >(addedSpy.at(0).at(0));
    QCOMPARE(added.size(), 1);
    QCOMPARE(added.first(), slice1);

    // try to append same slice to another series
    QPieSeries series2;
    QVERIFY(!series2.append(slice1));

    // append pointer list
    QList<QPieSlice *> list;
    QVERIFY(!m_series->append(list));
    list << (QPieSlice *) 0;
    QVERIFY(!m_series->append(list));
    list.clear();
    list << new QPieSlice("slice 2", 2);
    list << new QPieSlice("slice 3", 3);
    QVERIFY(m_series->append(list));
    QVERIFY(!m_series->append(list));
    QCOMPARE(m_series->count(), 3);
    QCOMPARE(addedSpy.size(), 2);
    added = qvariant_cast<QList<QPieSlice*> >(addedSpy.at(1).at(0));
    QCOMPARE(added.size(), 2);
    QCOMPARE(added, list);

    // append operator
    QPieSlice *slice4 = new QPieSlice("slice 4", 4);
    *m_series << slice4;
    *m_series << slice1; // fails because already added
    QCOMPARE(m_series->count(), 4);
    QCOMPARE(addedSpy.size(), 3);
    added = qvariant_cast<QList<QPieSlice*> >(addedSpy.at(2).at(0));
    QCOMPARE(added.size(), 1);
    QCOMPARE(added.first(), slice4);

    // append with params
    QPieSlice *slice5 = m_series->append("slice 5", 5);
    QVERIFY(slice5 != 0);
    QCOMPARE(slice5->value(), 5.0);
    QCOMPARE(slice5->label(), QString("slice 5"));
    QCOMPARE(m_series->count(), 5);
    QCOMPARE(addedSpy.size(), 4);
    added = qvariant_cast<QList<QPieSlice*> >(addedSpy.at(3).at(0));
    QCOMPARE(added.size(), 1);
    QCOMPARE(added.first(), slice5);

    // check slices
    QVERIFY(!m_series->isEmpty());
    for (int i=0; i<m_series->count(); i++) {
        QCOMPARE(m_series->slices().at(i)->value(), (qreal) i+1);
        QCOMPARE(m_series->slices().at(i)->label(), QString("slice ") + QString::number(i+1));
    }
}

void tst_qpieseries::appendAnimated()
{
    m_view->chart()->setAnimationOptions(QChart::AllAnimations);
    append();
}

void tst_qpieseries::insert()
{
    m_view->chart()->addSeries(m_series);
    QSignalSpy addedSpy(m_series, SIGNAL(added(QList<QPieSlice*>)));

    // insert one slice
    QPieSlice *slice1 = 0;
    QVERIFY(!m_series->insert(0, slice1));
    slice1 = new QPieSlice("slice 1", 1);
    QVERIFY(!m_series->insert(-1, slice1));
    QVERIFY(!m_series->insert(5, slice1));
    QVERIFY(m_series->insert(0, slice1));
    QVERIFY(!m_series->insert(0, slice1));
    QCOMPARE(m_series->count(), 1);
    QCOMPARE(addedSpy.size(), 1);
    QList<QPieSlice*> added = qvariant_cast<QList<QPieSlice*> >(addedSpy.at(0).at(0));
    QCOMPARE(added.size(), 1);
    QCOMPARE(added.first(), slice1);

    // try to insert same slice to another series
    QPieSeries series2;
    QVERIFY(!series2.insert(0, slice1));

    // add some more slices
    QPieSlice *slice2 = m_series->append("slice 2", 2);
    QPieSlice *slice4 = m_series->append("slice 4", 4);
    QCOMPARE(m_series->count(), 3);
    QCOMPARE(addedSpy.size(), 3);
    added = qvariant_cast<QList<QPieSlice*> >(addedSpy.at(1).at(0));
    QCOMPARE(added.size(), 1);
    QCOMPARE(added.first(), slice2);
    added = qvariant_cast<QList<QPieSlice*> >(addedSpy.at(2).at(0));
    QCOMPARE(added.size(), 1);
    QCOMPARE(added.first(), slice4);

    // insert between slices
    QPieSlice *slice3 = new QPieSlice("slice 3", 3);
    m_series->insert(2, slice3);
    QCOMPARE(m_series->count(), 4);
    QCOMPARE(addedSpy.size(), 4);
    added = qvariant_cast<QList<QPieSlice*> >(addedSpy.at(3).at(0));
    QCOMPARE(added.size(), 1);
    QCOMPARE(added.first(), slice3);

    // check slices
    for (int i=0; i<m_series->count(); i++) {
        QCOMPARE(m_series->slices().at(i)->value(), (qreal) i+1);
        QCOMPARE(m_series->slices().at(i)->label(), QString("slice ") + QString::number(i+1));
        QVERIFY(m_series->slices().at(i)->parent() == m_series);
    }
}

void tst_qpieseries::insertAnimated()
{
    m_view->chart()->setAnimationOptions(QChart::AllAnimations);
    insert();
}

void tst_qpieseries::remove()
{
    m_view->chart()->addSeries(m_series);
    QSignalSpy removedSpy(m_series, SIGNAL(removed(QList<QPieSlice*>)));

    // add some slices
    QPieSlice *slice1 = m_series->append("slice 1", 1);
    QPieSlice *slice2 = m_series->append("slice 2", 2);
    QPieSlice *slice3 = m_series->append("slice 3", 3);
    QSignalSpy spy1(slice1, SIGNAL(destroyed()));
    QSignalSpy spy2(slice2, SIGNAL(destroyed()));
    QSignalSpy spy3(slice3, SIGNAL(destroyed()));
    QCOMPARE(m_series->count(), 3);

    // null pointer remove
    QVERIFY(!m_series->remove(0));

    // remove first
    QVERIFY(m_series->remove(slice1));
    QVERIFY(!m_series->remove(slice1));
    QCOMPARE(m_series->count(), 2);
    QCOMPARE(m_series->slices().at(0)->label(), slice2->label());
    QCOMPARE(removedSpy.size(), 1);
    QList<QPieSlice*> removed = qvariant_cast<QList<QPieSlice*> >(removedSpy.at(0).at(0));
    QCOMPARE(removed.size(), 1);
    QCOMPARE(static_cast<const void *>(removed.first()), static_cast<const void *>(slice1));

    // remove all
    m_series->clear();
    QVERIFY(m_series->isEmpty());
    QVERIFY(m_series->slices().isEmpty());
    QCOMPARE(m_series->count(), 0);
    QCOMPARE(removedSpy.size(), 2);
    removed = qvariant_cast<QList<QPieSlice*> >(removedSpy.at(1).at(0));
    QCOMPARE(removed.size(), 2);
    QCOMPARE(static_cast<const void *>(removed.first()), static_cast<const void *>(slice2));
    QCOMPARE(static_cast<const void *>(removed.last()), static_cast<const void *>(slice3));

    // check that slices were actually destroyed
    TRY_COMPARE(spy1.size(), 1);
    TRY_COMPARE(spy2.size(), 1);
    TRY_COMPARE(spy3.size(), 1);
}

void tst_qpieseries::removeAnimated()
{
    m_view->chart()->setAnimationOptions(QChart::AllAnimations);
    remove();
}

void tst_qpieseries::take()
{
    m_view->chart()->addSeries(m_series);
    QSignalSpy removedSpy(m_series, SIGNAL(removed(QList<QPieSlice*>)));

    // add some slices
    QPieSlice *slice1 = m_series->append("slice 1", 1);
    QPieSlice *slice2 = m_series->append("slice 2", 2);
    m_series->append("slice 3", 3);
    QSignalSpy spy1(slice1, SIGNAL(destroyed()));
    QCOMPARE(m_series->count(), 3);

    // null pointer remove
    QVERIFY(!m_series->take(0));

    // take first
    QVERIFY(m_series->take(slice1));
    TRY_COMPARE(spy1.size(), 0);
    QVERIFY(slice1->parent() == m_series); // series is still the parent object
    QVERIFY(!m_series->take(slice1));
    QCOMPARE(m_series->count(), 2);
    QCOMPARE(m_series->slices().at(0)->label(), slice2->label());
    QCOMPARE(removedSpy.size(), 1);
    QList<QPieSlice*> removed = qvariant_cast<QList<QPieSlice*> >(removedSpy.at(0).at(0));
    QCOMPARE(removed.size(), 1);
    QCOMPARE(removed.first(), slice1);
}

void tst_qpieseries::takeAnimated()
{
    m_view->chart()->setAnimationOptions(QChart::AllAnimations);
    take();
}

void tst_qpieseries::calculatedValues()
{
    m_view->chart()->addSeries(m_series);

    QPieSlice *slice1 = new QPieSlice("slice 1", 1);
    QSignalSpy percentageSpy(slice1, SIGNAL(percentageChanged()));
    QSignalSpy startAngleSpy(slice1, SIGNAL(startAngleChanged()));
    QSignalSpy angleSpanSpy(slice1, SIGNAL(angleSpanChanged()));

    // add a slice
    m_series->append(slice1);
    bool ok;
    verifyCalculatedData(*m_series, &ok);
    if (!ok)
        return;
    QCOMPARE(percentageSpy.size(), 1);
    QCOMPARE(startAngleSpy.size(), 0);
    QCOMPARE(angleSpanSpy.size(), 1);

    // add some more slices
    QList<QPieSlice *> list;
    list << new QPieSlice("slice 2", 2);
    list << new QPieSlice("slice 3", 3);
    m_series->append(list);
    verifyCalculatedData(*m_series, &ok);
    if (!ok)
        return;
    QCOMPARE(percentageSpy.size(), 2);
    QCOMPARE(startAngleSpy.size(), 0);
    QCOMPARE(angleSpanSpy.size(), 2);

    // remove a slice
    m_series->remove(list.first()); // remove slice 2
    verifyCalculatedData(*m_series, &ok);
    if (!ok)
        return;
    QCOMPARE(percentageSpy.size(), 3);
    QCOMPARE(startAngleSpy.size(), 0);
    QCOMPARE(angleSpanSpy.size(), 3);

    // insert a slice
    m_series->insert(0, new QPieSlice("Slice 4", 4));
    verifyCalculatedData(*m_series, &ok);
    if (!ok)
        return;
    QCOMPARE(percentageSpy.size(), 4);
    QCOMPARE(startAngleSpy.size(), 1);
    QCOMPARE(angleSpanSpy.size(), 4);

    // modify pie angles
    m_series->setPieStartAngle(-90);
    m_series->setPieEndAngle(90);
    verifyCalculatedData(*m_series, &ok);
    if (!ok)
        return;
    QCOMPARE(percentageSpy.size(), 4);
    QCOMPARE(startAngleSpy.size(), 3);
    QCOMPARE(angleSpanSpy.size(), 6);

    // clear all
    m_series->clear();
    verifyCalculatedData(*m_series, &ok);
    if (!ok)
        return;
    QCOMPARE(percentageSpy.size(), 4);
    QCOMPARE(startAngleSpy.size(), 3);
    QCOMPARE(angleSpanSpy.size(), 6);
}

void tst_qpieseries::verifyCalculatedData(const QPieSeries &series, bool *ok)
{
    *ok = false;

    qreal sum = 0;
    foreach (const QPieSlice *slice, series.slices())
        sum += slice->value();
    QCOMPARE(series.sum(), sum);

    qreal startAngle = series.pieStartAngle();
    qreal pieAngleSpan = series.pieEndAngle() - series.pieStartAngle();
    foreach (const QPieSlice *slice, series.slices()) {
        qreal ratio = slice->value() / sum;
        qreal sliceSpan = pieAngleSpan * ratio;
        QCOMPARE(slice->startAngle(), startAngle);
        QCOMPARE(slice->angleSpan(), sliceSpan);
        QCOMPARE(slice->percentage(), ratio);
        startAngle += sliceSpan;
    }

    if (!series.isEmpty())
        QCOMPARE(series.slices().last()->startAngle() + series.slices().last()->angleSpan(), series.pieEndAngle());

    *ok = true;
}

void tst_qpieseries::clickedSignal()
{
    // NOTE:
    // This test is the same as tst_qpieslice::clickedSignal()
    // Just for different signals.

    SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();

    // add some slices
    QPieSlice *s1 = m_series->append("slice 1", 1);
    QPieSlice *s2 = m_series->append("slice 2", 1);
    QPieSlice *s3 = m_series->append("slice 3", 1);
    QPieSlice *s4 = m_series->append("slice 4", 1);
    QSignalSpy clickSpy(m_series, SIGNAL(clicked(QPieSlice*)));

    // add series to the chart
    m_view->chart()->legend()->setVisible(false);
    m_view->chart()->addSeries(m_series);
    m_view->show();
    QVERIFY(QTest::qWaitForWindowExposed(m_view));

    // test maximum size
    m_series->setPieSize(1.0);
    QRectF pieRect = m_view->chart()->plotArea();
    QList<QPoint> points = slicePoints(pieRect);
    QTest::mouseClick(m_view->viewport(), Qt::LeftButton, {}, points.at(0));
    QTest::mouseClick(m_view->viewport(), Qt::LeftButton, {}, points.at(1));
    QTest::mouseClick(m_view->viewport(), Qt::LeftButton, {}, points.at(2));
    QTest::mouseClick(m_view->viewport(), Qt::LeftButton, {}, points.at(3));
    TRY_COMPARE(clickSpy.size(), 4);
    QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(0).at(0)), s1);
    QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(1).at(0)), s2);
    QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(2).at(0)), s3);
    QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(3).at(0)), s4);
    clickSpy.clear();

    // test half size
    m_series->setPieSize(0.5);
    m_series->setVerticalPosition(0.25);
    m_series->setHorizontalPosition(0.25);
    pieRect = QRectF(m_view->chart()->plotArea().topLeft(), m_view->chart()->plotArea().center());
    points = slicePoints(pieRect);
    QTest::mouseClick(m_view->viewport(), Qt::LeftButton, {}, points.at(0));
    QTest::mouseClick(m_view->viewport(), Qt::LeftButton, {}, points.at(1));
    QTest::mouseClick(m_view->viewport(), Qt::LeftButton, {}, points.at(2));
    QTest::mouseClick(m_view->viewport(), Qt::LeftButton, {}, points.at(3));
    TRY_COMPARE(clickSpy.size(), 4);
    QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(0).at(0)), s1);
    QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(1).at(0)), s2);
    QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(2).at(0)), s3);
    QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(3).at(0)), s4);
}

void tst_qpieseries::hoverSignal()
{
    // NOTE:
    // This test is the same as tst_qpieslice::hoverSignal()
    // Just for different signals.

    SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();
    SKIP_IF_FLAKY_MOUSE_MOVE();

    // add some slices
    m_series->append("slice 1", 1);
    m_series->append("slice 2", 1);
    m_series->append("slice 3", 1);
    m_series->append("slice 4", 1);

    // add series to the chart
    m_view->chart()->legend()->setVisible(false);
    m_view->chart()->addSeries(m_series);
    m_view->show();
    QVERIFY(QTest::qWaitForWindowExposed(m_view));

    // move inside the slices
    m_series->setPieSize(1.0);
    QRectF pieRect = m_view->chart()->plotArea();
    QList<QPoint> points = slicePoints(pieRect);
    QTest::mouseMove(m_view->viewport(), pieRect.topRight().toPoint(), 100);
    QSignalSpy hoverSpy(m_series, SIGNAL(hovered(QPieSlice*,bool)));
    QTest::mouseMove(m_view->viewport(), points.at(0), 100);
    QTest::mouseMove(m_view->viewport(), points.at(1), 100);
    QTest::mouseMove(m_view->viewport(), points.at(2), 100);
    QTest::mouseMove(m_view->viewport(), points.at(3), 100);
    QTest::mouseMove(m_view->viewport(), pieRect.topLeft().toPoint(), 100);
    // Final hoverevent can take few milliseconds to appear in some environments, so wait a bit
    QTest::qWait(100);

    // check
    QCOMPARE(hoverSpy.size(), 8);
    int i = 0;
    foreach (QPieSlice *s, m_series->slices()) {
        QCOMPARE(qvariant_cast<QPieSlice*>(hoverSpy.at(i).at(0)), s);
        QCOMPARE(qvariant_cast<bool>(hoverSpy.at(i).at(1)), true);
        i++;
        QCOMPARE(qvariant_cast<QPieSlice*>(hoverSpy.at(i).at(0)), s);
        QCOMPARE(qvariant_cast<bool>(hoverSpy.at(i).at(1)), false);
        i++;
    }
}

void tst_qpieseries::sliceSeries()
{
    QPieSlice *slice = new QPieSlice();
    QVERIFY(!slice->series());
    delete slice;

    slice = new QPieSlice(m_series);
    QVERIFY(!slice->series());

    m_series->append(slice);
    QCOMPARE(slice->series(), m_series);

    slice = new QPieSlice();
    m_series->insert(0, slice);
    QCOMPARE(slice->series(), m_series);

    m_series->take(slice);
    QCOMPARE(slice->series(), (QPieSeries*) 0);
}

void tst_qpieseries::destruction()
{
    // add some slices
    QPieSlice *slice1 = m_series->append("slice 1", 1);
    QPieSlice *slice2 = m_series->append("slice 2", 2);
    QPieSlice *slice3 = m_series->append("slice 3", 3);
    QSignalSpy spy1(slice1, SIGNAL(destroyed()));
    QSignalSpy spy2(slice2, SIGNAL(destroyed()));
    QSignalSpy spy3(slice3, SIGNAL(destroyed()));

    // destroy series
    delete m_series;
    m_series = 0;

    // check that series has destroyed its slices
    QCOMPARE(spy1.size(), 1);
    QCOMPARE(spy2.size(), 1);
    QCOMPARE(spy3.size(), 1);
}

QList<QPoint> tst_qpieseries::slicePoints(QRectF rect)
{
    qreal x1 = rect.topLeft().x() + (rect.width() / 4);
    qreal x2 = rect.topLeft().x() + (rect.width() / 4) * 3;
    qreal y1 = rect.topLeft().y() + (rect.height() / 4);
    qreal y2 = rect.topLeft().y() + (rect.height() / 4) * 3;
    QList<QPoint> points;
    points << QPoint(x2, y1);
    points << QPoint(x2, y2);
    points << QPoint(x1, y2);
    points << QPoint(x1, y1);
    return points;
}

void tst_qpieseries::pressedSignal()
{
    // NOTE:
    // This test is the same as tst_qpieslice::pressedSignal()
    // Just for different signals.

    SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();

    // add some slices
    QPieSlice *s1 = m_series->append("slice 1", 1);
    QPieSlice *s2 = m_series->append("slice 2", 1);
    QPieSlice *s3 = m_series->append("slice 3", 1);
    QPieSlice *s4 = m_series->append("slice 4", 1);
    QSignalSpy clickSpy(m_series, SIGNAL(pressed(QPieSlice*)));

    // add series to the chart
    m_view->chart()->legend()->setVisible(false);
    m_view->chart()->addSeries(m_series);
    m_view->show();
    QVERIFY(QTest::qWaitForWindowExposed(m_view));

    // test maximum size
    m_series->setPieSize(1.0);
    QRectF pieRect = m_view->chart()->plotArea();
    QList<QPoint> points = slicePoints(pieRect);
    QTest::mouseClick(m_view->viewport(), Qt::LeftButton, {}, points.at(0));
    QTest::mouseClick(m_view->viewport(), Qt::LeftButton, {}, points.at(1));
    QTest::mouseClick(m_view->viewport(), Qt::LeftButton, {}, points.at(2));
    QTest::mouseClick(m_view->viewport(), Qt::LeftButton, {}, points.at(3));
    TRY_COMPARE(clickSpy.size(), 4);
    QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(0).at(0)), s1);
    QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(1).at(0)), s2);
    QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(2).at(0)), s3);
    QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(3).at(0)), s4);
    clickSpy.clear();

    // test half size
    m_series->setPieSize(0.5);
    m_series->setVerticalPosition(0.25);
    m_series->setHorizontalPosition(0.25);
    pieRect = QRectF(m_view->chart()->plotArea().topLeft(), m_view->chart()->plotArea().center());
    points = slicePoints(pieRect);
    QTest::mouseClick(m_view->viewport(), Qt::LeftButton, {}, points.at(0));
    QTest::mouseClick(m_view->viewport(), Qt::LeftButton, {}, points.at(1));
    QTest::mouseClick(m_view->viewport(), Qt::LeftButton, {}, points.at(2));
    QTest::mouseClick(m_view->viewport(), Qt::LeftButton, {}, points.at(3));
    TRY_COMPARE(clickSpy.size(), 4);
    QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(0).at(0)), s1);
    QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(1).at(0)), s2);
    QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(2).at(0)), s3);
    QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(3).at(0)), s4);
}

void tst_qpieseries::releasedSignal()
{
    // NOTE:
    // This test is the same as tst_qpieslice::pressedSignal()
    // Just for different signals.

    SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();

    // add some slices
    QPieSlice *s1 = m_series->append("slice 1", 1);
    QPieSlice *s2 = m_series->append("slice 2", 1);
    QPieSlice *s3 = m_series->append("slice 3", 1);
    QPieSlice *s4 = m_series->append("slice 4", 1);
    QSignalSpy clickSpy(m_series, SIGNAL(released(QPieSlice*)));

    // add series to the chart
    m_view->chart()->legend()->setVisible(false);
    m_view->chart()->addSeries(m_series);
    m_view->show();
    QVERIFY(QTest::qWaitForWindowExposed(m_view));

    // test maximum size
    m_series->setPieSize(1.0);
    QRectF pieRect = m_view->chart()->plotArea();
    QList<QPoint> points = slicePoints(pieRect);
    QTest::mouseClick(m_view->viewport(), Qt::LeftButton, {}, points.at(0));
    QTest::mouseClick(m_view->viewport(), Qt::LeftButton, {}, points.at(1));
    QTest::mouseClick(m_view->viewport(), Qt::LeftButton, {}, points.at(2));
    QTest::mouseClick(m_view->viewport(), Qt::LeftButton, {}, points.at(3));
    TRY_COMPARE(clickSpy.size(), 4);
    QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(0).at(0)), s1);
    QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(1).at(0)), s2);
    QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(2).at(0)), s3);
    QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(3).at(0)), s4);
    clickSpy.clear();

    // test half size
    m_series->setPieSize(0.5);
    m_series->setVerticalPosition(0.25);
    m_series->setHorizontalPosition(0.25);
    pieRect = QRectF(m_view->chart()->plotArea().topLeft(), m_view->chart()->plotArea().center());
    points = slicePoints(pieRect);
    QTest::mouseClick(m_view->viewport(), Qt::LeftButton, {}, points.at(0));
    QTest::mouseClick(m_view->viewport(), Qt::LeftButton, {}, points.at(1));
    QTest::mouseClick(m_view->viewport(), Qt::LeftButton, {}, points.at(2));
    QTest::mouseClick(m_view->viewport(), Qt::LeftButton, {}, points.at(3));
    TRY_COMPARE(clickSpy.size(), 4);
    QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(0).at(0)), s1);
    QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(1).at(0)), s2);
    QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(2).at(0)), s3);
    QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(3).at(0)), s4);
}

void tst_qpieseries::doubleClickedSignal()
{
    // NOTE:
    // This test is the same as tst_qpieslice::pressedSignal()
    // Just for different signals.

    SKIP_IF_CANNOT_TEST_MOUSE_EVENTS();

    // add some slices
    QPieSlice *s1 = m_series->append("slice 1", 1);
    QSignalSpy clickSpy(m_series, SIGNAL(doubleClicked(QPieSlice*)));

    // add series to the chart
    m_view->chart()->legend()->setVisible(false);
    m_view->chart()->addSeries(m_series);
    m_view->show();
    QVERIFY(QTest::qWaitForWindowExposed(m_view));

    // test maximum size
    m_series->setPieSize(1.0);
    QRectF pieRect = m_view->chart()->plotArea();
    QList<QPoint> points = slicePoints(pieRect);
    QTest::mouseDClick(m_view->viewport(), Qt::LeftButton, {}, points.at(0));
    TRY_COMPARE(clickSpy.size(), 1);
    QCOMPARE(qvariant_cast<QPieSlice*>(clickSpy.at(0).at(0)), s1);
}

QTEST_MAIN(tst_qpieseries)

#include "tst_qpieseries.moc"

