#include "opkg_command.h"

#include "command.h"
#include "utils_internal.h"
using namespace internal;

#include <QDir>
#include <QDebug>
#include <QFlags>
#include <QRegularExpression>

OpkgCommand::OpkgCommand(bool noaction, QString const &opkg_commands_filename)
  : m_noaction(noaction)
  , m_opkg_commands_filename(opkg_commands_filename) {
    cleanUpOpkgCache();
    execCommandsInternal();
}

bool OpkgCommand::readCommands() {
    QFile opkgFile(QDir::cleanPath(m_opkg_commands_dir + QDir::separator() + m_opkg_commands_filename));
    if (!opkgFile.exists()) {
        qCritical() << __func__ << ":" << __LINE__
                    << opkgFile.fileName() << "does not exists";
        return false;
    }

    m_commands.clear();

    if (opkgFile.open(QIODevice::ReadOnly)) {
        QTextStream in(&opkgFile);
        while (!in.atEnd()) {
            QString line = in.readLine();
            // TODO: "^\\s*[#]{0,}$" : empty line or comment line starting with #
            static const QRegularExpression comment("^\\s*[#].*$");
            static const QRegularExpression emptyLine("^\\s*$");
            if (line.indexOf(emptyLine, 0) == -1 &&
                line.indexOf(comment, 0) == -1) {
                QString const &commandLine = line.trimmed();
                if (!commandLine.isEmpty()) {
                    m_commands << commandLine;
                }
            }
        }
    } else {
        qCritical() << __func__ << ":" << __LINE__
                    << "error opening" << opkgFile.fileName();
    }

    return m_commands.size() > 0;
}

bool OpkgCommand::execCommandsInternal() {
    if (readCommands()) {
        // command lines are located between markers: <OPKG>...<OPKG>
        // they are later removed when used by the update-tool.
        qCritical().noquote() << "<OPKG>";
        QListIterator<QString> it(m_commands);
        while (it.hasNext()) {
            QString command = it.next();
            QStringList cmdAndOptions = command.split(u' ', QString::SkipEmptyParts);
            if (cmdAndOptions.size() > 0) {
                QString const &cmd = cmdAndOptions.takeFirst();
                if (m_noaction) {
                    if (cmd.contains("opkg")) {
                        cmdAndOptions.prepend("--noaction");
                    } else continue; // only opkg has the --noaction option
                }
                QStringList const &options = cmdAndOptions;
                if (exec(cmd, options)) {
                    qCritical().noquote() << cmd << options.join(" ") << "ok" << "<OPKG>";
                } else {
                    qCritical().noquote() << cmd << options.join(" ") << "FAIL" << "<OPKG>";
                }
            }
        }
        return true;
    }
    return false;

}

bool OpkgCommand::execCommands() {
    if (readCommands()) {
        QListIterator<QString> it(m_commands);
        while (it.hasNext()) {
            QString command = it.next();
            QStringList cmdAndOptions = command.split(u' ', QString::SkipEmptyParts);
            if (cmdAndOptions.size() > 0) {
                QString const &cmd = cmdAndOptions.takeFirst();
                if (m_noaction) {
                    cmdAndOptions.prepend("--noaction");
                }
                QStringList const &options = cmdAndOptions;
                if (exec(cmd, options)) {
                    qCritical().noquote() << cmd << options.join(" ");
                } else {
                    qCritical().noquote() << cmd << options.join(" ") << "FAIL";
                    return false;
                }
            }
        }
        return true;
    }
    return false;

#if 0

    QFile opkgFile(QDir::cleanPath(m_opkg_commands_dir + QDir::separator() + m_opkg_commands_filename));
    if (!opkgFile.exists()) {
        qCritical() << __func__ << ":" << __LINE__
                    << opkgFile.fileName() << "does not exists";
        return false;
    }

    if (opkgFile.open(QIODevice::ReadOnly)) {
        QTextStream in(&opkgFile);
        while (!in.atEnd()) {
            QString line = in.readLine();
            // TODO: "^\\s*[#]{0,}$" : empty line or comment line starting with #
            static const QRegularExpression comment("^\\s*[#].*$");
            static const QRegularExpression emptyLine("^\\s*$");
            if (line.indexOf(emptyLine, 0) == -1 &&
                line.indexOf(comment, 0) == -1) {
                QString const &commandLine = line.trimmed();
                if (!commandLine.isEmpty()) {
                    QStringList cmdAndOptions = commandLine.split(u' ', QString::SkipEmptyParts);
                    if (cmdAndOptions.size() > 0) {
                        QString const &cmd = cmdAndOptions.takeFirst();
                        if (m_noaction) {
                            cmdAndOptions.prepend("--noaction");
                        }
                        QStringList const &options = cmdAndOptions;
                        if (exec(cmd, options)) {
                            qCritical().noquote() << cmd << options.join(" ") << "ok";
                        } else {
                            qCritical().noquote() << cmd << options.join(" ") << "FAIL";
                        }
                    } else {
                        continue;
                    }
                }
            }
        }
        return true;
    } else {
        qCritical() << __func__ << ":" << __LINE__
                    << "error opening" << opkgFile.fileName();
    }

    return false;
#endif
}

bool OpkgCommand::exec(QString const &cmd, QStringList const &options,
                       int start_timeout, int finish_timeout) {
    bool const verbose = false;
    return Command(cmd, options, "/tmp", verbose, start_timeout, finish_timeout).exec();
}

bool OpkgCommand::cleanUpOpkgCache() {
    bool removedFiles = true;
    QDir dir("/var/cache/opkg/");
    if (dir.exists()) {
        dir.setNameFilters(QStringList() << ".gz" << ".ipk");
        dir.setFilter(QDir::Files);
        foreach(QString dirFile, dir.entryList()) {
            removedFiles &= dir.remove(dirFile);
        }
    }

    if (removedFiles == false) {
        qCritical() << "some errors while cleaning up opkg-cache";
    }

    return removedFiles;
}