"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.rectifyGlyphOrder = rectifyGlyphOrder;
const errors_1 = require("@ot-builder/errors");
const ot_glyphs_1 = require("@ot-builder/ot-glyphs");
const variance_1 = require("@ot-builder/variance");
function rectifyGlyphOrder(gOrd) {
    const gs = new Set();
    for (const glyph of gOrd) {
        rectifyGlyph(glyph, gs);
    }
}
function rectifyGlyph(glyph, gs) {
    if (gs.has(glyph))
        return;
    if (glyph.geometry) {
        const alg = new AttachmentPointToCoordAlg(gs);
        glyph.geometry = alg.process(glyph.geometry)({ points: [] });
    }
    gs.add(glyph);
}
class AttachmentPointToCoordAlg {
    constructor(gs) {
        this.gs = gs;
    }
    process(geom) {
        switch (geom.type) {
            case ot_glyphs_1.OtGlyph.GeometryType.ContourSet:
                return this.contourSet(geom);
            case ot_glyphs_1.OtGlyph.GeometryType.TtReference:
                return this.ttReference(geom);
            case ot_glyphs_1.OtGlyph.GeometryType.GeometryList:
                return this.geometryList(geom.items.map(item => this.process(item)));
        }
    }
    contourSet(cs) {
        return (st) => {
            const g = new ot_glyphs_1.OtGlyph.ContourSet(cs.contours);
            for (const c of g.contours)
                for (const z of c)
                    st.points.push(z);
            return g;
        };
    }
    geometryList(processes) {
        return (st) => {
            const children = [];
            for (const proc of processes) {
                children.push(proc(st));
            }
            return new ot_glyphs_1.OtGlyph.GeometryList(children);
        };
    }
    ttReference(ref) {
        return (st) => {
            rectifyGlyph(ref.to, this.gs);
            let tfm = ref.transform;
            const innerPoints = ot_glyphs_1.OtGeometryUtil.apply(ot_glyphs_1.OtGeometryUtil.ListPoint, ref.to.geometry);
            if (ref.pointAttachment) {
                const zOut = st.points[ref.pointAttachment.outer.pointIndex];
                const zIn = innerPoints[ref.pointAttachment.inner.pointIndex];
                if (zOut && zIn) {
                    const zInTransformed = ot_glyphs_1.OtGlyph.PointOps.applyTransform(zIn, {
                        ...ref.transform,
                        scaledOffset: false,
                        dx: 0,
                        dy: 0
                    });
                    tfm = {
                        ...ref.transform,
                        scaledOffset: false,
                        dx: variance_1.OtVar.Ops.minus(zOut.x, zInTransformed.x),
                        dy: variance_1.OtVar.Ops.minus(zOut.y, zInTransformed.y)
                    };
                }
                else {
                    throw errors_1.Errors.Ttf.InvalidPointAttachment(ref.pointAttachment.outer.pointIndex, ref.pointAttachment.inner.pointIndex);
                }
            }
            const geom = new ot_glyphs_1.OtGlyph.TtReference(ref.to, tfm);
            geom.roundXyToGrid = ref.roundXyToGrid;
            geom.useMyMetrics = ref.useMyMetrics;
            geom.pointAttachment = ref.pointAttachment;
            for (const z of innerPoints) {
                st.points.push(ot_glyphs_1.OtGlyph.PointOps.applyTransform(z, tfm));
            }
            return geom;
        };
    }
}
//# sourceMappingURL=rectify.js.map