import { Entity } from "./entity";
import { Cycle } from "./cycle";
import { Line } from "./core";
import { LayoutParams } from "./layouts";
import { RoleDef, RawBlock, Block, SectionBlock, RepeatBlock, CycleBlock, BeatDurationBlock, BreaksBlock, RoleBlock, GroupBlock, isBlock, isLine, isRawBlock, findContainingBlock, } from "./block";
export { RoleDef, RawBlock, Block, SectionBlock, RepeatBlock, CycleBlock, BeatDurationBlock, BreaksBlock, RoleBlock, GroupBlock, isBlock, isLine, isRawBlock, findContainingBlock, };
export class Command extends Entity {
    constructor(params = []) {
        super();
        this.autoGenerated = false;
        this.prevSibling = null;
        this.nextSibling = null;
        this.params = params;
        this.index = 0;
        this.validateParams();
    }
    validateParams() {
    }
    get name() {
        return this.constructor.name;
    }
    debugValue() {
        return { name: this.name, index: this.index, params: this.params };
    }
    getParam(name) {
        for (const param of this.params) {
            if (param.key == name)
                return param.value;
        }
        return null;
    }
    getParamAt(index) {
        return index < this.params.length ? this.params[index].value : null;
    }
    applyToNotation(notation) {
        this.applyToBlock(notation);
    }
}
export class MetaData {
    constructor(key, value, params) {
        this.key = key;
        this.value = value;
        this.params = params;
        params = params || {};
    }
}
export class Notation extends Block {
    constructor() {
        super("notation", null);
        this.TYPE = "Notation";
        this.metadata = new Map();
        this.onMissingRole = (name) => this.newRoleDef(name, name == "sw");
        this._unnamedLayoutParams = [];
        this._namedLayoutParams = new Map();
        this._layoutParams = null;
        this._currRoleDef = null;
        this._currentLine = null;
        this.localCycle = Cycle.DEFAULT;
        this.localAtomsPerBeat = 1;
        this.localBreaks = [];
    }
    get blocks() {
        return this.blockItems;
    }
    get currentAPB() {
        var _a;
        return (_a = this.localAtomsPerBeat) !== null && _a !== void 0 ? _a : 1;
    }
    set currentAPB(value) {
        this.localAtomsPerBeat = value;
    }
    get currentCycle() {
        var _a;
        return (_a = this.localCycle) !== null && _a !== void 0 ? _a : Cycle.DEFAULT;
    }
    set currentCycle(value) {
        this.localCycle = value;
    }
    get currentBreaks() {
        var _a;
        return (_a = this.localBreaks) !== null && _a !== void 0 ? _a : [];
    }
    set currentBreaks(value) {
        this.localBreaks = value;
    }
    get roles() {
        return Array.from(this.localRoles.values());
    }
    get unnamedLayoutParams() {
        return this._unnamedLayoutParams;
    }
    get namedLayoutParams() {
        return this._namedLayoutParams;
    }
    get layoutParams() {
        if (this._layoutParams == null) {
            this._layoutParams = this.findUnnamedLayoutParams();
            if (this._layoutParams == null) {
                this._layoutParams = this.snapshotLayoutParams();
                this._unnamedLayoutParams.push(this._layoutParams);
            }
        }
        return this._layoutParams;
    }
    resetLayoutParams() {
        this._layoutParams = null;
        this.resetLine();
    }
    ensureNamedLayoutParams(name) {
        let lp = this._namedLayoutParams.get(name) || null;
        if (lp == null || this._layoutParams != lp) {
            if (lp == null) {
                lp = this.snapshotLayoutParams();
                this._namedLayoutParams.set(name, lp);
            }
            else {
                this.currentCycle = lp.cycle;
                this.currentAPB = lp.beatDuration;
                this.currentBreaks = lp.lineBreaks;
            }
            this._layoutParams = lp;
            this.resetLine();
        }
        return this._layoutParams;
    }
    snapshotLayoutParams() {
        return new LayoutParams({
            cycle: this.currentCycle,
            beatDuration: this.currentAPB,
            layout: this.currentBreaks,
        });
    }
    findUnnamedLayoutParams() {
        return (this._unnamedLayoutParams.find((lp) => {
            return (lp.beatDuration == this.currentAPB &&
                this.currentCycle.equals(lp.cycle) &&
                lp.lineBreaksEqual(this.currentBreaks));
        }) || null);
    }
    setCurrRole(name) {
        name = name.trim().toLowerCase();
        if (name.trim() == "") {
            throw new Error("Role name cannot be empty");
        }
        const roleDef = this.getRole(name) || (this.onMissingRole ? this.onMissingRole(name) || null : null);
        if (roleDef == null) {
            throw new Error("Role not found: " + name);
        }
        this._currRoleDef = roleDef;
    }
    getRoleDef(name) {
        var _a;
        name = name.trim().toLowerCase();
        if (name === "") {
            const roles = Array.from(this.localRoles.values());
            return roles[roles.length - 1] || null;
        }
        return (_a = this.localRoles.get(name)) !== null && _a !== void 0 ? _a : null;
    }
    newRoleDef(name, notesOnly = false) {
        name = name.trim().toLowerCase();
        if (name === "") {
            throw new Error("Role name cannot be empty");
        }
        if (this.localRoles.has(name)) {
            throw new Error("Role already exists: " + name);
        }
        const rd = new RoleDef();
        rd.name = name;
        rd.notesOnly = notesOnly;
        rd.index = this.localRoles.size;
        this.localRoles.set(name, rd);
        return rd;
    }
    addLine(line) {
        this.addBlockItem(line);
    }
    removeLine(line) {
        return this.removeBlockItem(line);
    }
    addRawBlock(raw) {
        this.addBlockItem(raw);
        this.resetLine();
    }
    addMetaData(meta, addBlock = true) {
        if (addBlock && !this.metadata.has(meta.key)) {
            const raw = new RawBlock(meta.key, "metadata");
            this.addRawBlock(raw);
        }
        this.metadata.set(meta.key, meta);
    }
    resetLine() {
        this._currentLine = null;
    }
    debugValue() {
        var _a;
        return {
            blocks: this.blocks.map((b) => b.debugValue()),
            currentAPB: this.currentAPB,
            currentBreaks: this.currentBreaks,
            currentCycle: (_a = this.currentCycle) === null || _a === void 0 ? void 0 : _a.uuid,
            roles: this.roles,
        };
    }
    get currRoleDef() {
        if (this._currRoleDef == null) {
            const roles = Array.from(this.localRoles.values());
            if (roles.length === 0) {
                return null;
            }
            else {
                this._currRoleDef = roles[roles.length - 1];
            }
        }
        return this._currRoleDef;
    }
    get currentLine() {
        if (this._currentLine == null) {
            return this.newLine();
        }
        return this._currentLine;
    }
    newLine() {
        if (this._currentLine && this._currentLine.isEmpty) {
            this.removeLine(this._currentLine);
        }
        this._currentLine = new Line();
        this.addLine(this._currentLine);
        return this._currentLine;
    }
}
//# sourceMappingURL=notation.js.map