#include "command.h"

#include <QProcess>
#include <QDebug>
#include <QRegularExpression>

Command::Command(QString const &command, int start_timeout, int finish_timeout)
    : m_command(command.trimmed())
    , m_commandResult("")
    , m_waitForStartTimeout(start_timeout)
    , m_waitForFinishTimeout(finish_timeout) {
}

QString Command::getCommandResult() const {
    return m_commandResult;
}

void Command::readyReadStandardOutput() {
    QProcess *p = (QProcess *)sender();
    m_commandResult += p->readAllStandardOutput();
    // qCritical() << m_commandResult;
}

void Command::readyReadStandardError() {
    QProcess *p = (QProcess *)sender();
    QByteArray buf = p->readAllStandardError();
    qCritical() << buf;
}

void Command::finished(int /*exitCode*/, QProcess::ExitStatus /*exitStatus*/) {
    QProcess *p = (QProcess *)sender();
    // read all remaining data sent to the process, just in case
    QString d = p->readAllStandardOutput();
    if (!d.isEmpty()) {
        m_commandResult += d;
    }
    disconnect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(readyReadStandardOutput()));
    disconnect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(readyReadStandardError()));
}

bool Command::execute(QString workingDirectory, QStringList args) {
    QScopedPointer<QProcess> p(new QProcess(this));
    p->setProcessChannelMode(QProcess::MergedChannels);

    connect(&(*p), SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadStandardOutput()));
    connect(&(*p), SIGNAL(readyReadStandardError()), this, SLOT(readyReadStandardError()));

    qCritical() << "START COMMAND" << m_command << "IN" << workingDirectory;

    p->setWorkingDirectory(workingDirectory);
    if (!args.isEmpty()) {
        p->start(m_command, args);
    } else {
        p->start(m_command);
    }

    if (p->waitForStarted(m_waitForStartTimeout)) {
        if (p->state() == QProcess::ProcessState::Running) {
            if (p->waitForFinished(m_waitForFinishTimeout)) {
                if (p->exitStatus() == QProcess::NormalExit) {
                    qInfo() << "EXECUTED" << m_command
                            << "with code" << p->exitCode();
                    // qInfo() << "RESULT" << m_commandResult;
                    return true;
                } else {
                    qCritical() << "PROCESS" << m_command << "CRASHED with code"
                                << p->exitCode();
                }
            } else {
                qCritical() << "PROCESS" << m_command << "DID NOT FINISH";
            }
        } else {
            qCritical() << "WRONG PROCESS STATE" << p->state();
        }
    } else {
        qCritical() << "PROCESS" << m_command << "TIMEOUT AT START";
    }
    return false;
}
