"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.UnicodeFull = void 0;
const bin_util_1 = require("@ot-builder/bin-util");
const errors_1 = require("@ot-builder/errors");
const ot_encoding_1 = require("@ot-builder/ot-encoding");
const primitive_1 = require("@ot-builder/primitive");
const general_1 = require("./general");
const unicode_encoding_collector_1 = require("./unicode-encoding-collector");
class UnicodeFull {
    constructor() {
        this.mapping = new ot_encoding_1.Cmap.EncodingMap();
        this.key = general_1.SubtableHandlerKey.UnicodeFull;
    }
    acceptEncoding(platform, encoding, format) {
        return platform === 3 && encoding === 10 && format === 12;
    }
    read(view, gOrd) {
        const format = view.uint16();
        errors_1.Assert.FormatSupported("subtable format", format, 12);
        const reserved = view.uint16();
        const length = view.uint32();
        const language = view.uint32();
        const numGroups = view.uint32();
        for (const [v] of view.repeat(numGroups)) {
            const startCharCode = v.uint32();
            const endCharCode = v.uint32();
            const startGlyphID = v.uint32();
            for (let code = startCharCode; code <= endCharCode; code++) {
                this.mapping.set(code, gOrd.at(code - startCharCode + startGlyphID));
            }
        }
    }
    apply(cmap) {
        for (const [c, g] of this.mapping.entries()) {
            cmap.unicode.set(c, g);
        }
    }
    writeOpt(cmap, gOrd, options) {
        const col = new unicode_encoding_collector_1.UnicodeEncodingCollector(cmap.unicode, gOrd, primitive_1.UInt32.max).collect();
        return new CmapFormat12Writer().getFrag(col, options);
    }
    createAssignments(frag) {
        if (!frag.size)
            return [];
        return [
            { platform: 3, encoding: 10, frag },
            { platform: 0, encoding: 4, frag }
        ];
    }
}
exports.UnicodeFull = UnicodeFull;
class CmapFormat12Seg {
    constructor(unicode, gid) {
        this.unicodeStart = this.unicodeEnd = unicode;
        this.gidStart = this.gidEnd = gid;
    }
    tryAccept(unicode, gid) {
        if (unicode !== this.unicodeEnd + 1)
            return false;
        if (gid !== this.gidEnd + 1)
            return false;
        this.unicodeEnd = unicode;
        this.gidEnd = gid;
        return true;
    }
}
class CmapFormat12Writer {
    constructor() {
        this.runs = [];
        this.last = null;
    }
    startSegment(unicode, gid) {
        this.last = new CmapFormat12Seg(unicode, gid);
    }
    flush() {
        if (!this.last)
            throw errors_1.Errors.Unreachable();
        this.runs.push(this.last);
    }
    iterateSegments(collected) {
        for (const [unicode, gid] of collected) {
            if (!this.last) {
                this.startSegment(unicode, gid);
            }
            else {
                const r = this.last.tryAccept(unicode, gid);
                if (!r) {
                    this.flush();
                    this.startSegment(unicode, gid);
                }
            }
        }
        if (this.last)
            this.flush();
    }
    makeTarget() {
        const fr = new bin_util_1.Frag();
        fr.uint16(12); // format
        fr.uint16(0); // reserved
        const hLength = fr.reserve(primitive_1.UInt32);
        fr.uint32(0); // language
        fr.uint32(this.runs.length);
        for (const run of this.runs) {
            fr.uint32(run.unicodeStart) // startCharCode
                .uint32(run.unicodeEnd) // endCharCode
                .uint32(run.gidStart); // startGlyphID
        }
        // Flag fragment, size is trustable
        hLength.fill(fr.size);
        return fr;
    }
    getFrag(collected, options) {
        if (!collected.length)
            return null;
        let hasNonBmp = false;
        for (const [unicode] of collected) {
            if (unicode >= primitive_1.UInt16.max)
                hasNonBmp = true;
        }
        if (!options.forceWriteUnicodeFull && !hasNonBmp)
            return null;
        this.iterateSegments(collected);
        return this.makeTarget();
    }
}
//# sourceMappingURL=unicode-full.js.map