#include "syntaxhighlighter.h"
#include <set>

SyntaxHighlighter::SyntaxHighlighter(QTextDocument *parent) :
    QSyntaxHighlighter(parent)
{
    levelColor.push_back(QTextCharFormat());
    levelColor.push_back(QTextCharFormat());
    levelColor.push_back(QTextCharFormat());
    levelColor.push_back(QTextCharFormat());
    levelColor.push_back(QTextCharFormat());
    levelColor.push_back(QTextCharFormat());
    levelColor[0].setForeground(Qt::blue);
    levelColor[1].setForeground(Qt::red);
    levelColor[2].setForeground(Qt::darkGreen);
    levelColor[3].setForeground(Qt::darkRed);
    levelColor[4].setForeground(Qt::darkYellow);
    levelColor[5].setForeground(Qt::green);
    for (auto& tcf : levelColor) {
        tcf.setFontWeight(99);
    }
    comment.setForeground(Qt::gray);
}


void SyntaxHighlighter::highlightBlock(const QString &text)
{
    struct FormatState {
        QTextCharFormat* currentFormat;
        int startIndex = 0;
        int length = 0;
        SyntaxHighlighter* sh;

        FormatState(SyntaxHighlighter* sh) : currentFormat{ &sh->comment }, sh{ sh } {}

        void upateFormat(int len, QTextCharFormat* format) {
            if (format == currentFormat) {
                length++;
            }
            else {
                sh->setFormat(startIndex, length, *currentFormat);
                currentFormat = format;
                startIndex += length;
                length = 1;
            }
        }

        void finish() {
            sh->setFormat(startIndex, length, *currentFormat);
        }
    };

    int level = previousBlockState();
    if (level < 0) level = 0;
    FormatState fs(this);
    for (int i = 0; i < text.length(); i++) {
        auto& c = text[i];
        if (c == '[') {
            level++;
        }
        if (isBfChar(c)) {
            fs.upateFormat(1, &levelColor[level % levelColor.size()]);
        }
        else {
            fs.upateFormat(1, &comment);
        }
        if (c == ']') {
            level--;
        }
        /*if (c == '[') {
            level++;
        }
        if (isBfChar(c)) {
            setFormat(i, 1, levelColor[level % levelColor.size()]);
        }
        else {
            setFormat(i, 1, comment);
        }
        if (c == ']') {
            level--;
        }*/
    }
    fs.finish();
    setCurrentBlockState(level);
}


bool SyntaxHighlighter::isBfChar(const QChar& c)
{
    static const std::set<QChar> x{'+', '-', '<', '>', ',', '.', '[', ']'};
    return x.find(c) != x.end();
}