#include "remarkupplugin.h"
#include "remarkupparserthread.h"

#include "SciDoc.h"
#include "JuffScintilla.h"
#include <QDebug>
#include <QMap>
#include <QDomDocument>
#include "AppInfo.h"
#include "LexerStorage.h"

using namespace Juff;

//"PhutilRemarkupDefaultBlockRule",

//"PhutilRemarkupHeaderBlockRule",
//"PhutilRemarkupListBlockRule",
//"PhutilRemarkupNoteBlockRule",

//"PhutilRemarkupHorizontalRuleBlockRule",
//"PhutilRemarkupReplyBlockRule",
//"PhutilRemarkupCodeBlockRule",
//"PhutilRemarkupLiteralBlockRule",
//"PhutilRemarkupTableBlockRule",
//"PhutilRemarkupSimpleTableBlockRule",

//"PhutilRemarkupInterpreterBlockRule"

class BlocksHighlighter{

public:
    BlocksHighlighter(){
    }

    QDomDocument loadScheme(){
            QDomDocument doc("JuffScheme");
            QString fileName = QString("remarkup.xml");
            fileName = AppInfo::configDirPath() + "/hlschemes/" + fileName;

            QFile file(fileName);
            if ( !file.open(QIODevice::ReadOnly) ) {
                qDebug()<<(QString("[BlocksScheme] No scheme found in '%1'. Using the standard one.").arg(fileName));
                return doc;
            }

            QString err;
            int errLine, errCol;
            if ( !doc.setContent(&file, &err, &errLine, &errCol) ) {
                qDebug() << QString("[BlocksScheme] File %1: XML reading error: '%2', line %3, column %4")
                        .arg(fileName).arg(err).arg(errLine).arg(errCol);
            }

            file.close();
            return doc;
    }

    void init(){
        const QDomDocument docScheme = loadScheme();

        QDomElement root = docScheme.documentElement().firstChildElement("blockrules");

//        while (!root.isNull() && root.tagName().compare("blockrules")){
//            root = root.nextSiblingElement();
//        }


        if (root.isNull()){
            qDebug()<<"[BlocksScheme] not found blocks section";
            return;
        }

        int countRules=0;
        QDomElement styleNode = root.firstChildElement("style");
        while (!styleNode.isNull()){
            QString rule = styleNode.attribute("name", "");
            if (!rule.isEmpty()) {
                QColor colorBg = QVariant(styleNode.attribute("color", "#FFFFFF")).value<QColor>();
                QString markerType = styleNode.attribute("marker", "Background");

                QsciScintilla::MarkerSymbol marker = QsciScintilla::Background;

                if (markerType == "FullRectangle"){
                    marker = QsciScintilla::FullRectangle;

                } else if (markerType == "LeftRectangle") {
                    marker = QsciScintilla::LeftRectangle;

                } else if (markerType == "Underline") {
                    marker = QsciScintilla::Underline;
                }

                rules.insert(rule, countRules);
                Style style;
                style.color = colorBg;
                style.marker = marker;
                markerStyles.append(style);

                ++countRules;
            }

            styleNode = styleNode.nextSiblingElement("style");
        }
    }

    void defineMarkersForDoc(JuffScintilla* doc){
        doc->setMarginMarkerMask(0, 32767);

        for (int i=0; i<markerStyles.size(); ++i){
            doc->markerDefine(markerStyles[i].marker, markersCustomOffset + i);
            doc->setMarkerBackgroundColor(markerStyles[i].color, markersCustomOffset + i);
        }
    }

    void removeMarkers(JuffScintilla* doc){
        for (int i=0; i<markerStyles.size(); ++i){
            doc->markerDeleteAll(i + markersCustomOffset);
        }
    }

    void highlightDoc(JuffScintilla* doc, const std::vector<Block>& blocks){
        removeMarkers(doc);

        for (size_t i=0; i<blocks.size(); ++i){
            const Block& block = blocks.at(i);

            QString debug__rulename = QString::fromStdString(block.rule);
            int ruleId = rules.value(QString::fromStdString(block.rule), -1);

            //unknown rule
            if (ruleId == -1) continue;

            int markerForRule = ruleId + markersCustomOffset;

            for (int lineNo = block.start; lineNo<block.start + block.num_lines; ++lineNo){
                doc->markerAdd(lineNo, markerForRule);
            }
        }
    }

private:

    struct Style {
        QColor color;
        QsciScintilla::MarkerSymbol marker;
    };

    QVector<Style> markerStyles;
    QMap<QString, int> rules;
    const int markersCustomOffset = 3;
} highlighterRemarkupBlocks;

QAction* createAction(const QString& title, const QKeySequence& key, const QObject* this_, const char* slot) {
    QAction* act = new QAction(title, 0);
    this_->connect(act, SIGNAL(triggered()), this_, slot);
    act->setShortcut(key);
    return act;
}

RemarkupPlugin::RemarkupPlugin(): QObject(), JuffPlugin()
{
    threadRemarkupParser = new RemarkupParserThread();

    connect(threadRemarkupParser, SIGNAL(updateDoc(Blocks, Juff::JuffScintilla*)), this, SLOT(onTextParsed(Blocks, Juff::JuffScintilla*)));
}

RemarkupPlugin::~RemarkupPlugin(){
    threadRemarkupParser->exit();
    threadRemarkupParser->wait();
    delete threadRemarkupParser;
}

//	info
QString RemarkupPlugin::name()const {return "Remarkup";}
QString RemarkupPlugin::title() const {return "Remarkup";}
QString RemarkupPlugin::description() const {return "Remarkup";}
QString RemarkupPlugin::targetEngine() const{
    return "all";
}

void
RemarkupPlugin::init(){

    connect(api(), SIGNAL(docOpened(Juff::Document*, Juff::PanelIndex)), SLOT(onDocOpened(Juff::Document*, Juff::PanelIndex)));
    connect(api(), SIGNAL(docTextChanged(Juff::Document*)), this, SLOT(refresh(Juff::Document*)));
    connect(api(), SIGNAL(docActivated(Juff::Document*)), this, SLOT(refresh(Juff::Document*)));
    connect(api(), SIGNAL(docSyntaxChanged(Juff::Document*,QString)), this, SLOT(onDocSyntaxChanged(Juff::Document*,QString)));
    connect(api(), SIGNAL(docClosed(Juff::Document*)), this, SLOT(onDocClosed(Juff::Document*)));
     connect(api(), SIGNAL(docRenamed(Juff::Document*,QString)), this, SLOT(onDocRenamed(Juff::Document*,QString)));


    highlighterRemarkupBlocks.init();
    threadRemarkupParser->start();

//    connect(api(), SIGNAL(docActivated(Juff::Document*)), this, SLOT(onDocActivated(Juff::Document*)));



}

void
RemarkupPlugin::onDocOpened(Juff::Document* doc, Juff::PanelIndex panel){
    onDocSyntaxChanged(doc, doc->syntax());
}

void
RemarkupPlugin::onDocClosed(Juff::Document* doc){
    if (doc->isNull()) {return;}
    if (doc->syntax().compare("Remarkup") !=0){return;}

    threadRemarkupParser->stop();
}


void
RemarkupPlugin::onDocSyntaxChanged(Juff::Document* doc, QString syntax){
    if (syntax.compare("Remarkup") !=0){return;}

    SciDoc* __doc = qobject_cast<SciDoc*> (doc);
    JuffScintilla* scintilla = __doc->getCurrentEditor();
    if (!scintilla) return;

    highlighterRemarkupBlocks.defineMarkersForDoc(scintilla);
}

void
RemarkupPlugin::refresh(Juff::Document* doc){
    if (doc->isNull()) {return;}
    if (doc->syntax().compare("Remarkup") !=0){return;}

    SciDoc* __doc = qobject_cast<SciDoc*> (api()->currentDocument());
    JuffScintilla* scintilla = __doc->getCurrentEditor();

    threadRemarkupParser->processDoc(scintilla);
}

void
RemarkupPlugin::onTextParsed(const Blocks& blocks, Juff::JuffScintilla* doc){
    highlighterRemarkupBlocks.highlightDoc(doc, blocks);

}

Juff::ActionList
RemarkupPlugin::mainMenuActions(Juff::MenuID id) const {
    Juff::ActionList list;

    if ( id == Juff::MenuEdit ) {
        list << createAction(tr("Bold"), QKeySequence("Ctrl+B"), this, SLOT(setSelectionBold()));
        list << createAction(tr("Italic"), QKeySequence("Ctrl+I"), this, SLOT(setSelectionItalic()));
    }
    return list;
}

void
RemarkupPlugin::setSelectionItalic(){
    Juff::Document*  doc = this->api()->currentDocument();
    if (doc->isNull()) {return;}
    if (doc->syntax().compare("Remarkup") !=0){return;}

    QString textInput;
    doc->getSelectedText(textInput);

    QString textItalic = QString("//%1//").arg(textInput);
    doc->replaceSelectedText(textItalic);
}

void
RemarkupPlugin::setSelectionBold(){
    Juff::Document*  doc = this->api()->currentDocument();
    if (doc->isNull()) {return;}
    if (doc->syntax().compare("Remarkup") !=0){return;}

    QString textInput;
    doc->getSelectedText(textInput);

    QString textBold = QString("**%1**").arg(textInput);
    doc->replaceSelectedText(textBold);
}




