/***************************************************************************
 *   Copyright (C) 2013 by Peter Grasch <me@bedahr.org>                    *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 ***************************************************************************/

#include <QtTest>

#include "../core/document.h"
#include "../core/page.h"
#include "../core/annotations.h"
#include "../settings_core.h"

Q_DECLARE_METATYPE(Okular::Annotation*)
Q_DECLARE_METATYPE(Okular::LineAnnotation*)

class AnnotationTest : public QObject
{
    Q_OBJECT

private slots:
    void initTestCase();
    void testDistance();
    void testDistance_data();
//     void testLine();
//     void testPoly();
//     void testInk();
//     void testHighlight();
//     void testGeom();
    void testTypewriter();
    void cleanupTestCase();

private:
    Okular::Document *m_document;
};

void AnnotationTest::initTestCase()
{
    Okular::SettingsCore::instance( QStringLiteral("annotationtest") );
    m_document = new Okular::Document( nullptr );
    const QString testFile = QStringLiteral(KDESRCDIR "data/file1.pdf");
    QMimeDatabase db;
    const QMimeType mime = db.mimeTypeForFile( testFile );
    QCOMPARE( m_document->openDocument(testFile, QUrl(), mime), Okular::Document::OpenSuccess );
}

void AnnotationTest::cleanupTestCase()
{
    if ( m_document->isOpened() ) {
        const QLinkedList<Okular::Annotation *> annotations = m_document->page( 0 )->annotations();
        for ( Okular::Annotation* annotation : annotations ) {
            m_document->removePageAnnotation( 0, annotation );
        }
    }
}



void AnnotationTest::testDistance()
{
    QFETCH(Okular::Annotation*, annotation);
    QFETCH(double, x);
    QFETCH(double, y);
    QFETCH(int, distance);
    Okular::AnnotationObjectRect* rect = new Okular::AnnotationObjectRect( annotation );
    QCOMPARE( qRound( rect->distanceSqr( x, y, m_document->page(0)->width(), m_document->page(0)->height() ) ), distance );
    delete rect;
}

void AnnotationTest::testDistance_data()
{
    QTest::addColumn<Okular::Annotation*>("annotation");
    QTest::addColumn<double>("x");
    QTest::addColumn<double>("y");
    QTest::addColumn<int>("distance");

    double documentX = m_document->page(0)->width();
    double documentY = m_document->page(0)->height();

    // lines
    Okular::LineAnnotation *line = new Okular::LineAnnotation;
    line->setLinePoints( QLinkedList< Okular::NormalizedPoint >()
        << Okular::NormalizedPoint( 0.1, 0.1 )
        << Okular::NormalizedPoint( 0.9, 0.1 )
    );
    m_document->addPageAnnotation( 0, line );
    QTest::newRow("Line: Base point 1") << (Okular::Annotation*) line << 0.1 << 0.1 << 0;
    QTest::newRow("Line: Base point 2") << (Okular::Annotation*) line << 0.5 << 0.1 << 0;
    QTest::newRow("Line: Off by a lot") << (Okular::Annotation*) line << 0.5 << 0.5 << qRound( pow( 0.4 * documentY, 2 ) );
    QTest::newRow("Line: Off by a little") << (Okular::Annotation*) line << 0.1 << 0.1 + (5.0 /* px */ / documentY) << 25;


    // squares (non-filled squares also act as tests for the ink annotation as they share the path-distance code)
    for ( int i = 0; i < 2; ++i )
    {
        Okular::GeomAnnotation *square = new Okular::GeomAnnotation;
        square->setGeometricalType( Okular::GeomAnnotation::InscribedSquare );
        square->setBoundingRectangle( Okular::NormalizedRect( 0.1, 0.1, 0.9, 0.9 ) );
        if ( i != 0 )
            square->setGeometricalInnerColor( QColor(0, 0, 0) );
        m_document->addPageAnnotation( 0, square );
        QTest::newRow("Square: Base point 1") << (Okular::Annotation*) square << 0.1 << 0.1 << 0;
        QTest::newRow("Square: On edge 1") << (Okular::Annotation*) square << 0.1 << 0.2 << 0;
        QTest::newRow("Square: On edge 2") << (Okular::Annotation*) square << 0.2 << 0.1 << 0;
        QTest::newRow("Square: Inside") << (Okular::Annotation*) square << 0.2 << 0.2 <<
            ((i == 0) ? qRound( pow( 0.1 * documentX, 2 ) - 1 /* stroke width */) : 0 );
        QTest::newRow("Square: Outside") << (Okular::Annotation*) square << 0.0 << 0.0 <<
            qRound( pow( 0.1 * documentX, 2 ) + pow( 0.1 * documentY, 2) ) ;
    }

    // ellipsis
    for ( int i = 0; i < 2; ++i )
    {
        Okular::GeomAnnotation *ellipse = new Okular::GeomAnnotation;
        ellipse->setGeometricalType( Okular::GeomAnnotation::InscribedCircle );
        ellipse->setBoundingRectangle( Okular::NormalizedRect( 0.1, 0.1, 0.9, 0.5 ) );
        if ( i != 0 )
            ellipse->setGeometricalInnerColor( QColor(0, 0, 0) );
        m_document->addPageAnnotation( 0, ellipse );
        QTest::newRow("Ellipse: Base point 1") << (Okular::Annotation*) ellipse << 0.1 << 0.3 << 0;
        QTest::newRow("Ellipse: Inside") << (Okular::Annotation*) ellipse << 0.2 << 0.3 <<
            qRound( (i == 0) ? pow( documentX * 0.1, 2 ) - 1 /* pen */ : 0 );
        QTest::newRow("Ellipse: Outside") << (Okular::Annotation*) ellipse << 0.0 << 0.3 << qRound( pow( documentX * 0.1, 2 ) );
    }


    // highlight
    Okular::HighlightAnnotation *highlight = new Okular::HighlightAnnotation;
    Okular::HighlightAnnotation::Quad q;
    q.setPoint( Okular::NormalizedPoint( 0.1, 0.1 ), 0 );
    q.setPoint( Okular::NormalizedPoint( 0.2, 0.1 ), 1 );
    q.setPoint( Okular::NormalizedPoint( 0.8, 0.9 ), 2 );
    q.setPoint( Okular::NormalizedPoint( 0.9, 0.9 ), 3 );
    highlight->highlightQuads() << q;
    m_document->addPageAnnotation( 0, highlight );
    QTest::newRow("Highlight: Point 1") << (Okular::Annotation*) highlight << 0.1 << 0.1 << 0;
    QTest::newRow("Highlight: Point 2") << (Okular::Annotation*) highlight << 0.2 << 0.1 << 0;
    QTest::newRow("Highlight: Point 3") << (Okular::Annotation*) highlight << 0.8 << 0.9 << 0;
    QTest::newRow("Highlight: Point 4") << (Okular::Annotation*) highlight << 0.9 << 0.9 << 0;
    QTest::newRow("Highlight: Inside") << (Okular::Annotation*) highlight << 0.5 << 0.5 << 0;
    QTest::newRow("Highlight: Outside") << (Okular::Annotation*) highlight << 1.0 << 0.9 << qRound( pow( documentX * 0.1, 2 ) );
}

void AnnotationTest::testTypewriter()
{
  Okular::Annotation * annot = nullptr;
  Okular::TextAnnotation * ta = new Okular::TextAnnotation();
  annot = ta;
  ta->setFlags( ta->flags() | Okular::Annotation::FixedRotation );
  ta->setTextType( Okular::TextAnnotation::InPlace );
  ta->setInplaceIntent( Okular::TextAnnotation::TypeWriter );
  ta->style().setWidth( 0.0 );
  ta->style().setColor( QColor(255,255,255,0) );

  annot->setBoundingRectangle( Okular::NormalizedRect( 0.8, 0.1, 0.85, 0.15 ) );
  annot->setContents( QStringLiteral("annot contents") );

  m_document->addPageAnnotation( 0, annot );

  QDomNode annotNode = annot->getAnnotationPropertiesDomNode();
  QDomNodeList annotNodeList = annotNode.toElement().elementsByTagName(QStringLiteral("base"));
  QDomElement annotEl = annotNodeList.item(0).toElement();
  QCOMPARE( annotEl.attribute( QStringLiteral("color") ), QStringLiteral("#00ffffff") );
  QCOMPARE( annotEl.attribute( QStringLiteral("flags") ), QStringLiteral("4") );
  QCOMPARE( annotEl.attribute( QStringLiteral("contents") ), QStringLiteral("annot contents") );
}

QTEST_MAIN( AnnotationTest )
#include "annotationstest.moc"
