/*
 * Copyright (C) 2009-2010  Lorenzo Bettini <http://www.lorenzobettini.it>
 * See COPYING file that comes with this distribution
 */

#include <QtDebug>
#include <QMutex>
#include <QRegExp>

#include "debuggerthread.h"
#include "stepconditionvariable.h"

#include <srchilite/sourcehighlight.h>
#include <srchilite/parserexception.h>
#include <srchilite/highlightevent.h>
#include <srchilite/highlighttoken.h>
#include <srchilite/highlightrule.h>

static QRegExp fileInfo("(\\S*):(\\d*)");

DebuggerThread::DebuggerThread(srchilite::SourceHighlight *sourcehighlight_,
                               const QString &langDefFile_,
                               const QString &contents, std::ostringstream *os,
                               QMutex *mutex_,
                               StepConditionVariable *waitCondVariable_) :
    sourcehighlight(sourcehighlight_), langDefFile(langDefFile_),
    contentsToHighlight(contents), outputBuffer(os), mutex(mutex_), waitCondVariable(waitCondVariable_)
{
    waitCondVariable->reset();
}

void DebuggerThread::run() {
    //ide->highlight(this);
    qDebug() << "DebuggerThread started\n";

    // set this as the listener for highlighting events
    sourcehighlight->setHighlightEventListener(this);

    inputBuffer.str(contentsToHighlight.toStdString());

    // let's highlight!
    try {
        sourcehighlight->highlight(inputBuffer, *outputBuffer, langDefFile.toStdString());
    } catch (const srchilite::ParserException &pe) {
        std::ostringstream details;
        details << pe;
        emit highlightException(details.str().c_str());
    } catch (const std::exception &e) {
        emit highlightException(e.what());
    }
    
    qDebug() << "Thread terminated";

}

void DebuggerThread::stepDebugging() {
    mutex->lock();
    waitCondVariable->waitStep = false;
    waitCondVariable->wakeAll();
    mutex->unlock();
}

void DebuggerThread::stopDebugging() {
    qDebug() << "stop debugging";
    mutex->lock();
    waitCondVariable->stop = true;
    waitCondVariable->waitStep = false;
    waitCondVariable->wakeAll();
    mutex->unlock();
}

void DebuggerThread::waitForStep() {
    // wait for a step command
    mutex->lock();
    if (waitCondVariable->waitStep) {
        waitCondVariable->wait(mutex);
    }
    mutex->unlock();

    if (waitCondVariable->stop) {
        // this will make source-highlight stop as soon as
        // it reaches the end of a line
        inputBuffer.setstate(std::ios_base::eofbit);
    }
}

void DebuggerThread::notify(const srchilite::HighlightEvent &event) {
    if (waitCondVariable->stop)
        return; // no need to catch any event
    // just wait that source-highlight finishes highlighting the current line

    waitCondVariable->waitStep = true;

    switch (event.type) {
    case srchilite::HighlightEvent::FORMAT:
        qDebug() << event.token.rule->getAdditionalInfo().c_str() << "\n";
        qDebug() << event.token.rule->toString().c_str() << "\n";
        if (fileInfo.indexIn(event.token.rule->getAdditionalInfo().c_str()) != -1) {
            emit debuggerFileInfo(fileInfo.cap(1), fileInfo.cap(2).toInt());
        }
        emit debuggerRegex(event.token.rule->toString().c_str());
        emit highlightedSomething();
        break;
    case srchilite::HighlightEvent::FORMATDEFAULT:
        emit debuggerRegex("");
        emit highlightedSomething();
        break;
    default:
        break;
    }

    waitForStep();
}
