/*
    SPDX-FileCopyrightText: 2009 George Kiagiadakis <gkiagia@users.sourceforge.net>

    SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "debuggermanager.h"

#include <KConfigGroup>

#include "backtracegenerator.h"
#include "debugger.h"
#include "debuggerlaunchers.h"

struct DebuggerManager::Private {
    BacktraceGenerator *btGenerator;
    bool debuggerRunning;
    QList<AbstractDebuggerLauncher *> externalDebuggers;
    DBusInterfaceAdaptor *dbusInterfaceAdaptor;
};

DebuggerManager::DebuggerManager(const Debugger &internalDebugger, const QList<Debugger> &externalDebuggers, QObject *parent)
    : QObject(parent)
    , d(new Private)
{
    d->debuggerRunning = false;
    d->btGenerator = new BacktraceGenerator(internalDebugger, this);
    connect(d->btGenerator, &BacktraceGenerator::starting, this, &DebuggerManager::onDebuggerStarting);
    connect(d->btGenerator, &BacktraceGenerator::done, this, &DebuggerManager::onDebuggerFinished);
    connect(d->btGenerator, &BacktraceGenerator::someError, this, &DebuggerManager::onDebuggerFinished);
    connect(d->btGenerator, &BacktraceGenerator::failedToStart, this, &DebuggerManager::onDebuggerFinished);

    foreach (const Debugger &debugger, externalDebuggers) {
        if (debugger.isInstalled()) {
            // TODO: use TerminalDebuggerLauncher instead
            addDebugger(new DefaultDebuggerLauncher(debugger, this));
        }
    }

    // setup kdevelop compatibility
    d->dbusInterfaceAdaptor = new DBusInterfaceAdaptor(this);
}

DebuggerManager::~DebuggerManager()
{
    if (d->btGenerator->state() == BacktraceGenerator::Loading) {
        // if the debugger is running, kill it and continue the process.
        delete d->btGenerator;
        onDebuggerFinished();
    }

    delete d;
}

bool DebuggerManager::debuggerIsRunning() const
{
    return d->debuggerRunning;
}

bool DebuggerManager::showExternalDebuggers() const
{
    KConfigGroup config(KSharedConfig::openConfig(), "DrKonqi");
    return config.readEntry("ShowDebugButton", false);
}

QList<AbstractDebuggerLauncher *> DebuggerManager::availableExternalDebuggers() const
{
    return d->externalDebuggers;
}

BacktraceGenerator *DebuggerManager::backtraceGenerator() const
{
    return d->btGenerator;
}

void DebuggerManager::addDebugger(AbstractDebuggerLauncher *launcher, bool emitsignal)
{
    d->externalDebuggers.append(launcher);
    connect(launcher, &AbstractDebuggerLauncher::starting, this, &DebuggerManager::onDebuggerStarting);
    connect(launcher, &AbstractDebuggerLauncher::finished, this, &DebuggerManager::onDebuggerFinished);
    connect(launcher, &AbstractDebuggerLauncher::invalidated, this, &DebuggerManager::onDebuggerInvalidated);
    if (emitsignal) {
        emit externalDebuggerAdded(launcher);
    }
}

void DebuggerManager::onDebuggerStarting()
{
    d->debuggerRunning = true;
    emit debuggerStarting();
    emit debuggerRunning(true);
}

void DebuggerManager::onDebuggerFinished()
{
    d->debuggerRunning = false;
    emit debuggerFinished();
    emit debuggerRunning(false);
}

void DebuggerManager::onDebuggerInvalidated()
{
    AbstractDebuggerLauncher *launcher = qobject_cast<AbstractDebuggerLauncher *>(sender());
    Q_ASSERT(launcher);
    int index = d->externalDebuggers.indexOf(launcher);
    Q_ASSERT(index >= 0);
    d->externalDebuggers.removeAt(index);
    emit externalDebuggerRemoved(launcher);
}
