#include "settingsdialog.h"
#include "ui_settingsdialog.h"

using namespace Xybrid;

#include <QDialogButtonBox>
#include <QPushButton>
#include <QRegularExpression>
#include <QDebug>

#include "fileops.h"
#include "config/audioconfig.h"
#include "config/uiconfig.h"
using namespace Xybrid::Config;

#include "audio/audioengine.h"
using namespace Xybrid::Audio;

#include "util/strings.h"

SettingsDialog* SettingsDialog::instance = nullptr;

namespace { // clazy:excludeall=non-pod-global-static
    std::vector<std::function<void()>>* bnd;

    void bind(QCheckBox* o, bool& v) {
        o->setChecked(v);
        bnd->push_back([o, &v] {
            v = o->isChecked();
        });
    }

    const QRegularExpression numeric("[0-9.]+");

    void bind(QComboBox* o, int& v, const QStringList& items) {
        o->clear();
        o->addItems(items);
        int ld = 100000000;
        QString cm;
        for (auto& i : items) { // find closest match
            auto q = numeric.match(i).captured().toInt();
            int id = std::abs(q - v);
            if (id < ld) {
                ld = id;
                cm = i;
            }
        }
        o->setCurrentText(cm);
        bnd->push_back([o, &v] { // convert back to int
            v = numeric.match(o->currentText()).captured().toInt();
        });
    }

    void bind(QSpinBox* o, int& v, int min, int max, const QString& suffix = { }) {
        o->setRange(min, max);
        o->setValue(std::clamp(v, min, max));
        o->setSuffix(suffix);
        bnd->push_back([o, &v] {
            v = o->value();
        });
    }
}

SettingsDialog::SettingsDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::SettingsDialog) {
    ui->setupUi(this);

    connect(ui->buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked, this, &SettingsDialog::apply);

    instance = this;
    bnd = &this->binds;

    // audio page
    QStringList sampleRates = { qs("44100Hz"), qs("48000Hz"), qs("96000Hz") };
    const constexpr int minBufMs = 25, maxBufMs = 250;
    const QString ms = qs("ms");

    bind(ui->playbackSampleRate, AudioConfig::playbackSampleRate, sampleRates);
    bind(ui->playbackBufferMs, AudioConfig::playbackBufferMs, minBufMs, maxBufMs, ms);
    bind(ui->previewSampleRate, AudioConfig::previewSampleRate, sampleRates);
    bind(ui->previewBufferMs, AudioConfig::previewBufferMs, minBufMs, maxBufMs, ms);
    bind(ui->renderSampleRate, AudioConfig::renderSampleRate, sampleRates);

    // UI page
    bind(ui->verticalKnobs, UIConfig::verticalKnobs);
    bind(ui->invertScrollWheel, UIConfig::invertScrollWheel);
}

SettingsDialog::~SettingsDialog() {
    if (instance == this) instance = nullptr;
    delete ui;
}

void SettingsDialog::apply() {
    for (auto& f : binds) f();
    FileOps::saveConfig();

    // if left in preview mode, stop to allow settings to take
    if (audioEngine->playbackMode() == audioEngine->Previewing) audioEngine->stop();
}

void SettingsDialog::reject() {
    QDialog::reject();
    if (instance == this) instance = nullptr;
    deleteLater();
}

void SettingsDialog::tryOpen() {
    if (!instance) {
        (new SettingsDialog(nullptr))->show();
    } else {
        instance->show();
        instance->raise();
        instance->activateWindow();
    }
}



