/*
 * Copyright (c) 2017 Elvis Angelaccio <elvis.angelaccio@kde.org>
 * Copyright (c) 2018 Michael Heidelbach <ottwolt@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 */

#include "ktooltipwidgettest.h"

#include <KToolTipWidget>

#include <QLayout>
#include <QStyle>
#include <QLabel>
#include <QLineEdit>
#include <QSignalSpy>
#include <QScreen>
#include <QTest>

void KToolTipWidgetTest::initTestCase()
{
    m_screenGeometry = QGuiApplication::primaryScreen()->geometry();
}

void KToolTipWidgetTest::showTooltipShouldShowContent()
{
    KToolTipWidget tooltip;
    QLabel label;

    tooltip.showAt(QPoint(10, 10), &label, nullptr);
    QVERIFY(tooltip.isVisible());
    QVERIFY(label.isVisible());
}

void KToolTipWidgetTest::hideLaterShouldHideAfterDelay()
{
    KToolTipWidget tooltip;
    QLabel label;

    tooltip.showAt(QPoint(10, 10), &label, nullptr);
    QVERIFY(tooltip.isVisible());
    QVERIFY(label.isVisible());

    tooltip.hideLater();
    QVERIFY(tooltip.isVisible());
    QVERIFY(label.isVisible());

    QSignalSpy spy(&tooltip, &KToolTipWidget::hidden);
    connect(&tooltip, &KToolTipWidget::hidden, this, [&]() {
        QVERIFY(tooltip.isHidden());
        QVERIFY(!label.isVisible());
    });

    QEventLoop eventLoop;
    connect(&tooltip, &KToolTipWidget::hidden, &eventLoop, &QEventLoop::quit);
    QCOMPARE(eventLoop.exec(), 0);
    QCOMPARE(spy.count(), 1);
}

void KToolTipWidgetTest::setZeroDelayShouldHideImmediately()
{
    KToolTipWidget tooltip;
    QLabel label;

    tooltip.setHideDelay(0);
    tooltip.showAt(QPoint(10, 10), &label, nullptr);
    QVERIFY(tooltip.isVisible());
    QVERIFY(label.isVisible());

    tooltip.hideLater();
    QVERIFY(tooltip.isHidden());
    QVERIFY(!label.isVisible());
}

void KToolTipWidgetTest::shouldHideImmediatelyIfContentDestroyed()
{
    KToolTipWidget tooltip;
    auto lineEdit = new QLineEdit();

    tooltip.showAt(QPoint(10, 10), lineEdit, nullptr);
    QVERIFY(tooltip.isVisible());

    delete lineEdit;
    QVERIFY(tooltip.isHidden());
}

void KToolTipWidgetTest::shouldNotTakeOwnershipOfContent()
{
    auto parent = new QWidget();
    auto label = new QLabel(parent);
    auto tooltip = new KToolTipWidget();

    tooltip->showAt(QPoint(10, 10), label, nullptr);
    QCOMPARE(label->parent(), tooltip);
    QVERIFY(label->isVisible());

    QSignalSpy spy(label, &QWidget::destroyed);
    delete tooltip;
    QVERIFY(!label->isVisible());
    QCOMPARE(label->parent(), parent);
    QCOMPARE(spy.count(), 0);

    delete parent;
    QCOMPARE(spy.count(), 1);
}

void KToolTipWidgetTest::shouldNotObscureTarget_data()
{
    qDebug() << "Style used" << QApplication::style()->objectName();

    QTest::addColumn<QPoint>("position");
    QTest::addColumn<QString>("content");

    const QMap<QString,QPoint> positions{
        {QStringLiteral("topleft"), QPoint(m_offset, m_offset)},
        {QStringLiteral("topright"), QPoint(-m_offset, m_offset)},
        {QStringLiteral("bottomright"), QPoint(-m_offset, -m_offset)},
        {QStringLiteral("bottomleft"), QPoint(m_offset, -m_offset)},
        {QStringLiteral("centered"),
            QPoint(m_screenGeometry.width() / 2, m_screenGeometry.height() / 2)}
    };

    QMapIterator<QString, QPoint> i(positions);
    while (i.hasNext()) {
        i.next();
        QTest::newRow(qPrintable(QStringLiteral("small/%1").arg(i.key())) )
            << i.value()
            << QStringLiteral("dummy text");

        QTest::newRow(qPrintable(QStringLiteral("multiline/%1").arg(i.key())))
            << i.value()
            << QStringLiteral("dummy text\nLine 1\nLine 2\nLine 3");

        QTest::newRow(qPrintable(QStringLiteral("one long line/%1").arg(i.key())))
            << i.value()
            << QStringLiteral(
                "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam nec felis sed elit auctor lobortis non a urna. Quisque non posuere mauris. Suspendisse potenti. In diam leo, lobortis at placerat nec, sagittis at tortor. Pellentesque scelerisque enim vel elementum scelerisque. Integer eget lectus vitae lorem pulvinar hendrerit. Suspendisse auctor sapien vel semper porta. Vestibulum fringilla aliquet tincidunt. Maecenas mollis mauris et erat viverra mollis. Proin suscipit felis nisi, a dapibus est hendrerit euismod. Suspendisse quis faucibus quam. Fusce eu cursus magna, et egestas purus. Duis enim sapien, feugiat id facilisis non, rhoncus ut lectus. Aliquam at nisi vel ligula interdum ultricies. Donec condimentum ante quam, eu congue lectus pulvinar in. Cras interdum, neque quis fermentum consequat, lectus tellus eleifend turpis."
            );

        if (m_screenGeometry.width() >= 1600 && m_screenGeometry.height() >= 900) {
            QTest::newRow(qPrintable(QStringLiteral("super large/%1").arg(i.key())))
                << i.value()
                << QStringLiteral(
                    "dummy 0 text\nLine 1\nLine 2\nLine 3"
                    "dummy 1 text\nLine 1\nLine 2\nLine 3"
                    "dummy 2 text\nLine 1\nLine 2\nLine 3"
                    "dummy 3 text\nLine 1\nLine 2\nLine 3"
                    "dummy 4 text\nLine 1\nLine 2\nLine 3"

                    "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam nec felis sed elit auctor lobortis non a urna. Quisque non posuere mauris. Suspendisse potenti. In diam leo, lobortis at placerat nec, sagittis at tortor. Pellentesque scelerisque enim vel elementum scelerisque. Integer eget lectus vitae lorem pulvinar hendrerit. Suspendisse auctor sapien vel semper porta. Vestibulum fringilla aliquet tincidunt. Maecenas mollis mauris et erat viverra mollis. Proin suscipit felis nisi, a dapibus est hendrerit euismod. Suspendisse quis faucibus quam. Fusce eu cursus magna, et egestas purus. Duis enim sapien, feugiat id facilisis non, rhoncus ut lectus. Aliquam at nisi vel ligula interdum ultricies. Donec condimentum ante quam, eu congue lectus pulvinar in. Cras interdum, neque quis fermentum consequat, lectus tellus eleifend turpis."
                );
        }
    }
}

void KToolTipWidgetTest::shouldNotObscureTarget()
{
    QFETCH(QPoint, position);
    QFETCH(QString, content);

    QWidget* containerWidget = new QWidget();
    const int margin = containerWidget->style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth);
    QLabel* targetWidget = new QLabel(QStringLiteral("dummy file"));
    QLayout* layout = new QHBoxLayout(containerWidget);
    layout->addWidget(targetWidget);

    containerWidget->adjustSize();
    containerWidget->move(
        position.x() >= 0
            ? position.x()
            : m_screenGeometry.right() + position.x() - containerWidget->width(),
        position.y() >= 0
            ? position.y()
            : m_screenGeometry.bottom() + position.y() - containerWidget->height()
    );
    containerWidget->show();
    QVERIFY(QTest::qWaitForWindowActive(containerWidget));
    QVERIFY(targetWidget->isVisible());

    QRect targetRect = QRect(targetWidget->frameGeometry());
    targetRect.moveTo(targetWidget->mapToGlobal(QPoint(0, 0)));

    QLabel* contentWidget = new QLabel(content);

    QVERIFY2(containerWidget->windowHandle(), "Container's window handle is invalid");
    KToolTipWidget tooltipWidget;
    tooltipWidget.showBelow(targetRect, contentWidget, containerWidget->windowHandle());
    QVERIFY(QTest::qWaitForWindowActive(&tooltipWidget));
    const QRect tooltipRect = tooltipWidget.frameGeometry();

    qDebug() << QStringLiteral("tooltip: %1x%2 x=%3, y=%4")
        .arg(tooltipRect.width())
        .arg(tooltipRect.height())
        .arg(tooltipRect.left())
        .arg(tooltipRect.top());
    qDebug() << QStringLiteral("target:  %1x%2 x=%3, y=%4")
        .arg(targetRect.width())
        .arg(targetRect.height())
        .arg(targetRect.left())
        .arg(targetRect.top());

    QVERIFY2(!tooltipRect.intersects(targetRect), "Target obscured");
    QCOMPARE(tooltipRect.intersected(m_screenGeometry), tooltipRect);

    // Check margins
    if (tooltipRect.bottom() <  targetRect.top()) {
        QCOMPARE(margin, targetRect.top() - tooltipRect.bottom());
    } else if (tooltipRect.top() > targetRect.bottom()) {
        QCOMPARE(margin, tooltipRect.top() - targetRect.bottom());
    } else if (tooltipRect.right() < targetRect.left()) {
        QCOMPARE(margin, targetRect.left() - tooltipRect.right());
    } else if (tooltipRect.left() > targetRect.right() ) {
        QCOMPARE(margin, tooltipRect.left() - targetRect.right());
    }

    tooltipWidget.hide();
    QVERIFY(tooltipWidget.isHidden());

    delete contentWidget;
    delete containerWidget;
}


QTEST_MAIN(KToolTipWidgetTest)


