"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CffPrivateDictIo = void 0;
const bin_util_1 = require("@ot-builder/bin-util");
const errors_1 = require("@ot-builder/errors");
const ot_glyphs_1 = require("@ot-builder/ot-glyphs");
const variance_1 = require("@ot-builder/variance");
const subroutine_index_1 = require("../char-string/read/subroutine-index");
const draw_call_1 = require("../char-string/write/draw-call");
const operator_1 = require("../interp/operator");
const general_1 = require("./general");
class PrivateDictInterpreter extends general_1.CffDictInterpreterBase {
    constructor(ctx, viewDict) {
        super(ctx.ivs);
        this.ctx = ctx;
        this.viewDict = viewDict;
        this.result = new ot_glyphs_1.Cff.PrivateDict();
    }
    // Justification: This is a dispatch table and does not contain substantial complexity
    // eslint-disable-next-line complexity
    doOperator(opCode, flags) {
        switch (opCode) {
            case operator_1.CffOperator.VsIndex: {
                const vsIndex = this.st.doVsIndex();
                this.result.inheritedVsIndex = vsIndex;
                return vsIndex;
            }
            case operator_1.CffOperator.Blend:
                return this.st.doBlend();
            case operator_1.CffOperator.Subrs: {
                const vwPrivateSubrs = this.viewDict.lift(variance_1.OtVar.Ops.originOf(this.st.pop()));
                this.result.localSubroutines = vwPrivateSubrs.next(subroutine_index_1.CffSubroutineIndex, this.ctx);
                break;
            }
            case operator_1.CffOperator.BlueValues:
                this.result.blueValues = this.st.accumulate(this.st.allArgs());
                break;
            case operator_1.CffOperator.OtherBlues:
                this.result.otherBlues = this.st.accumulate(this.st.allArgs());
                break;
            case operator_1.CffOperator.FamilyBlues:
                this.result.familyBlues = this.st.accumulate(this.st.allArgs());
                break;
            case operator_1.CffOperator.FamilyOtherBlues:
                this.result.familyOtherBlues = this.st.accumulate(this.st.allArgs());
                break;
            case operator_1.CffOperator.BlueScale:
                this.result.blueScale = this.st.pop();
                break;
            case operator_1.CffOperator.BlueShift:
                this.result.blueShift = this.st.pop();
                break;
            case operator_1.CffOperator.BlueFuzz:
                this.result.blueFuzz = this.st.pop();
                break;
            case operator_1.CffOperator.StdHW:
                this.result.stdHW = this.st.pop();
                break;
            case operator_1.CffOperator.StdVW:
                this.result.stdVW = this.st.pop();
                break;
            case operator_1.CffOperator.StemSnapH:
                this.result.stemSnapH = this.st.accumulate(this.st.allArgs());
                break;
            case operator_1.CffOperator.StemSnapV:
                this.result.stemSnapV = this.st.accumulate(this.st.allArgs());
                break;
            case operator_1.CffOperator.LanguageGroup:
                this.result.languageGroup = variance_1.OtVar.Ops.originOf(this.st.pop());
                break;
            case operator_1.CffOperator.ExpansionFactor:
                this.result.expansionFactor = this.st.pop();
                break;
            case operator_1.CffOperator.DefaultWidthX:
                this.result.defaultWidthX = variance_1.OtVar.Ops.originOf(this.st.pop());
                break;
            case operator_1.CffOperator.NominalWidthX:
                this.result.nominalWidthX = variance_1.OtVar.Ops.originOf(this.st.pop());
                break;
            case operator_1.CffOperator.ForceBold:
                this.result.forceBold = Boolean(variance_1.OtVar.Ops.originOf(this.st.pop()));
                break;
            case operator_1.CffOperator.initialRandomSeed:
                this.result.initialRandomSeed = variance_1.OtVar.Ops.originOf(this.st.pop());
                break;
            default:
                throw errors_1.Errors.Cff.OperatorNotSupported(opCode);
        }
    }
    getResult() {
        return this.result;
    }
}
class PrivateDictDataCollector extends general_1.CffDictDataCollector {
    *emitDeltas(vs, op) {
        if (!vs.length)
            return;
        let a = 0;
        const deltas = [];
        for (const v of vs) {
            const d = variance_1.OtVar.Ops.minus(v, a);
            deltas.push(d);
            a = v;
        }
        yield new draw_call_1.CffDrawCallRaw(deltas, op);
    }
    *emitNumber(q, defaultQ, op) {
        if (variance_1.OtVar.Ops.equal(q, defaultQ, 1 / 0x10000))
            return;
        yield new draw_call_1.CffDrawCallRaw([q], op);
    }
    *collectDrawCalls(pd, ctx, rest) {
        // Blue zones ("deltas" in spec)
        yield* this.emitDeltas(pd.blueValues, operator_1.CffOperator.BlueValues);
        yield* this.emitDeltas(pd.otherBlues, operator_1.CffOperator.OtherBlues);
        yield* this.emitDeltas(pd.familyBlues, operator_1.CffOperator.FamilyBlues);
        yield* this.emitDeltas(pd.familyOtherBlues, operator_1.CffOperator.FamilyOtherBlues);
        yield* this.emitDeltas(pd.stemSnapH, operator_1.CffOperator.StemSnapH);
        yield* this.emitDeltas(pd.stemSnapV, operator_1.CffOperator.StemSnapV);
        // Numeric fields
        const defaultPd = new ot_glyphs_1.Cff.PrivateDict();
        yield* this.emitNumber(pd.blueScale, defaultPd.blueScale, operator_1.CffOperator.BlueScale);
        yield* this.emitNumber(pd.blueShift, defaultPd.blueShift, operator_1.CffOperator.BlueShift);
        yield* this.emitNumber(pd.blueFuzz, defaultPd.blueFuzz, operator_1.CffOperator.BlueFuzz);
        yield* this.emitNumber(pd.stdHW, defaultPd.stdHW, operator_1.CffOperator.StdHW);
        yield* this.emitNumber(pd.stdVW, defaultPd.stdVW, operator_1.CffOperator.StdVW);
        yield* this.emitNumber(pd.expansionFactor, defaultPd.expansionFactor, operator_1.CffOperator.ExpansionFactor);
        yield* this.emitNumber(pd.languageGroup, defaultPd.languageGroup, operator_1.CffOperator.LanguageGroup);
        if (ctx.version === 1) {
            yield* this.emitNumber(pd.defaultWidthX, defaultPd.defaultWidthX, operator_1.CffOperator.DefaultWidthX);
            yield* this.emitNumber(pd.nominalWidthX, defaultPd.nominalWidthX, operator_1.CffOperator.NominalWidthX);
            yield* this.emitNumber(Number(pd.forceBold), Number(defaultPd.forceBold), operator_1.CffOperator.ForceBold);
            yield* this.emitNumber(pd.initialRandomSeed, defaultPd.initialRandomSeed, operator_1.CffOperator.initialRandomSeed);
        }
    }
    processPointers(encoder, pd, ctx, rest) {
        if (pd.localSubroutines) {
            encoder.embRelPointer(new bin_util_1.Frag().push(subroutine_index_1.CffSubroutineIndex, pd.localSubroutines, ctx), operator_1.CffOperator.Subrs);
        }
    }
}
exports.CffPrivateDictIo = {
    ...(0, general_1.CffDictReadT)((viewDict, ctx) => new PrivateDictInterpreter(ctx, viewDict.lift(0))),
    ...(0, general_1.CffDictWriteT)(new PrivateDictDataCollector())
};
//# sourceMappingURL=private-dict.js.map