import * as TSU from "@panyam/tsutils";
import { AtomType, Note, Syllable } from "../core";
import { LeafAtomView as LeafAtomViewBase, GroupView as GroupViewBase, ElementShape, } from "../shapes";
import { OctaveIndicator, Kampitham, Nokku, Spuritham, Prathyagatham, Orikkai, Odukkal, Raavi, Kandippu, Vaali, Jaaru, } from "./embelishments";
import { GamakaType } from "./gamakas";
export class GroupView extends GroupViewBase {
    createAtomView(atom) {
        return createAtomView(this.groupElement, atom, this.defaultToNotes, 0.7);
    }
}
export class LeafAtomView extends LeafAtomViewBase {
    constructor() {
        super(...arguments);
        this.leftSlot = [];
        this.topSlot = [];
        this.rightSlot = [];
        this.bottomSlot = [];
    }
    refreshBBox() {
        return TSU.DOM.svgBBox(this.rootGroup.element);
    }
    refreshMinSize() {
        const out = Object.assign({}, this.rootText.minSize);
        const totalWidth = this.leftSlot.reduce((a, b) => a + b.minSize.width, 0) +
            this.rightSlot.reduce((a, b) => a + b.minSize.width, 0) +
            this.leftSlot.length +
            this.rightSlot.length;
        const totalHeight = this.topSlot.reduce((a, b) => a + b.minSize.height, 0) +
            this.bottomSlot.reduce((a, b) => a + b.minSize.height, 0);
        out.width += totalWidth;
        out.height += totalHeight;
        return out;
    }
    get glyphOffset() {
        return (this.leftSlot.reduce((a, b) => a + b.minSize.width, 0) + this.leftSlot.length);
    }
    updateBounds(x, y, w, h) {
        return [x, y, NaN, NaN];
    }
    layoutElements() {
        const textSize = this.rootText.minSize;
        let currX = 0;
        let currY = this.hasY ? this.y : 0;
        for (const emb of this.leftSlot) {
            emb.x = currX;
            emb.refreshLayout();
            currX += emb.minSize.width + 1;
        }
        const textX = currX;
        this.rootText.x = currX;
        this.rootText.refreshLayout();
        currX += this.rootText.minSize.width;
        for (const emb of this.rightSlot) {
            emb.x = currX;
            emb.refreshLayout();
            currX += emb.minSize.width + 1;
        }
        const gminSize = this.glyph.minSize;
        const glyphX = textX + this.glyph.x;
        const glyphY = this.glyph.y;
        currY = glyphY - this.glyph.minSize.height + 5;
        for (const emb of this.topSlot) {
            const bb = emb.minSize;
            emb.setBounds(glyphX + (gminSize.width - bb.width) / 2, currY - bb.height, null, null, true);
            currY = emb.y;
        }
        currY = glyphY + 7;
        for (const emb of this.bottomSlot) {
            const bb = emb.minSize;
            emb.setBounds(glyphX + (gminSize.width - bb.width) / 2, currY, null, null, true);
            currY = emb.y + bb.height;
        }
        this.invalidateBounds();
    }
    refreshLayout() {
        this.layoutElements();
        this.rootGroup.element.setAttribute("transform", "translate(" + this.x + "," + this.y + ")");
    }
    addEmbelishment(slot, emb) {
        slot.push(emb);
    }
    orderEmbelishments() {
        const atom = this.leafAtom;
        if (atom.TYPE != AtomType.SYLLABLE && atom.TYPE != AtomType.NOTE) {
            return;
        }
        const lit = atom;
        if (lit.embelishments.length == 0)
            return;
        for (const emb of lit.embelishments) {
            switch (emb.type) {
                case GamakaType.Kampitham:
                    this.addEmbelishment(this.topSlot, new Kampitham(this));
                    break;
                case GamakaType.Nokku:
                    this.addEmbelishment(this.topSlot, new Nokku(this));
                    break;
                case GamakaType.Spuritham:
                    this.addEmbelishment(this.topSlot, new Spuritham(this));
                    break;
                case GamakaType.Prathyagatham:
                    this.addEmbelishment(this.topSlot, new Prathyagatham(this));
                    break;
                case GamakaType.Orikkai:
                    this.addEmbelishment(this.topSlot, new Orikkai(this));
                    break;
                case GamakaType.Odukkal:
                    this.addEmbelishment(this.topSlot, new Odukkal(this));
                    break;
                case GamakaType.Aahaatam_Raavi:
                    this.addEmbelishment(this.topSlot, new Raavi(this));
                    break;
                case GamakaType.Aahaatam_Kandippu:
                    this.addEmbelishment(this.topSlot, new Kandippu(this));
                    break;
                case GamakaType.Vaali:
                    this.addEmbelishment(this.topSlot, new Vaali(this));
                    break;
                case GamakaType.Jaaru_Eetra:
                case GamakaType.Jaaru_Irakka:
                    this.addEmbelishment(this.leftSlot, new Jaaru(emb, this));
                    break;
            }
        }
    }
    embRoot() {
        return this.rootGroup.element;
    }
    needsRootElement() {
        return true;
    }
    createElements(parent) {
        this.createGlyphRoot(parent);
        this.createGlyphElement();
        this.orderEmbelishments();
        this.createPostSpacingElement();
        this.invalidateBounds();
    }
    createGlyphRoot(parent) {
        this.rootGroup = new ElementShape(TSU.DOM.createSVGNode("g", {
            doc: document,
            parent: parent,
            attrs: {
                atomid: this.leafAtom.uuid,
                class: "atomViewRootGroup",
                id: "atomViewRootGroup" + this.leafAtom.uuid,
            },
        }));
        this.rootText = new ElementShape(TSU.DOM.createSVGNode("text", {
            doc: document,
            parent: this.rootGroup.element,
            attrs: {
                atomid: this.leafAtom.uuid,
                class: "atomViewTextRoot",
                id: "atomViewTextRoot" + this.leafAtom.uuid,
            },
        }));
    }
    createGlyphElement() {
        const atom = this.leafAtom;
        this.glyph = new ElementShape(TSU.DOM.createSVGNode("tspan", {
            doc: document,
            parent: this.rootText.element,
            attrs: {
                atomid: atom.uuid,
                id: "atomGlyph" + atom.uuid,
            },
            text: this.glyphLabel,
        }));
    }
    createPostSpacingElement() {
        if (this.leafAtom.beforeRest) {
            this.postSpacingSpan = TSU.DOM.createSVGNode("tspan", {
                doc: document,
                parent: this.rootText.element,
                attrs: {
                    atomid: this.leafAtom.uuid,
                    id: "postSpacing" + this.leafAtom.uuid,
                },
                text: this.leafAtom.beforeRest ? " - " : "  ",
            });
        }
    }
}
class SpaceView extends LeafAtomView {
    get glyphLabel() {
        if (this.space.isSilent)
            return " ";
        if (this.space.duration.isOne)
            return ",";
        if (this.space.duration.cmpNum(2) == 0)
            return ";";
        return "_";
    }
    get space() {
        return this.leafAtom;
    }
}
class NoteView extends LeafAtomView {
    get glyphLabel() {
        return this.note.value;
    }
    needsRootElement() {
        return true;
    }
    createGlyphElement() {
        super.createGlyphElement();
        if (this.note.shift == true || this.note.shift != 0) {
            this.shiftElement = TSU.DOM.createSVGNode("tspan", {
                doc: document,
                parent: this.rootText.element,
                attrs: {
                    atomid: this.note.uuid,
                    class: "noteShiftTSpan",
                    id: "noteShift" + this.note.uuid,
                    "baseline-shift": "sub",
                },
                text: (this.note.shift == true ? "*" : this.note.shift) + " ",
            });
        }
    }
    moveGlyphToRoot() {
        if (this.shiftElement) {
            this.rootGroup.element.appendChild(this.shiftElement);
        }
    }
    orderEmbelishments() {
        const note = this.note;
        if (note.octave > 0) {
            this.topSlot.push(new OctaveIndicator(this, note));
        }
        else if (this.note.octave < 0) {
            this.bottomSlot.push(new OctaveIndicator(this, note));
        }
        super.orderEmbelishments();
    }
    get note() {
        return this.leafAtom;
    }
}
class SyllableView extends LeafAtomView {
    get glyphLabel() {
        return this.syllable.value;
    }
    get syllable() {
        return this.leafAtom;
    }
}
export function createAtomView(parent, atom, litDefaultsToNote = false, groupViewScale = 1.0) {
    let out;
    switch (atom.TYPE) {
        case AtomType.SPACE:
            out = new SpaceView(atom);
            break;
        case AtomType.SYLLABLE:
            out = new SyllableView(atom);
            break;
        case AtomType.NOTE:
            out = new NoteView(atom);
            break;
        case AtomType.LITERAL:
            if (litDefaultsToNote) {
                const lit = Note.fromLit(atom);
                out = new NoteView(lit);
            }
            else {
                const lit = Syllable.fromLit(atom);
                out = new SyllableView(lit);
            }
            break;
        case AtomType.GROUP:
            out = new GroupView(atom);
            out.defaultToNotes = litDefaultsToNote;
            out.scaleFactor = groupViewScale;
            break;
        default:
            throw new Error("Invalid atom type: " + atom.TYPE);
    }
    out.createElements(parent);
    return out;
}
//# sourceMappingURL=atomviews.js.map