/*
 * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
 *
 * 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 program 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 program; 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 "config.h"
#include "qwebkittest_p.h"

#include "PageViewportControllerClientQt.h"
#include "qquickwebview_p_p.h"
#include <QMutableListIterator>
#include <QTouchEvent>
#include <QWheelEvent>
#include <qpa/qwindowsysteminterface.h>

using namespace WebKit;

QWebKitTest::QWebKitTest(QQuickWebViewPrivate* webViewPrivate, QObject* parent)
    : QObject(parent)
    , m_webViewPrivate(webViewPrivate)
{
}

QWebKitTest::~QWebKitTest()
{
}

static QTouchEvent::TouchPoint touchPoint(qreal x, qreal y)
{
    QPointF localPos(x, y);

    QTouchEvent::TouchPoint point;
    point.setId(1);
    point.setLastPos(localPos);
    QRectF touchRect(0, 0, 40, 40);
    touchRect.moveCenter(localPos);
    point.setRect(touchRect);
    point.setPressure(1);

    return point;
}

bool QWebKitTest::sendTouchEvent(QQuickWebView* window, QEvent::Type type, const QList<QTouchEvent::TouchPoint>& points, ulong timestamp)
{
    ASSERT(window);

    static QTouchDevice* device = 0;
    if (!device) {
        device = new QTouchDevice;
        device->setType(QTouchDevice::TouchScreen);
        QWindowSystemInterface::registerTouchDevice(device);
    }

    Qt::TouchPointStates touchPointStates = 0;
    foreach (const QTouchEvent::TouchPoint& touchPoint, points)
        touchPointStates |= touchPoint.state();

    QTouchEvent event(type, device, Qt::NoModifier, touchPointStates, points);
    event.setTimestamp(timestamp);
    event.setAccepted(false);

    window->touchEvent(&event);

    return event.isAccepted();
}

bool QWebKitTest::touchTap(QObject* item, qreal x, qreal y, int delay)
{
    QQuickWebView* window = qobject_cast<QQuickWebView*>(item);

    if (!window) {
        qWarning("Touch event \"TouchBegin\" not accepted by receiving item");
        return false;
    }

    // FIXME: implement delay using QTest::qWait() or similar.
    Q_UNUSED(delay);

    QList<QTouchEvent::TouchPoint> points;
    points.append(touchPoint(x, y));

    points[0].setState(Qt::TouchPointPressed);
    sendTouchEvent(window, QEvent::TouchBegin, points, QDateTime::currentMSecsSinceEpoch());

    points[0].setState(Qt::TouchPointReleased);
    sendTouchEvent(window, QEvent::TouchEnd, points, QDateTime::currentMSecsSinceEpoch());

    return true;
}

bool QWebKitTest::touchDoubleTap(QObject* item, qreal x, qreal y, int delay)
{
    if (!touchTap(item, x, y, delay))
        return false;

    if (!touchTap(item, x, y, delay))
        return false;

    return true;
}

bool QWebKitTest::wheelEvent(QObject* item, qreal x, qreal y, int delta, Qt::Orientation orient)
{
    QQuickWebView* window = qobject_cast<QQuickWebView*>(item);

    if (!window) {
        qWarning("Wheel event not accepted by receiving item");
        return false;
    }

    QWheelEvent event(QPointF(x, y), delta, Qt::NoButton, Qt::NoModifier, orient);
    event.setTimestamp(QDateTime::currentMSecsSinceEpoch());
    event.setAccepted(false);

    window->wheelEvent(&event);

    return event.isAccepted();
}

QSize QWebKitTest::contentsSize() const
{
    return QSize(m_webViewPrivate->pageView->contentsSize().toSize());
}

static inline QJsonObject toJsonObject(const QSizeF& sizeF)
{
    QJsonObject result;
    result.insert(QStringLiteral("width"), sizeF.width());
    result.insert(QStringLiteral("height"), sizeF.height());
    return result;
}

QJsonObject QWebKitTest::viewport() const
{
    QJsonObject viewportData;
    if (const PageViewportController* const viewportHandler = m_webViewPrivate->viewportController()) {
        viewportData.insert(QStringLiteral("layoutSize"), toJsonObject(viewportHandler->contentsLayoutSize()));
        viewportData.insert(QStringLiteral("isScalable"), viewportHandler->allowsUserScaling());
        viewportData.insert(QStringLiteral("minimumScale"), viewportHandler->minimumScale());
        viewportData.insert(QStringLiteral("maximumScale"), viewportHandler->maximumScale());
    } else {
        viewportData.insert(QStringLiteral("initialScale"), 1.0);
        viewportData.insert(QStringLiteral("layoutSize"), toJsonObject(QSizeF()));
        viewportData.insert(QStringLiteral("isScalable"), false);
        viewportData.insert(QStringLiteral("minimumScale"), 1.0);
        viewportData.insert(QStringLiteral("maximumScale"), 1.0);
    }
    return viewportData;
}

QVariant QWebKitTest::devicePixelRatio() const
{
    if (const PageViewportController* const viewport = m_webViewPrivate->viewportController())
        return viewport->deviceScaleFactor();
    return 1.0;
}

QVariant QWebKitTest::contentsScale() const
{
    if (const PageViewportController* const viewport = m_webViewPrivate->viewportController())
        return viewport->currentScale();
    return 1.0;
}

#include "moc_qwebkittest_p.cpp"
