import * as TSU from "@panyam/tsutils";
import { parseCycle } from "./utils";
import { Command, RawBlock, Notation, MetaData as Meta } from "./notation";
export class RawEmbedding extends Command {
    get rawContents() {
        return this.getParamAt(0);
    }
    applyToBlock(container) {
        const raw = new RawBlock(this.rawContents);
        container.addBlockItem(raw);
        container.resetLine();
    }
}
export class MetaData extends Command {
    applyToBlock(container) {
        if (container instanceof Notation) {
            container.addMetaData(this.meta);
        }
    }
    get meta() {
        const out = new Meta(this.key, this.value);
        return out;
    }
    get key() {
        return this.getParamAt(0);
    }
    get value() {
        return this.getParamAt(1);
    }
}
export class ActivateRole extends Command {
    applyToBlock(container) {
        container.setCurrRole(this.roleName);
    }
    get roleName() {
        return this.getParamAt(0);
    }
}
export class AddAtoms extends Command {
    constructor(...atoms) {
        super();
        this.atoms = atoms;
        this.index = 0;
    }
    debugValue() {
        return {
            name: this.name,
            index: this.index,
            atoms: this.atoms.map((a) => a.debugValue()),
        };
    }
    applyToBlock(container) {
        let roleDef = container.currRoleDef;
        if (roleDef == null) {
            roleDef = container.newRoleDef("Sw", true);
        }
        const line = container.currentLine;
        const lpForLine = line.layoutParams;
        if (lpForLine == null) {
            line.layoutParams = container.layoutParams;
        }
        else {
            TSU.assert(lpForLine == container.layoutParams, "Layout parameters have changed so a new line should have been started");
        }
        line.addAtoms(roleDef.name, roleDef.notesOnly, ...this.atoms);
    }
}
export class CreateLine extends Command {
    applyToBlock(container) {
        const line = container.newLine();
        line.offset = this.offset;
        line.marginText = this.marginText;
    }
    get offset() {
        let offset = this.getParam("offset") || TSU.Num.Fraction.ZERO;
        if (typeof offset === "number")
            offset = new TSU.Num.Fraction(offset);
        return offset;
    }
    get marginText() {
        if (this.params.length > 0) {
            if (this.params[0].key == null && typeof this.params[0].value === "string") {
                return this.params[0].value.trim();
            }
        }
        return this.getParam("marginText") || "";
    }
}
export class CreateRole extends Command {
    applyToBlock(container) {
        const name = this.getParamAt(0);
        container.newRoleDef(name, this.notesOnly);
    }
    get notesOnly() {
        const notesOnly = this.getParam("notes");
        return notesOnly == "true" || notesOnly == "yes" || notesOnly == true;
    }
}
export class LayoutParamCommand extends Command {
}
export class ApplyLayout extends Command {
    validateParams() {
        if (this.params.length != 1 || typeof this.params[0].value !== "string") {
            throw new Error("layout command must contain one string argument");
        }
    }
    applyToBlock(container) {
        if (container instanceof Notation) {
            const value = this.params[0].value;
            container.ensureNamedLayoutParams(value);
        }
    }
}
export class SetBreaks extends LayoutParamCommand {
    get pattern() {
        return this.params.map((cmd) => cmd.value);
    }
    validateParams() {
        for (const param of this.params) {
            if (param.key != null) {
                throw new Error("Breaks command cannot have keyword params");
            }
            if (typeof param.value !== "number") {
                throw new Error("Breaks command must be a list of integers");
            }
        }
    }
    applyToBlock(container) {
        container.localBreaks = this.pattern;
        if (container instanceof Notation) {
            container.resetLayoutParams();
        }
    }
}
export class SetCycle extends LayoutParamCommand {
    applyToBlock(container) {
        const value = this.params[0].value;
        const cycle = parseCycle(value);
        container.localCycle = cycle;
        if (container instanceof Notation) {
            container.resetLayoutParams();
        }
    }
}
export class SetBeatDuration extends LayoutParamCommand {
    validateParams() {
        if (this.params.length != 1 || typeof this.params[0].value !== "number") {
            throw new Error("beatDuration command must contain one number");
        }
    }
    get beatDuration() {
        return this.params[0].value;
    }
    applyToBlock(container) {
        container.localAtomsPerBeat = this.beatDuration;
        if (container instanceof Notation) {
            container.resetLayoutParams();
        }
    }
}
export class Section extends Command {
    get sectionName() {
        return this.getParamAt(0) || "";
    }
    validateParams() {
        if (this.params.length < 1 || typeof this.params[0].value !== "string") {
            throw new Error("section command must contain a string name");
        }
    }
    applyToBlock(_container) {
    }
}
export class ScopedGroup extends Command {
    get groupName() {
        return this.getParamAt(0) || "";
    }
    applyToBlock(_container) {
    }
}
export class Repeat extends Command {
    get count() {
        const count = this.getParamAt(0);
        if (typeof count === "number") {
            return count;
        }
        return 0;
    }
    validateParams() {
        if (this.params.length > 0) {
            const count = this.params[0].value;
            if (typeof count !== "number" || count < 0) {
                throw new Error("repeat command count must be a non-negative number");
            }
        }
    }
    applyToBlock(_container) {
    }
}
//# sourceMappingURL=commands.js.map