import * as TSU from "@panyam/tsutils";
import { Cycle, CycleCursor } from "./cycle";
const ZERO = TSU.Num.Fraction.ZERO;
export class LayoutParams {
    constructor(config) {
        this.uuid = LayoutParams.counter++;
        config = config || {};
        this.beatDuration = config.beatDuration || 1;
        if ("cycle" in config)
            this.cycle = config.cycle;
        if (!this.cycle || this.cycle.duration.isZero) {
            this.cycle = Cycle.DEFAULT;
        }
        this._rowStartOffsets = [];
        this._rowEndOffsets = [];
        this._rowDurations = [];
        this._totalLayoutDuration = ZERO;
        this._totalBeats = 0;
        this._beatLayouts = [];
        this.lineBreaks = config.lineBreaks || config.layout || [];
    }
    equals(another) {
        return (this.beatDuration == another.beatDuration &&
            this.cycle.equals(another.cycle) &&
            this.lineBreaksEqual(another._lineBreaks));
    }
    lineBreaksEqual(another) {
        return this._lineBreaks.length == another.length && this._lineBreaks.every((x, i) => x == another[i]);
    }
    debugValue() {
        var _a;
        return {
            cycle: (_a = this.cycle) === null || _a === void 0 ? void 0 : _a.debugValue(),
            beatDuration: this.beatDuration,
            lineBreaks: this._lineBreaks,
        };
    }
    getBeatLocation(beat) {
        const modIndex = beat.index % this.totalBeats;
        let total = 0;
        for (let i = 0; i < this._lineBreaks.length; i++) {
            if (modIndex < total + this._lineBreaks[i]) {
                let offset = ZERO;
                if (modIndex > total) {
                    const cursor = new CycleCursor(this.cycle, beat.barIndex, beat.beatIndex, beat.instance);
                    let [, duration] = cursor.prev;
                    for (let i = total; i < modIndex; i++) {
                        [, duration] = cursor.prev;
                        offset = offset.plus(duration.timesNum(this.beatDuration));
                    }
                }
                return [i, modIndex - total, offset];
            }
            total += this._lineBreaks[i];
        }
        throw new Error("Invalid beat index: " + beat.index);
        return [-1, -1, ZERO];
    }
    get lineBreaks() {
        if (!this._lineBreaks || this._lineBreaks.length == 0) {
            this.lineBreaks = [this.cycle.beatCount];
        }
        return this._lineBreaks;
    }
    set lineBreaks(val) {
        this._lineBreaks = val;
        this.refreshLayout();
    }
    get beatLayouts() {
        if (!this._beatLayouts || this._beatLayouts.length < this.lineBreaks.length) {
            this.refreshLayout();
        }
        return this._beatLayouts;
    }
    get totalBeats() {
        this.beatLayouts;
        return this._totalBeats;
    }
    get totalLayoutDuration() {
        this.beatLayouts;
        return this._totalLayoutDuration;
    }
    refreshLayout() {
        const cycleIter = this.cycle.iterateBeats();
        const akb = this.beatDuration;
        this._beatLayouts = this.lineBreaks.map((numBeats, index) => {
            const beats = [];
            for (let i = 0; i < numBeats; i++) {
                const nextCP = cycleIter.next().value;
                nextCP[1] = nextCP[1].timesNum(akb);
                beats.push(nextCP);
            }
            return beats;
        });
        this._totalBeats = this.lineBreaks.reduce((a, b) => a + b, 0);
        this._rowDurations = this._beatLayouts.map((beats) => beats.reduce((x, y) => x.plus(y[1]), ZERO));
        this._rowDurations.forEach((rd, index) => {
            this._rowStartOffsets[index] = index == 0 ? ZERO : this._rowStartOffsets[index - 1].plus(rd);
        });
        this._rowEndOffsets = this._rowDurations.map((rd, index) => {
            return this._rowStartOffsets[index].plus(rd);
        });
        this._totalLayoutDuration = this._rowDurations.reduce((x, y) => x.plus(y), ZERO);
    }
}
LayoutParams.counter = 0;
//# sourceMappingURL=layouts.js.map