"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CompositeGlyph = exports.SimpleGlyph = exports.SpaceGlyph = exports.GlyphClassifier = void 0;
const errors_1 = require("@ot-builder/errors");
const ot_glyphs_1 = require("@ot-builder/ot-glyphs");
class GlyphClassifier {
    constructor(gOrd) {
        this.gOrd = gOrd;
        this.cache = new Map();
    }
    classifyImpl(g) {
        const gid = this.gOrd.reverse(g);
        const algGeom = new GeometryClassifier();
        const algHint = new HintClassifier();
        if (g.geometry)
            algGeom.process(g.geometry);
        if (g.hints)
            algHint.process(g.hints);
        if (!algGeom.hasContours && !algGeom.hasReference) {
            return new SpaceGlyph(gid, g.horizontal, g.vertical);
        }
        if (algGeom.hasReference && algGeom.allReference) {
            return new CompositeGlyph(this, gid, g.horizontal, g.vertical, algGeom.collectedReferences, algHint.collectedInstructions);
        }
        if (algGeom.hasContours && algGeom.allContours) {
            return new SimpleGlyph(gid, g.horizontal, g.vertical, algGeom.collectedContourSets, algHint.collectedInstructions);
        }
        throw errors_1.Errors.Ttf.MixedGlyph(gid);
    }
    classify(g) {
        const cached = this.cache.get(g);
        if (cached)
            return cached;
        const sg = this.classifyImpl(g);
        this.cache.set(g, sg);
        return sg;
    }
}
exports.GlyphClassifier = GlyphClassifier;
class GeometryClassifier {
    constructor() {
        this.hasReference = false;
        this.allReference = true;
        this.hasContours = false;
        this.allContours = true;
        this.collectedContourSets = [];
        this.collectedReferences = [];
    }
    process(g) {
        switch (g.type) {
            case ot_glyphs_1.OtGlyph.GeometryType.ContourSet:
                return this.contourSet(g);
            case ot_glyphs_1.OtGlyph.GeometryType.TtReference:
                return this.ttReference(g);
            case ot_glyphs_1.OtGlyph.GeometryType.GeometryList:
                return this.geometryList(g);
        }
    }
    contourSet(csProps) {
        this.hasContours = true;
        this.allReference = false;
        this.collectedContourSets.push(new ot_glyphs_1.OtGlyph.ContourSet(csProps.contours));
    }
    geometryList(glProps) {
        for (const entry of glProps.items)
            this.process(entry);
    }
    ttReference(refProps) {
        this.hasReference = true;
        this.allContours = false;
        const ref = new ot_glyphs_1.OtGlyph.TtReference(refProps.to, refProps.transform);
        ref.roundXyToGrid = refProps.roundXyToGrid;
        ref.useMyMetrics = refProps.useMyMetrics;
        ref.pointAttachment = refProps.pointAttachment;
        this.collectedReferences.push(ref);
    }
}
class HintClassifier {
    constructor() {
        this.collectedInstructions = Buffer.alloc(0);
    }
    process(h) {
        switch (h.type) {
            case ot_glyphs_1.OtGlyph.HintType.TtInstruction:
                this.collectedInstructions = h.instructions;
        }
    }
}
class SpaceGlyph {
    constructor(gid, hm, vm) {
        this.gid = gid;
        this.hm = hm;
        this.vm = vm;
    }
    getStatData() {
        return {
            eigenContours: 0,
            eigenPoints: 0,
            extent: { xMin: 0, xMax: 0, yMin: 0, yMax: 0 },
            depth: 0,
            eigenReferences: 0,
            totalContours: 0,
            totalPoints: 0
        };
    }
    stat(sink) {
        sink.simpleGlyphStat(this.getStatData());
        sink.instructionsStat(0);
        sink.setMetric(this.gid, this.hm, this.vm, { xMin: 0, xMax: 0, yMin: 0, yMax: 0 });
    }
}
exports.SpaceGlyph = SpaceGlyph;
class SimpleGlyph extends SpaceGlyph {
    constructor(gid, hm, vm, outlines, instructions) {
        super(gid, hm, vm);
        this.outlines = outlines;
        this.instructions = instructions;
        const bound = ot_glyphs_1.OtGeometryUtil.apply(ot_glyphs_1.OtGeometryUtil.GetBound, ...this.outlines);
        const pointCount = ot_glyphs_1.OtGeometryUtil.apply(ot_glyphs_1.OtGeometryUtil.CountPoint, ...this.outlines);
        let contourCount = 0;
        for (const cs of outlines)
            contourCount += cs.contours.length;
        this.st = {
            eigenContours: contourCount,
            eigenPoints: pointCount,
            extent: bound,
            depth: 0,
            eigenReferences: 0,
            totalContours: contourCount,
            totalPoints: pointCount
        };
    }
    getStatData() {
        return this.st;
    }
    stat(sink) {
        sink.simpleGlyphStat(this.getStatData());
        sink.instructionsStat(this.instructions.byteLength);
        sink.setMetric(this.gid, this.hm, this.vm, this.st.extent);
    }
}
exports.SimpleGlyph = SimpleGlyph;
class CompositeGlyph extends SpaceGlyph {
    constructor(classifier, gid, hm, vm, references, instructions) {
        super(gid, hm, vm);
        this.references = references;
        this.instructions = instructions;
        let totalContours = 0;
        let totalPoints = 0;
        let depth = 1;
        for (const ref of references) {
            const stat = classifier.classify(ref.to).getStatData();
            if (stat.depth + 1 > depth)
                depth = stat.depth + 1;
            totalContours += stat.totalContours;
            totalPoints += stat.totalPoints;
        }
        const bound = ot_glyphs_1.OtGeometryUtil.apply(ot_glyphs_1.OtGeometryUtil.GetBound, ...references);
        this.st = {
            eigenContours: 0,
            eigenPoints: 0,
            extent: bound,
            depth,
            eigenReferences: references.length,
            totalContours,
            totalPoints
        };
    }
    getStatData() {
        return this.st;
    }
    stat(sink) {
        sink.complexGlyphStat(this.getStatData());
        sink.instructionsStat(this.instructions.byteLength);
        sink.setMetric(this.gid, this.hm, this.vm, this.st.extent);
    }
}
exports.CompositeGlyph = CompositeGlyph;
//# sourceMappingURL=classifier.js.map