"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GposAdjustment = exports.GposAdjustmentFormat = void 0;
exports.hashVarVal = hashVarVal;
const Crypto = require("crypto");
const ImpLib = require("@ot-builder/common-impl");
const primitive_1 = require("@ot-builder/primitive");
const variance_1 = require("@ot-builder/variance");
const device_table_1 = require("./device-table");
var GposAdjustmentFormat;
(function (GposAdjustmentFormat) {
    GposAdjustmentFormat[GposAdjustmentFormat["ELIMINATED"] = 0] = "ELIMINATED";
    GposAdjustmentFormat[GposAdjustmentFormat["X_PLACEMENT"] = 1] = "X_PLACEMENT";
    GposAdjustmentFormat[GposAdjustmentFormat["Y_PLACEMENT"] = 2] = "Y_PLACEMENT";
    GposAdjustmentFormat[GposAdjustmentFormat["X_ADVANCE"] = 4] = "X_ADVANCE";
    GposAdjustmentFormat[GposAdjustmentFormat["Y_ADVANCE"] = 8] = "Y_ADVANCE";
    GposAdjustmentFormat[GposAdjustmentFormat["X_PLACEMENT_DEVICE"] = 16] = "X_PLACEMENT_DEVICE";
    GposAdjustmentFormat[GposAdjustmentFormat["Y_PLACEMENT_DEVICE"] = 32] = "Y_PLACEMENT_DEVICE";
    GposAdjustmentFormat[GposAdjustmentFormat["X_ADVANCE_DEVICE"] = 64] = "X_ADVANCE_DEVICE";
    GposAdjustmentFormat[GposAdjustmentFormat["Y_ADVANCE_DEVICE"] = 128] = "Y_ADVANCE_DEVICE";
})(GposAdjustmentFormat || (exports.GposAdjustmentFormat = GposAdjustmentFormat = {}));
function needDeviceEntry(dt, v) {
    return dt || !variance_1.OtVar.Ops.isConstant(v);
}
function omitWhenNoDeviceNeed(dt, v, val) {
    return dt || !variance_1.OtVar.Ops.isConstant(v) ? val : null;
}
function deviceDataSize(dt, v) {
    if (dt)
        return primitive_1.Int16.size * 5 + dt.length;
    else if (!variance_1.OtVar.Ops.isConstant(v))
        return primitive_1.Int16.size * 5;
    else
        return 0;
}
// Estimate data size under a specific format
function estimatePackedSizeImpl(format, adj) {
    let f = 0;
    if (format & GposAdjustmentFormat.X_PLACEMENT)
        f += primitive_1.Int16.size;
    if (format & GposAdjustmentFormat.Y_PLACEMENT)
        f += primitive_1.Int16.size;
    if (format & GposAdjustmentFormat.X_ADVANCE)
        f += primitive_1.Int16.size;
    if (format & GposAdjustmentFormat.Y_ADVANCE)
        f += primitive_1.Int16.size;
    if (format & GposAdjustmentFormat.X_PLACEMENT_DEVICE) {
        f += deviceDataSize(adj.dXDevice, adj.dX);
    }
    if (format & GposAdjustmentFormat.Y_PLACEMENT_DEVICE) {
        f += deviceDataSize(adj.dYDevice, adj.dY);
    }
    if (format & GposAdjustmentFormat.X_ADVANCE_DEVICE) {
        f += deviceDataSize(adj.dWidthDevice, adj.dWidth);
    }
    if (format & GposAdjustmentFormat.Y_ADVANCE_DEVICE) {
        f += deviceDataSize(adj.dHeightDevice, adj.dHeight);
    }
    return f;
}
exports.GposAdjustment = {
    read(view, format, ivs) {
        const adj = {
            dX: 0,
            dY: 0,
            dWidth: 0,
            dHeight: 0
        };
        if (format & GposAdjustmentFormat.X_PLACEMENT) {
            adj.dX = view.int16();
        }
        if (format & GposAdjustmentFormat.Y_PLACEMENT) {
            adj.dY = view.int16();
        }
        if (format & GposAdjustmentFormat.X_ADVANCE) {
            adj.dWidth = view.int16();
        }
        if (format & GposAdjustmentFormat.Y_ADVANCE) {
            adj.dHeight = view.int16();
        }
        if (format & GposAdjustmentFormat.X_PLACEMENT_DEVICE) {
            const dd = view.next(device_table_1.Ptr16DeviceTable, ivs);
            if (dd) {
                adj.dX = variance_1.OtVar.Ops.add(adj.dX, dd.variation);
                adj.dXDevice = dd.deviceDeltas;
            }
        }
        if (format & GposAdjustmentFormat.Y_PLACEMENT_DEVICE) {
            const dd = view.next(device_table_1.Ptr16DeviceTable, ivs);
            if (dd) {
                adj.dY = variance_1.OtVar.Ops.add(adj.dY, dd.variation);
                adj.dYDevice = dd.deviceDeltas;
            }
        }
        if (format & GposAdjustmentFormat.X_ADVANCE_DEVICE) {
            const dd = view.next(device_table_1.Ptr16DeviceTable, ivs);
            if (dd) {
                adj.dWidth = variance_1.OtVar.Ops.add(adj.dWidth, dd.variation);
                adj.dWidthDevice = dd.deviceDeltas;
            }
        }
        if (format & GposAdjustmentFormat.Y_ADVANCE_DEVICE) {
            const dd = view.next(device_table_1.Ptr16DeviceTable, ivs);
            if (dd) {
                adj.dHeight = variance_1.OtVar.Ops.add(adj.dHeight, dd.variation);
                adj.dHeightDevice = dd.deviceDeltas;
            }
        }
        return adj;
    },
    write(b, adj, format, ivs) {
        if (format & GposAdjustmentFormat.X_PLACEMENT) {
            b.int16(ImpLib.Arith.Round.Offset(variance_1.OtVar.Ops.originOf(adj.dX)));
        }
        if (format & GposAdjustmentFormat.Y_PLACEMENT) {
            b.int16(ImpLib.Arith.Round.Offset(variance_1.OtVar.Ops.originOf(adj.dY)));
        }
        if (format & GposAdjustmentFormat.X_ADVANCE) {
            b.int16(ImpLib.Arith.Round.Offset(variance_1.OtVar.Ops.originOf(adj.dWidth)));
        }
        if (format & GposAdjustmentFormat.Y_ADVANCE) {
            b.int16(ImpLib.Arith.Round.Offset(variance_1.OtVar.Ops.originOf(adj.dHeight)));
        }
        if (format & GposAdjustmentFormat.X_PLACEMENT_DEVICE) {
            const dt = omitWhenNoDeviceNeed(adj.dXDevice, adj.dX, {
                variation: adj.dX,
                deviceDeltas: adj.dXDevice
            });
            b.push(device_table_1.Ptr16DeviceTable, dt, ivs);
        }
        if (format & GposAdjustmentFormat.Y_PLACEMENT_DEVICE) {
            const dt = omitWhenNoDeviceNeed(adj.dYDevice, adj.dY, {
                variation: adj.dY,
                deviceDeltas: adj.dYDevice
            });
            b.push(device_table_1.Ptr16DeviceTable, dt, ivs);
        }
        if (format & GposAdjustmentFormat.X_ADVANCE_DEVICE) {
            const dt = omitWhenNoDeviceNeed(adj.dWidthDevice, adj.dWidth, {
                variation: adj.dWidth,
                deviceDeltas: adj.dWidthDevice
            });
            b.push(device_table_1.Ptr16DeviceTable, dt, ivs);
        }
        if (format & GposAdjustmentFormat.Y_ADVANCE_DEVICE) {
            const dt = omitWhenNoDeviceNeed(adj.dWidthDevice, adj.dWidth, {
                variation: adj.dHeight,
                deviceDeltas: adj.dHeightDevice
            });
            b.push(device_table_1.Ptr16DeviceTable, dt, ivs);
        }
    },
    measure(adj, format) {
        return estimatePackedSizeImpl(format, adj);
    },
    decideFormat(adj) {
        let f = GposAdjustmentFormat.ELIMINATED;
        if (!variance_1.OtVar.Ops.isZero(adj.dX))
            f |= GposAdjustmentFormat.X_PLACEMENT;
        if (!variance_1.OtVar.Ops.isZero(adj.dY))
            f |= GposAdjustmentFormat.Y_PLACEMENT;
        if (!variance_1.OtVar.Ops.isZero(adj.dWidth))
            f |= GposAdjustmentFormat.X_ADVANCE;
        if (!variance_1.OtVar.Ops.isZero(adj.dHeight))
            f |= GposAdjustmentFormat.Y_ADVANCE;
        if (needDeviceEntry(adj.dXDevice, adj.dX)) {
            f |= GposAdjustmentFormat.X_PLACEMENT_DEVICE | GposAdjustmentFormat.X_PLACEMENT;
        }
        if (needDeviceEntry(adj.dYDevice, adj.dY)) {
            f |= GposAdjustmentFormat.Y_PLACEMENT_DEVICE | GposAdjustmentFormat.Y_PLACEMENT;
        }
        if (needDeviceEntry(adj.dWidthDevice, adj.dWidth)) {
            f |= GposAdjustmentFormat.X_ADVANCE_DEVICE | GposAdjustmentFormat.X_ADVANCE;
        }
        if (needDeviceEntry(adj.dHeightDevice, adj.dHeight)) {
            f |= GposAdjustmentFormat.Y_ADVANCE_DEVICE | GposAdjustmentFormat.Y_ADVANCE;
        }
        return f;
    },
    hash(adj, ivs) {
        const hasher = new ImpLib.Hasher();
        hashVarVal(hasher.begin(), ivs, adj.dX, adj.dXDevice);
        hashVarVal(hasher.begin(), ivs, adj.dY, adj.dYDevice);
        hashVarVal(hasher.begin(), ivs, adj.dWidth, adj.dWidthDevice);
        hashVarVal(hasher.begin(), ivs, adj.dHeight, adj.dHeightDevice);
        const sink = Crypto.createHash("sha256");
        hasher.transfer(sink);
        return sink.digest("hex");
    },
    hashPair(adj, ivs) {
        const hasher = new ImpLib.Hasher();
        hashVarVal(hasher.begin(), ivs, adj[0].dX, adj[0].dXDevice);
        hashVarVal(hasher.begin(), ivs, adj[0].dY, adj[0].dYDevice);
        hashVarVal(hasher.begin(), ivs, adj[0].dWidth, adj[0].dWidthDevice);
        hashVarVal(hasher.begin(), ivs, adj[0].dHeight, adj[0].dHeightDevice);
        hashVarVal(hasher.begin(), ivs, adj[1].dX, adj[1].dXDevice);
        hashVarVal(hasher.begin(), ivs, adj[1].dY, adj[1].dYDevice);
        hashVarVal(hasher.begin(), ivs, adj[1].dWidth, adj[1].dWidthDevice);
        hashVarVal(hasher.begin(), ivs, adj[1].dHeight, adj[1].dHeightDevice);
        const sink = Crypto.createHash("sha256");
        hasher.transfer(sink);
        return sink.digest("hex");
    }
};
function hashVarVal(h, ivs, x, device) {
    h.number(ImpLib.Arith.Round.Offset(variance_1.OtVar.Ops.originOf(x)));
    const oi = ivs === null || ivs === void 0 ? void 0 : ivs.valueToInnerOuterID(x);
    if (oi)
        h.number(1, oi.outer, oi.inner);
    if (device)
        h.number(2).numbers(device);
}
//# sourceMappingURL=gpos-adjust.js.map