//--
// This file is part of Sonic Pi: http://sonic-pi.net
// Full project source: https://github.com/samaaron/sonic-pi
// License: https://github.com/samaaron/sonic-pi/blob/main/LICENSE.md
//
// Copyright 2013, 2014, 2015, 2016 by Sam Aaron (http://sam.aaron.name).
// All rights reserved.
//
// Permission is granted for use, copying, modification, and
// distribution of modified versions of this work as long as this
// notice is included.
//++

#include "sonicpilog.h"

// Standard stuff
#include "model/sonicpitheme.h"
#include <QScrollBar>
#include <vector>

SonicPiLog::SonicPiLog(QWidget* parent)
    : QPlainTextEdit(parent)
{
    forceScroll = true;
    zoomLevel = 0;
}

void SonicPiLog::zoomIn()
{
    setZoomLevel(zoomLevel + 1);
}

void SonicPiLog::zoomOut()
{
    setZoomLevel(zoomLevel - 1);
}

void SonicPiLog::setZoomLevel(int zoom)
{
    const int MIN_ZOOM = -10;
    const int MAX_ZOOM = 10;

    // Clamp the desired zoom to your range
    int targetZoom = std::clamp(zoom, MIN_ZOOM, MAX_ZOOM);

    int delta = targetZoom - zoomLevel;

    if (delta > 0)
    {
        QPlainTextEdit::zoomIn(delta);
    }
    else if (delta < 0)
    {

        QPlainTextEdit::zoomOut(-delta);
    }
    zoomLevel = targetZoom;
}

int SonicPiLog::currentZoomLevel() const
{
    return zoomLevel;
}

void SonicPiLog::forceScrollDown(bool force)
{
    forceScroll = force;
}

void SonicPiLog::setTextColor(QColor c)
{
    QTextCharFormat tf;
    tf.setForeground(c);
    setCurrentCharFormat(tf);
}

void SonicPiLog::setTextBgFgColors(QColor bg, QColor fg)
{
    QTextCharFormat tf;
    tf.setBackground(bg);
    tf.setForeground(fg);
    setCurrentCharFormat(tf);
}

void SonicPiLog::setTextBackgroundColor(QColor c)
{
    QTextCharFormat tf;
    tf.setBackground(c);
    setCurrentCharFormat(tf);
}

void SonicPiLog::setFontFamily(QString font_name)
{
#ifdef __APPLE__
    setFont(QFont(font_name, 14, -1, false));
#elif __linux__
    setFont(QFont(font_name, 12, -1, false));
#else
    setFont(QFont(font_name, 8, -1, false));
#endif
}

void SonicPiLog::appendPlainText(QString text)
{
    QPlainTextEdit::appendPlainText(text);
    if (forceScroll)
    {
        QScrollBar* sb = verticalScrollBar();
        sb->setValue(sb->maximum());
    }
}

void SonicPiLog::handleMultiMessage(SonicPiLog::MultiMessage mm)
{
    int msg_count = int(mm.messages.size());
    SonicPiTheme* theme = mm.theme;

    QTextCharFormat tf;
    QString ss;

    tf.setForeground(theme->color("LogForeground"));
    tf.setBackground(theme->color("LogBackground"));
    setCurrentCharFormat(tf);

    ss.append("{run: ").append(QString::number(mm.job_id));
    ss.append(", time: ").append(QString::fromStdString(mm.runtime));
    if (!(mm.thread_name == "\"\""))
    {
        ss.append(", thread: ").append(QString::fromStdString(mm.thread_name));
    }
    ss.append("}");
    appendPlainText(ss);

    for (int i = 0; i < msg_count; i++)
    {
        ss = "";
        int msg_type = mm.messages[i].msg_type;
        std::string s = mm.messages[i].s;

        QStringList lines = QString::fromUtf8(s.c_str()).split(QRegularExpression("\\n"));

        if (s.empty())
        {
            ss.append(QString::fromUtf8(" │"));
        }
        else if (i == (msg_count - 1))
        {
            ss.append(QString::fromUtf8(" └─ "));
        }
        else
        {
            ss.append(QString::fromUtf8(" ├─ "));
        }

        appendPlainText(ss);

        for (int j = 0; j < lines.size(); ++j)
        {
            switch (msg_type)
            {
            case 0:
                tf.setForeground(theme->color("LogForeground"));
                tf.setBackground(theme->color("LogBackground"));
                break;
            case 1:
                tf.setForeground(theme->color("LogForeground_1"));
                tf.setBackground(theme->color("LogBackground_1"));
                break;
            case 2:
                tf.setForeground(theme->color("LogForeground_2"));
                tf.setBackground(theme->color("LogBackground_2"));
                break;
            case 3:
                tf.setForeground(theme->color("LogForeground_3"));
                tf.setBackground(theme->color("LogBackground_3"));
                break;
            case 4:
                tf.setForeground(theme->color("LogForeground_4"));
                tf.setBackground(theme->color("LogBackground_4"));
                break;
            case 5:
                tf.setForeground(theme->color("LogForeground_5"));
                tf.setBackground(theme->color("LogBackground_5"));
                break;
            case 6:
                tf.setForeground(theme->color("LogForeground_6"));
                tf.setBackground(theme->color("LogBackground_6"));
                break;
            default:
                tf.setForeground(theme->color("LogForeground"));
                tf.setBackground(theme->color("LogBackground"));
            }

            setCurrentCharFormat(tf);
            insertPlainText(lines.at(j));
            if ((j + 1) < lines.size())
            {
                tf.setForeground(theme->color("LogForeground"));
                setCurrentCharFormat(tf);
                if (i == (msg_count - 1))
                {
                    // we are the last message
                    // so don't print joining lines
                    insertPlainText("\n  ");
                }
                else
                {
                    insertPlainText("\n │");
                }
            }
        }

        tf.setForeground(theme->color("LogForeground"));
        tf.setBackground(theme->color("LogBackground"));
        setCurrentCharFormat(tf);
    }
    appendPlainText(QString::fromStdString(" "));

    if (forceScroll)
    {
        QScrollBar* sb = verticalScrollBar();
        sb->setValue(sb->maximum());
    }
}
