"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CffFdSelect = void 0;
const bin_util_1 = require("@ot-builder/bin-util");
const errors_1 = require("@ot-builder/errors");
const primitive_1 = require("@ot-builder/primitive");
const FdSelectFormat0 = {
    ...(0, bin_util_1.Read)((view, sink) => {
        const nGlyphs = sink.getGlyphCount();
        for (let gid = 0; gid < nGlyphs; gid++) {
            const fd = view.uint8();
            sink.put(gid, fd);
        }
    })
};
class FdSelectFormat34ReadState {
    constructor(sink) {
        this.sink = sink;
        this.started = false;
        this.lastStartGid = 0;
        this.lastFdId = 0;
    }
    update(gid, fdId = this.lastFdId) {
        if (this.started) {
            for (let processGid = this.lastStartGid; processGid < gid; processGid++) {
                this.sink.put(processGid, this.lastFdId);
            }
        }
        this.started = true;
        this.lastStartGid = gid;
        this.lastFdId = fdId;
        return true;
    }
}
class FdSelectFormat34WriteState {
    constructor(frag, wGid, wFdId) {
        this.frag = frag;
        this.wGid = wGid;
        this.wFdId = wFdId;
        this.gid = 0;
        this.lastFdId = -1;
        this.ranges = [];
    }
    update(fdId) {
        if (this.gid === 0 || fdId !== this.lastFdId) {
            this.ranges.push([this.gid, fdId]);
        }
        this.gid += 1;
        this.lastFdId = fdId;
    }
    flush() {
        this.frag.push(this.wGid, this.ranges.length);
        for (const [gid, fdId] of this.ranges) {
            this.frag.push(this.wGid, gid);
            this.frag.push(this.wFdId, fdId);
        }
        this.frag.push(this.wGid, this.gid);
    }
}
const FdSelectFormat34 = {
    ...(0, bin_util_1.Read)((view, rGid, rFdId, sink) => {
        const nGlyphs = sink.getGlyphCount();
        const nRanges = view.next(rGid);
        const st = new FdSelectFormat34ReadState(sink);
        for (let ixRange = 0; ixRange < nRanges; ixRange++) {
            const gid = view.next(rGid);
            const fdId = view.next(rFdId);
            st.update(gid, fdId);
        }
        const sentinel = view.next(rGid);
        if (sentinel !== nGlyphs)
            throw errors_1.Errors.Cff.FdSelectSentinelMismatch(sentinel, nGlyphs);
        st.update(sentinel);
    }),
    ...(0, bin_util_1.Write)((frag, fdSelectAssignments, fdSelectFormat, wGid, wFdId) => {
        frag.uint8(fdSelectFormat);
        const st = new FdSelectFormat34WriteState(frag, wGid, wFdId);
        for (const fdId of fdSelectAssignments)
            st.update(fdId);
        st.flush();
    })
};
exports.CffFdSelect = {
    ...(0, bin_util_1.Read)((view, ctx, sink) => {
        const format = view.uint8();
        switch (format) {
            case 0:
                return view.next(FdSelectFormat0, sink);
            case 3:
                return view.next(FdSelectFormat34, primitive_1.UInt16, primitive_1.UInt8, sink);
            case 4:
                if (ctx.version <= 1)
                    throw errors_1.Errors.Cff.FdSelect4NotSupported();
                return view.next(FdSelectFormat34, primitive_1.UInt32, primitive_1.UInt16, sink);
            default:
                throw errors_1.Errors.FormatNotSupported("CFF::FdSelect", format);
        }
    }),
    ...(0, bin_util_1.Write)((frag, fdSelectValues, ctx) => {
        errors_1.Assert.NoGap("FDSelect assignments", fdSelectValues);
        let maxVal = 0;
        for (const v of fdSelectValues)
            if (v > maxVal)
                maxVal = v;
        const needsFormat4 = maxVal > 0xff || fdSelectValues.length > 0xffff;
        if (needsFormat4) {
            if (ctx.version <= 1)
                throw errors_1.Errors.Cff.FdSelect4NotSupported();
            return frag.push(FdSelectFormat34, fdSelectValues, 4, primitive_1.UInt32, primitive_1.UInt16);
        }
        else {
            return frag.push(FdSelectFormat34, fdSelectValues, 3, primitive_1.UInt16, primitive_1.UInt8);
        }
    })
};
//# sourceMappingURL=io.js.map