"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.UnicodeVS = 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");
const DefaultGlyph = Symbol();
const DefaultVs = {
    ...(0, bin_util_1.Read)((p, mapping, varSelector) => {
        const numUnicodeValueRanges = p.uint32();
        for (let range = 0; range < numUnicodeValueRanges; range++) {
            const startUnicodeValue = p.next(primitive_1.UInt24);
            const additionalCount = p.uint8();
            for (let count = 0; count <= additionalCount; count++) {
                mapping.set(startUnicodeValue + count, varSelector, DefaultGlyph);
            }
        }
    }),
    ...(0, bin_util_1.Write)((frag, mapping) => {
        const w = new DefaultVsWriter(frag);
        for (const code of mapping)
            w.push(code);
        w.end();
    })
};
class DefaultVsWriter {
    constructor(frag) {
        this.frag = frag;
        this.started = false;
        this.lastStartUnicodeValue = 0;
        this.lastEndUnicodeValue = 0;
        this.numUnicodeValueRanges = 0;
        this.hNumUnicodeValueRanges = frag.reserve(primitive_1.UInt32);
    }
    start(code) {
        this.started = true;
        this.lastStartUnicodeValue = this.lastEndUnicodeValue = code;
    }
    flush() {
        if (!this.started)
            return;
        this.frag.push(primitive_1.UInt24, this.lastStartUnicodeValue);
        this.frag.uint8(this.lastEndUnicodeValue - this.lastStartUnicodeValue);
        this.numUnicodeValueRanges++;
    }
    push(code) {
        if (!this.started) {
            this.start(code);
        }
        else if (code === this.lastEndUnicodeValue + 1
            && code - this.lastStartUnicodeValue < 0x100) {
            this.lastEndUnicodeValue = code;
        }
        else {
            this.flush();
            this.start(code);
        }
    }
    end() {
        if (this.started)
            this.flush();
        this.hNumUnicodeValueRanges.fill(this.numUnicodeValueRanges);
    }
}
const NonDefaultVs = {
    ...(0, bin_util_1.Read)((p, mapping, varSelector, gOrd) => {
        const numUVSMappings = p.uint32();
        for (let index = 0; index < numUVSMappings; index++) {
            const unicodeValue = p.next(primitive_1.UInt24);
            const glyphID = p.uint16();
            mapping.set(unicodeValue, varSelector, gOrd.at(glyphID));
        }
    }),
    ...(0, bin_util_1.Write)((frag, mapping) => {
        frag.uint32(mapping.length);
        for (const [unicode, gid] of mapping) {
            frag.push(primitive_1.UInt24, unicode);
            frag.uint16(gid);
        }
    })
};
class UnicodeVS {
    constructor() {
        this.mapping = new ot_encoding_1.CmapGeneralVsEncodingMapT();
        this.key = general_1.SubtableHandlerKey.UnicodeVS;
    }
    acceptEncoding(platform, encoding, format) {
        return platform === 0 && encoding === 5 && format === 14;
    }
    read(view, gOrd) {
        const format = view.uint16();
        errors_1.Assert.FormatSupported("subtable format", format, 14);
        const length = view.uint32();
        const numVarSelectorRecords = view.uint32();
        for (let recId = 0; recId < numVarSelectorRecords; recId++) {
            const varSelector = view.next(primitive_1.UInt24);
            const pDefaultUVS = view.ptr32Nullable();
            const pNonDefaultUVS = view.ptr32Nullable();
            if (pDefaultUVS)
                pDefaultUVS.next(DefaultVs, this.mapping, varSelector);
            if (pNonDefaultUVS)
                pNonDefaultUVS.next(NonDefaultVs, this.mapping, varSelector, gOrd);
        }
    }
    apply(cmap) {
        for (const [code, sel, glyph] of this.mapping.entries()) {
            if (glyph !== DefaultGlyph) {
                cmap.vs.set(code, sel, glyph);
            }
            else {
                const defaultG = cmap.unicode.get(code);
                if (defaultG)
                    cmap.vs.set(code, sel, defaultG);
            }
        }
    }
    writeOpt(cmap, gOrd) {
        const collected = new unicode_encoding_collector_1.UvsEncodingCollector(cmap.vs, cmap.unicode, gOrd).collect();
        if (!collected.length)
            return;
        const fSubtable = new bin_util_1.Frag();
        fSubtable.uint16(14);
        const hLength = fSubtable.reserve(primitive_1.UInt32);
        fSubtable.uint32(collected.length);
        for (const entry of collected) {
            fSubtable.push(primitive_1.UInt24, entry.selector);
            if (entry.defaults.length) {
                fSubtable.ptr32(bin_util_1.Frag.from(DefaultVs, entry.defaults));
            }
            else {
                fSubtable.ptr32(null);
            }
            if (entry.nonDefaults.length) {
                fSubtable.ptr32(bin_util_1.Frag.from(NonDefaultVs, entry.nonDefaults));
            }
            else {
                fSubtable.ptr32(null);
            }
        }
        // Consolidate before filling in the length
        bin_util_1.Frag.consolidate(fSubtable);
        hLength.fill(fSubtable.size);
        return fSubtable;
    }
    createAssignments(frag) {
        if (!frag.size)
            return [];
        return [{ platform: 0, encoding: 5, frag }];
    }
}
exports.UnicodeVS = UnicodeVS;
//# sourceMappingURL=unicode-vs.js.map