#include "transpose.h"
using Xybrid::Gadgets::Transpose;
using namespace Xybrid::Data;

#include "data/porttypes.h"

#include "config/pluginregistry.h"
using namespace Xybrid::Config;

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

#include "ui/patchboard/nodeobject.h"
#include "ui/gadgets/layoutgadget.h"
#include "ui/gadgets/knobgadget.h"
using namespace Xybrid::UI;

#include <cmath>

#include <QCborMap>

#define qs QStringLiteral

namespace {
    bool _ = PluginRegistry::enqueueRegistration([] {
        auto i = std::make_shared<PluginInfo>();
        i->id = "gadget:transpose";
        i->displayName = "Transpose";
        i->category = "Gadget";
        //i->hidden = true;
        i->createInstance = []{ return std::make_shared<Transpose>(); };
        PluginRegistry::registerPlugin(i);
        //inf = i;
    });
}

Transpose::Transpose() {

}

void Transpose::init() {
    addPort(Port::Input, Port::Command, 0);
    addPort(Port::Output, Port::Command, 0);
}

void Transpose::process() {
    int off = amount.load();

    auto in = std::static_pointer_cast<CommandPort>(port(Port::Input, Port::Command, 0));
    auto out = std::static_pointer_cast<CommandPort>(port(Port::Output, Port::Command, 0));
    in->pull();
    out->pull();

    out->data = reinterpret_cast<uint8_t*>(audioEngine->tickAlloc(in->dataSize));
    out->dataSize = in->dataSize;
    memcpy(out->data, in->data, in->dataSize); // precopy

    size_t mi = 0;
    while (out->dataSize >= mi+5) {
        int16_t& n = reinterpret_cast<int16_t&>(out->data[mi+2]);
        if (n > -1) {
            int nn = n;
            nn += off;
            if (nn < 0 || nn > 32767) nn = -1;
            n = static_cast<int16_t>(nn);
        }
        mi += 5 + out->data[mi+4]*2;
    }
}

void Transpose::saveData(QCborMap& m) const {
    m[qs("amount")] = QCborValue(amount);
}

void Transpose::loadData(const QCborMap& m) {
    amount = static_cast<int>(m.value("amount").toInteger(0));
}

void Transpose::onGadgetCreated() {
    if (!obj) return;
    obj->showPluginName = false;
    auto l = (new LayoutGadget(obj))->setMetrics(12);

    (new KnobGadget(l))->bind(amount)->setLabel("Transpose")->setRange(-24, 24, 1);
}
