"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Ptr16GposAnchor = exports.NullablePtr16GposAnchor = exports.GposAnchor = void 0;
const tslib_1 = require("tslib");
const Crypto = tslib_1.__importStar(require("node:crypto"));
const bin_composite_types_1 = require("@ot-builder/bin-composite-types");
const ImpLib = tslib_1.__importStar(require("@ot-builder/common-impl"));
const errors_1 = require("@ot-builder/errors");
const primitive_1 = require("@ot-builder/primitive");
const variance_1 = require("@ot-builder/variance");
const device_table_1 = require("./device-table");
const gpos_adjust_1 = require("./gpos-adjust");
function anchorNeedsFormat3(a) {
    return !variance_1.OtVar.Ops.isConstant(a.x) || !variance_1.OtVar.Ops.isConstant(a.y) || a.xDevice || a.yDevice;
}
exports.GposAnchor = {
    read(bp, ivs) {
        const format = bp.uint16();
        if (format === 1) {
            return {
                x: bp.int16(),
                y: bp.int16()
            };
        }
        else if (format === 2) {
            return {
                x: bp.int16(),
                y: bp.int16(),
                attachToPoint: { pointIndex: bp.uint16() }
            };
        }
        else if (format === 3) {
            const x = bp.int16();
            const y = bp.int16();
            const xDD = bp.next(device_table_1.Ptr16DeviceTable, ivs);
            const yDD = bp.next(device_table_1.Ptr16DeviceTable, ivs);
            return {
                x: variance_1.OtVar.Ops.add(x, xDD ? xDD.variation : 0),
                y: variance_1.OtVar.Ops.add(y, yDD ? yDD.variation : 0),
                xDevice: xDD ? xDD.deviceDeltas : null,
                yDevice: yDD ? yDD.deviceDeltas : null
            };
        }
        else {
            throw errors_1.Errors.FormatNotSupported("anchor", format);
        }
    },
    write(bb, a, ivs) {
        if (a.attachToPoint) {
            bb.uint16(2);
            bb.int16(ImpLib.Arith.Round.Coord(variance_1.OtVar.Ops.originOf(a.x)));
            bb.int16(ImpLib.Arith.Round.Coord(variance_1.OtVar.Ops.originOf(a.y)));
            bb.uint16(a.attachToPoint.pointIndex);
        }
        else if (anchorNeedsFormat3(a)) {
            const dtX = { variation: a.x, deviceDeltas: a.xDevice };
            const dtY = { variation: a.y, deviceDeltas: a.yDevice };
            bb.uint16(3);
            bb.int16(ImpLib.Arith.Round.Coord(variance_1.OtVar.Ops.originOf(a.x)));
            bb.int16(ImpLib.Arith.Round.Coord(variance_1.OtVar.Ops.originOf(a.y)));
            bb.push(device_table_1.Ptr16DeviceTable, dtX, ivs);
            bb.push(device_table_1.Ptr16DeviceTable, dtY, ivs);
        }
        else {
            bb.uint16(1);
            bb.int16(ImpLib.Arith.Round.Coord(variance_1.OtVar.Ops.originOf(a.x)));
            bb.int16(ImpLib.Arith.Round.Coord(variance_1.OtVar.Ops.originOf(a.y)));
        }
    },
    measure(a) {
        if (!a)
            return 0;
        const staticSize = primitive_1.Int16.size * 3;
        if (a.attachToPoint) {
            return staticSize + primitive_1.Int16.size;
        }
        else if (!anchorNeedsFormat3(a)) {
            return staticSize;
        }
        else {
            return (staticSize
                + primitive_1.UInt16.size * 8
                + (a.xDevice ? a.xDevice.length : 0)
                + (a.yDevice ? a.yDevice.length : 0));
        }
    },
    hash(a, ivs) {
        const hasher = new ImpLib.Hasher();
        (0, gpos_adjust_1.hashVarVal)(hasher.begin(), ivs, a.x, a.xDevice);
        (0, gpos_adjust_1.hashVarVal)(hasher.begin(), ivs, a.y, a.yDevice);
        if (a.attachToPoint) {
            hasher.beginSubObj("attachToPoint").number(a.attachToPoint.pointIndex);
        }
        const sink = Crypto.createHash("sha256");
        hasher.transfer(sink);
        return sink.digest("hex");
    },
    hashMeasure(col, ivs, anchor) {
        if (!anchor)
            return 0;
        const hash = exports.GposAnchor.hash(anchor, ivs);
        if (col.has(hash)) {
            return 0;
        }
        else {
            col.add(hash);
            return exports.GposAnchor.measure(anchor);
        }
    }
};
exports.NullablePtr16GposAnchor = (0, bin_composite_types_1.NullablePtr16)(exports.GposAnchor);
exports.Ptr16GposAnchor = (0, bin_composite_types_1.NonNullablePtr16)(exports.GposAnchor);
//# sourceMappingURL=gpos-anchor.js.map