#include "GutterPainter.h"
#include "CodeEditor.h"


GutterPainter::GutterPainter(CodeEditor *editor, QPaintEvent *event)
    : editor(editor)
    , painter(editor->gutterArea)
    , event(event)
    , fontMetrics(editor->fontMetrics())
    , colorTheme(GetColorTheme())
{

}

void GutterPainter::Paint()
{
    painter.fillRect(event->rect(), colorTheme.gutterBackground);

    LoopState loopState(editor);
    // We will now loop through all visible lines and paint the line numbers in the
    // extra area for each line. Notice that in a plain text edit each line will
    // consist of one QTextBlock; though, if line wrapping is enabled, a line may span
    // several rows in the text edit's viewport.
    //
    // We get the top and bottom y-coordinate of the first text block, and adjust these
    // values by the height of the current text block in each iteration in the loop.
    while (loopState.block.isValid() && loopState.top <= event->rect().bottom())
    {
        if (loopState.block.isVisible() && loopState.bottom >= event->rect().top())
        {
            drawLineNumber(loopState);
            if (editor->lineHasError(loopState.blockNumber()))
                drawGutterErrorMarker(loopState);
        }

        loopState.advanceToNextLine();
    }
}

void GutterPainter::drawLineNumber(const LoopState &loopState)
{
    QString number = QString::number(loopState.blockNumber() + 1);
    painter.setPen(colorTheme.lineNumber);
    painter.drawText(0, loopState.top, editor->gutterArea->width(), fontMetrics.height(),
                     Qt::AlignRight, number);
}

void GutterPainter::drawGutterErrorMarker(const LoopState &loopState)
{
    int s = fontMetrics.height() - 8;
    painter.setBrush(QBrush(Qt::red));
    painter.drawEllipse(4, loopState.top + 4, s, s);
}

GutterPainter::LoopState::LoopState(CodeEditor *editor)
    : editor(editor)
    , block(editor->firstVisibleBlock())
    , top((int) editor->blockBoundingGeometry(block).translated(editor->contentOffset()).top())
    , bottom(top + (int) editor->blockBoundingRect(block).height())
{}

int GutterPainter::LoopState::blockNumber() const
{
    return block.blockNumber();
}

void GutterPainter::LoopState::advanceToNextLine()
{
    block = block.next();
    top = bottom;
    bottom = top + (int) editor->blockBoundingRect(block).height();
}
