#include "pattern.h"
using Xybrid::Data::Pattern;
using Row = Pattern::Row;
using Channel = Pattern::Channel;

#include "data/project.h"

Row Pattern::fallbackRow(-1337, -1337);
Channel Pattern::fallbackChannel(0);
std::array<unsigned char, 2> Row::fallbackParam {'.', 0};

Row::Row(const Row& o) noexcept {
    *this = o;
}

Row& Row::operator=(const Row& o) noexcept {
    port = o.port;
    note = o.note;
    // copy-constructor the underlying vector
    if (o.params) params.reset(new std::vector<std::array<unsigned char, 2>>(*o.params));
    else params.reset();
    return *this;
}

Channel::Channel(int numRows, QString name) : Channel() {
    this->name = name;
    rows.resize(static_cast<size_t>(numRows));
}

Pattern::Pattern() {

}

Pattern::Pattern(int rows, int channels) : Pattern() {
    for (int i = 0; i < channels; i++) this->channels.emplace_back();
    setLength(rows);
}

void Pattern::setLength(int r) {
    if (r < 1) r = 1;
    rows = r;
    for (auto & c : channels) {
        c.rows.resize(static_cast<size_t>(rows));
    }
}

void Pattern::addChannel(int at) {
    if (at < 0 || at > static_cast<int>(channels.size())) at = static_cast<int>(channels.size());
    channels.insert(channels.begin() + at, rows);
}

void Pattern::deleteChannel(int at) {
    if (at < 0 || at >= static_cast<int>(channels.size())) at = static_cast<int>(channels.size()) - 1;
    channels.erase(channels.begin() + at);
}

bool Pattern::valid() const {
    return (project && index < project->patterns.size() && this == project->patterns[index].get());
}
bool Pattern::validFor(const Project* p) const {
    return valid() && project == p;
}
bool Pattern::validFor(const std::shared_ptr<Project>& p) const {
    return valid() && project == p.get();
}

Channel& Pattern::channel(int c) {
    auto cc = static_cast<size_t>(c);
    if (cc >= channels.size()) return fallbackChannel;
    return channels[cc];
}

Row& Pattern::rowAt(int c, int r) {
    auto nc = this->channels.size();
    if (nc == 0 || rows == 0) return fallbackRow;
    c = c % static_cast<int>(nc);
    r = r % rows;
    return channels[static_cast<size_t>(c)].rows[static_cast<size_t>(r)];
}
