"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GposCursiveWriter = exports.GposCursiveReader = void 0;
const bin_util_1 = require("@ot-builder/bin-util");
const errors_1 = require("@ot-builder/errors");
const ot_layout_1 = require("@ot-builder/ot-layout");
const primitive_1 = require("@ot-builder/primitive");
const general_1 = require("../gsub-gpos-shared/general");
const coverage_1 = require("../shared/coverage");
const gpos_anchor_1 = require("../shared/gpos-anchor");
const SubtableFormat1 = {
    read(view, lookup, context) {
        const format = view.uint16();
        errors_1.Assert.FormatSupported(`CursivePosFormat1`, format, 1);
        const coverage = view.ptr16().next(coverage_1.GidCoverage);
        const entryExitCount = view.uint16();
        errors_1.Assert.SizeMatch(`CursivePosFormat1::entryExitCount`, entryExitCount, coverage.length);
        for (const gid of coverage) {
            const entry = view.next(gpos_anchor_1.NullablePtr16GposAnchor, context.ivs);
            const exit = view.next(gpos_anchor_1.NullablePtr16GposAnchor, context.ivs);
            lookup.attachments.set(context.gOrd.at(gid), { entry, exit });
        }
    },
    write(frag, mapping, ctx) {
        const { gidList, values } = coverage_1.CovUtils.splitListFromMap(mapping, ctx.gOrd);
        frag.uint16(1);
        frag.push(coverage_1.Ptr16GidCoverage, gidList, ctx.trick);
        frag.uint16(values.length);
        for (const to of values) {
            frag.push(gpos_anchor_1.NullablePtr16GposAnchor, to.entry, ctx.ivs);
            frag.push(gpos_anchor_1.NullablePtr16GposAnchor, to.exit, ctx.ivs);
        }
    }
};
class GposCursiveReader {
    createLookup() {
        return new ot_layout_1.Gpos.Cursive();
    }
    parseSubtable(view, lookup, context) {
        const format = view.lift(0).uint16();
        switch (format) {
            case 1:
                view.next(SubtableFormat1, lookup, context);
                break;
            default:
                throw errors_1.Errors.FormatNotSupported(`Single Positioning Subtable`, format);
        }
    }
}
exports.GposCursiveReader = GposCursiveReader;
class State {
    constructor() {
        this.mapping = new Map();
        this.size = primitive_1.UInt16.size * 4;
    }
    tryAddMapping(from, to) {
        const deltaSize = primitive_1.UInt16.size * (2 + coverage_1.MaxCovItemWords) // 1 cov + 2 ptr
            + gpos_anchor_1.GposAnchor.measure(to.entry)
            + gpos_anchor_1.GposAnchor.measure(to.exit);
        if (this.size + deltaSize > general_1.SubtableSizeLimit)
            return false;
        this.mapping.set(from, to);
        this.size += deltaSize;
        return true;
    }
}
class GposCursiveWriter {
    canBeUsed(l) {
        return l.type === ot_layout_1.Gpos.LookupType.Cursive;
    }
    getLookupType() {
        return 3;
    }
    getLookupTypeSymbol() {
        return ot_layout_1.Gpos.LookupType.Cursive;
    }
    flush(frags, state, ctx) {
        if (!state.mapping.size)
            return;
        frags.push(bin_util_1.Frag.from(SubtableFormat1, state.mapping, ctx));
    }
    createSubtableFragments(lookup, ctx) {
        let state = new State();
        const frags = [];
        for (const [from, to] of lookup.attachments) {
            if (state.tryAddMapping(from, to))
                continue;
            this.flush(frags, state, ctx);
            state = new State();
            if (!state.tryAddMapping(from, to))
                throw errors_1.Errors.Unreachable();
        }
        this.flush(frags, state, ctx);
        return frags;
    }
}
exports.GposCursiveWriter = GposCursiveWriter;
//# sourceMappingURL=gpos-cursive.js.map