/******************************************************************************
  This source file is part of the Avogadro project.
  This source code is released under the 3-Clause BSD License, (see "LICENSE").
******************************************************************************/

#include <gtest/gtest.h>

#include <avogadro/qtgui/generichighlighter.h>

#include <QtGui/QBrush>
#include <QtGui/QTextCharFormat>
#include <QtGui/QTextCursor>
#include <QtGui/QTextDocument>
#include <QtGui/QTextDocumentFragment>
#include <QtGui/QTextLayout>

using Avogadro::QtGui::GenericHighlighter;

namespace {

// Extended GenericHighlighter that can export to html. Taken from
// http://stackoverflow.com/questions/15280452
// This is used to verify that the rules properly highlight the correct portions
// of text.
// (You'd think QTextDocument::toHtml() would do this. It doesn't. :-/ )
class GenericHighlighterHtml : public GenericHighlighter
{
public:
  void asHtml(QString& html)
  {
    // Create a new document from all the selected text document.
    QTextCursor cursor(document());
    cursor.select(QTextCursor::Document);
    QTextDocument* tempDocument(new QTextDocument);
    Q_ASSERT(tempDocument);
    QTextCursor tempCursor(tempDocument);

    tempCursor.insertFragment(cursor.selection());
    tempCursor.select(QTextCursor::Document);
    // Set the default foreground for the inserted characters.
    QTextCharFormat textfmt = tempCursor.charFormat();
    textfmt.setForeground(Qt::gray);
    tempCursor.setCharFormat(textfmt);

    // Apply the additional formats set by the syntax highlighter
    QTextBlock start = document()->findBlock(cursor.selectionStart());
    QTextBlock end = document()->findBlock(cursor.selectionEnd());
    end = end.next();
    const int selectionStart = cursor.selectionStart();
    const int endOfDocument = tempDocument->characterCount() - 1;
    for (QTextBlock current = start; current.isValid() && current != end;
         current = current.next()) {
      const QTextLayout* layout(current.layout());

      foreach (const QTextLayout::FormatRange& range, layout->formats()) {
        const int startIdx = current.position() + range.start - selectionStart;
        const int endIdx = startIdx + range.length;
        if (endIdx <= 0 || startIdx >= endOfDocument)
          continue;
        tempCursor.setPosition(qMax(startIdx, 0));
        tempCursor.setPosition(qMin(endIdx, endOfDocument),
                               QTextCursor::KeepAnchor);
        tempCursor.setCharFormat(range.format);
      }
    }

    // Reset the user states since they are not interesting
    for (QTextBlock block = tempDocument->begin(); block.isValid();
         block = block.next()) {
      block.setUserState(-1);
    }

    // Make sure the text appears pre-formatted, and set the background we want.
    tempCursor.select(QTextCursor::Document);
    QTextBlockFormat blockFormat = tempCursor.blockFormat();
    blockFormat.setNonBreakableLines(true);
    // blockFormat.setBackground(Qt::black);
    tempCursor.setBlockFormat(blockFormat);

    // Finally retrieve the syntax highlighted and formatted html.
    html = tempCursor.selection().toHtml();
    delete tempDocument;
  }
};

} // namespace

// This currently seg faults...
TEST(DISABLED_GenericHighlighterTest, exercise)
{
  QTextDocument doc("A regexp will turn this blue.\n"
                    "Only this and that will be yellow.\n"
                    "A wildcard expression will turn this red.\n"
                    "This string will be green.\n");

  GenericHighlighterHtml highlighter;
  QTextCharFormat format;

  GenericHighlighter::Rule& regexpRule = highlighter.addRule();
  regexpRule.addPattern(QRegularExpression("^.*regexp.*$"));
  format.setForeground(Qt::blue);
  regexpRule.setFormat(format);

  GenericHighlighter::Rule& regexpCapRule = highlighter.addRule();
  regexpCapRule.addPattern(QRegularExpression("^.*(this)[^\n]*(that).*$"));
  format.setForeground(Qt::yellow);
  regexpCapRule.setFormat(format);

  GenericHighlighter::Rule& stringRule = highlighter.addRule();
  stringRule.addPattern(QRegularExpression("This string will be green."));
  format.setForeground(Qt::green);
  stringRule.setFormat(format);

  highlighter.setDocument(&doc);
  highlighter.rehighlight();

  QString html;
  highlighter.asHtml(html);

  QString refHtml(
    "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" "
    "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
    "<html><head><meta name=\"qrichtext\" content=\"1\" />"
    "<style type=\"text/css\">\n"
    "p, li { white-space: pre-wrap; }\n"
    "</style></head><body>\n"
    "<pre style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; "
    "margin-right:0px; -qt-block-indent:0; text-indent:0px;\">"
    "<!--StartFragment--><span style=\" color:#0000ff;\">"
    "A regexp will turn this blue.</span></pre>\n"
    "<pre style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; "
    "margin-right:0px; -qt-block-indent:0; text-indent:0px;\">"
    "<span style=\" color:#a0a0a4;\">"
    "Only </span><span style=\" color:#ffff00;\">"
    "this</span><span style=\" color:#a0a0a4;\"> "
    "and </span><span style=\" color:#ffff00;\">"
    "that</span><span style=\" color:#a0a0a4;\"> "
    "will be yellow.</span></pre>\n"
    "<pre style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; "
    "margin-right:0px; -qt-block-indent:0; text-indent:0px;\">"
    "<span style=\" color:#ff0000;\">"
    "A wildcard expression will turn this red.</span></pre>\n"
    "<pre style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; "
    "margin-right:0px; -qt-block-indent:0; text-indent:0px;\">"
    "<span style=\" color:#00ff00;\">"
    "This string will be green.</span></pre>\n"
    "<pre style=\"-qt-paragraph-type:empty; margin-top:0px; "
    "margin-bottom:0px; margin-left:0px; margin-right:0px; "
    "-qt-block-indent:0; text-indent:0px; color:#a0a0a4;\">"
    "<br /><!--EndFragment--></pre></body></html>");

  EXPECT_STREQ(qPrintable(refHtml), qPrintable(html));
}
