/***************************** LICENSE START ***********************************

 Copyright 2013 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include "MvQLogDialog.h"

#include "IconObject.h"
#include "Folder.h"
#include "Log.h"

#include <QDebug>
#include <QDialogButtonBox>
#include <QFile>
#include <QHBoxLayout>
#include <QLabel>
#include <QPlainTextEdit>
#include <QPushButton>
#include <QSettings>
#include <QTextStream>
#include <QToolButton>
#include <QVBoxLayout>

#include "MvQFileWatcher.h"
#include "MvQIconProvider.h"
#include "MvQMethods.h"

static std::set<MvQLogDialog*> windows;

MvQLogDialog::MvQLogDialog() :
    current_(nullptr),
    file_(nullptr)
{
    // Window decoration
    setWindowIcon(QPixmap(":/desktop/log.svg"));

    auto* vb = new QVBoxLayout(this);

    //-----------------------
    // Header
    //------------------------

    auto* hb = new QHBoxLayout;
    vb->addLayout(hb);

    auto* logLabel = new QLabel(this);
    logLabel->setPixmap(QPixmap(":/desktop/log.svg"));
    hb->addWidget(logLabel);

    headerLabel_ = new QLabel("", this);
    headerLabel_->setObjectName(QString::fromUtf8("editorHeaderLabel"));
    headerLabel_->setMargin(4);
    headerLabel_->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
    headerLabel_->setAutoFillBackground(true);
    headerLabel_->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse);
    headerLabel_->setFrameShape(QFrame::Box);
    headerLabel_->setFrameShape(QFrame::StyledPanel);

    hb->addWidget(headerLabel_, 1);

    //-------------------
    // Toolbar
    //-------------------

    hb = new QHBoxLayout;
    vb->addLayout(hb);

    auto* clearTb = new QToolButton(this);
    clearTb->setAutoRaise(true);
    clearTb->setText(tr("Clear"));
    clearTb->setToolTip(tr("Clear log"));
    hb->addWidget(clearTb);

    connect(clearTb, SIGNAL(clicked(bool)),
            this, SLOT(slotClear(bool)));

    freezeTb_ = new QToolButton(this);
    freezeTb_->setAutoRaise(true);
    freezeTb_->setText(tr("Freeze"));
    freezeTb_->setToolTip(tr("Freeze log"));
    freezeTb_->setCheckable(true);

    hb->addWidget(freezeTb_);

    connect(freezeTb_, SIGNAL(toggled(bool)),
            this, SLOT(slotFreeze(bool)));

    hb->addStretch(1);

    //-------------------
    // TextEdit
    //-------------------

    textEdit_ = new QPlainTextEdit(this);
    textEdit_->setReadOnly(true);
    textEdit_->setFont(MvQ::findMonospaceFont());

    vb->addWidget(textEdit_, 1);

    //-------------------
    // Buttonbox
    //-------------------

    auto* buttonBox = new QDialogButtonBox(this);
    vb->addWidget(buttonBox);

    buttonBox->addButton(QDialogButtonBox::Close);
    connect(buttonBox, SIGNAL(rejected()),
            this, SLOT(reject()));

    //-------------------
    // Watcher
    //-------------------

    watcher_ = new MvQFileWatcher;

    connect(watcher_, SIGNAL(ready(const char*)),
            this, SLOT(slotReady(const char*)));

    connect(watcher_, SIGNAL(done(FILE*)),
            this, SLOT(slotDone(FILE*)));

    windows.insert(this);
}

MvQLogDialog::~MvQLogDialog()
{
    // Not called
    delete watcher_;
}

void MvQLogDialog::open(IconObject* icon)
{
    MvQLogDialog* e = icon->logWindow();
    if (e == nullptr) {
        for (auto window : windows)
            if (window->current_ == nullptr)
                e = window;

        if (e == nullptr)
            e = new MvQLogDialog();
    }
    Q_ASSERT(e);
    e->show(icon);
    e->raise();
}

void MvQLogDialog::show(IconObject* icon)
{
    if (icon != current_) {
        current_ = icon;
        if (current_) {
            current_->logWindow(this);

            // Update header and title
            if (current_ == Folder::top()) {
                setWindowTitle(tr("Log window - Metview"));
                QString str = tr("<b><font color=#505050> Log messages for all the icons</font></b>");
                headerLabel_->setText(str);
            }
            else {
                QString str = QString::fromStdString(current_->name());
                if (current_->parent()) {
                    str += " - " + QString::fromStdString(current_->parent()->fullName());
                }
                str += " - Log Window - Metview";
                setWindowTitle(str);

                str.clear();
                str = tr("<b><font color=#505050> Log messages for icon: </font>");
                str += "<font color=#084cb3>" + QString::fromStdString(current_->name()) + "</font></b>";
                headerLabel_->setText(str);
            }

            // Load data
            load();

            readSettings();
        }
    }
    QWidget::show();
}

void MvQLogDialog::load()
{
    watcher_->stop();
    textEdit_->clear();

    if (file_) {
        fclose(file_);
        file_ = nullptr;
    }

    Path p = current_->logPath();

    std::cout << "log: " << p.str() << std::endl;

    // Read contents
    QFile f(QString::fromStdString(p.str()));
    f.open(QFile::ReadOnly | QFile::Text);

    QTextStream readStream(&f);
    textEdit_->appendPlainText(readStream.readAll());
    // textEdit_->appendHtml(formatText(readStream.readAll()));
    f.close();

    // Set up file watcher
    file_ = fopen(p.str().c_str(), "r");
    if (file_) {
        fseek(file_, 0, SEEK_END);
        watcher_->start(file_, p.str());
    }
}

void MvQLogDialog::reject()
{
    watcher_->stop();

    if (file_) {
        fclose(file_);
        file_ = nullptr;
    }

    textEdit_->clear();

    if (current_)
        current_->logWindow(nullptr);
    current_ = nullptr;

    writeSettings();

    QDialog::reject();
}

void MvQLogDialog::closeEvent(QCloseEvent* event)
{
    reject();
    event->accept();
}


void MvQLogDialog::slotClear(bool)
{
    Path p = current_->logPath();
    FILE* f = fopen(p.str().c_str(), "w");
    if (f)
        fclose(f);

    load();
}

void MvQLogDialog::slotFreeze(bool b)
{
    if (b)
        watcher_->stop();
    else
        load();
}

void MvQLogDialog::slotDone(FILE*)
{
    watcher_->stop();
    // enable();
    std::cout << "done" << std::endl;
}

void MvQLogDialog::slotReady(const char* buf)
{
    textEdit_->appendPlainText(QString(buf));
    // textEdit_->appendHtml(formatText(QString(buf)));
}

QString MvQLogDialog::formatText(QString txt)
{
    // qDebug() << "add" << txt;

    QString res;
    QStringList lst = txt.split("\n");
    foreach (QString line, lst) {
        res += line + "<br>";

        /*QRegExp rx("\\[(.+)\\]");
        if(rx.indexIn(line) > -1)
        {
            QString v=rx.cap(1);
            res+="<b>" + v + "</b> -";
            res+=line.mid(v.size()+2)+ "<br>";
        }
        else
            res+=line + "<br>";*/
    }

    return res;
}


void MvQLogDialog::writeSettings()
{
    QSettings settings(MVQ_QSETTINGS_DEFAULT_ARGS, "MV4-Desktop-LogDialog");

    // We have to clear it so that should not remember all the previous values
    settings.clear();

    settings.beginGroup("main");
    settings.setValue("size", size());
    settings.endGroup();
}

void MvQLogDialog::readSettings()
{
    QSettings settings(MVQ_QSETTINGS_DEFAULT_ARGS, "MV4-Desktop-LogDialog");

    settings.beginGroup("main");
    if (settings.contains("size")) {
        resize(settings.value("size").toSize());
    }
    else {
        resize(QSize(520, 500));
    }

    settings.endGroup();
}
