var _onCurvePoint = 1 << 0;
var _xShortVector = 1 << 1;
var _yShortVector = 1 << 2;
var _repeatFlag = 1 << 3;
var _xOrPostiveXshortVector = 1 << 4;
var _yOrPostiveXshortVector = 1 << 5;
var _simpleOverlap = 1 << 6;
var _words = 1 << 0;
var _argsAreXYValues = 1 << 1;
var _scale = 1 << 3;
var _moreComponents = 1 << 5;
var _xyScale = 1 << 6;
var _twoByTwo = 1 << 7;
var _instructions = 1 << 8;
var _PdfGlyphTable = /** @class */ (function () {
    function _PdfGlyphTable(_a) {
        var glyfTable = _a.glyfTable, isGlyphLocationsLong = _a.isGlyphLocationsLong, locaTable = _a.locaTable, numGlyphs = _a.numGlyphs;
        this.glyphs = [];
        var loca = new DataView(locaTable.buffer, locaTable.byteOffset, locaTable.byteLength);
        var data = new DataView(glyfTable.buffer, glyfTable.byteOffset, glyfTable.byteLength);
        var offsetSize = isGlyphLocationsLong ? 4 : 2;
        var prev = isGlyphLocationsLong ? loca.getUint32(0) : 2 * loca.getUint16(0);
        var pos = 0;
        for (var i = 0; i < numGlyphs; i++) {
            pos += offsetSize;
            var next = isGlyphLocationsLong ? loca.getUint32(pos) : 2 * loca.getUint16(pos);
            if (next === prev) {
                this.glyphs.push(new _PdfGlyph({}));
                continue;
            }
            var pdfGlyph = new _PdfGlyph();
            var glyph = pdfGlyph.parse(prev, data); //eslint-disable-line
            this.glyphs.push(glyph);
            prev = next;
        }
    }
    _PdfGlyphTable.prototype._getSize = function () {
        return this.glyphs.reduce(function (a, g) {
            var size = g._getSize();
            return a + ((size + 3) & ~3);
        }, 0);
    };
    _PdfGlyphTable.prototype._write = function () {
        var totalSize = this._getSize();
        var glyfTable = new DataView(new ArrayBuffer(totalSize));
        var isLocationLong = totalSize > /* 0xffff * 2 */ 0x1fffe;
        var offsetSize = isLocationLong ? 4 : 2;
        var locaTable = new DataView(new ArrayBuffer((this.glyphs.length + 1) * offsetSize));
        if (isLocationLong) {
            locaTable.setUint32(0, 0);
        }
        else {
            locaTable.setUint16(0, 0);
        }
        var pos = 0;
        var locaIndex = 0;
        for (var _i = 0, _a = this.glyphs; _i < _a.length; _i++) {
            var glyph = _a[_i];
            pos += glyph._write(pos, glyfTable);
            pos = (pos + 3) & ~3;
            locaIndex += offsetSize;
            if (isLocationLong) {
                locaTable.setUint32(locaIndex, pos);
            }
            else {
                locaTable.setUint16(locaIndex, pos >> 1);
            }
        }
        return {
            isLocationLong: isLocationLong,
            loca: new Uint8Array(locaTable.buffer),
            data: new Uint8Array(glyfTable.buffer)
        };
    };
    _PdfGlyphTable.prototype.scale = function (factors) {
        for (var i = 0, ii = this.glyphs.length; i < ii; i++) {
            this.glyphs[Number.parseInt(i.toString(), 10)]._scale(factors[Number.parseInt(i.toString(), 10)]);
        }
    };
    return _PdfGlyphTable;
}());
export { _PdfGlyphTable };
var _PdfGlyph = /** @class */ (function () {
    function _PdfGlyph(params) {
        if (params) {
            this.header = params.header;
            this.simple = params.simple;
            this.composites = params.composites;
        }
        else {
            this.header = null;
            this.simple = null;
            this.composites = null;
        }
    }
    _PdfGlyph.prototype.parse = function (pos, data) {
        var glyphHeader = new _GlyphHeader();
        var _a = glyphHeader.parse(pos, data), read = _a[0], header = _a[1];
        pos += read;
        if (header.numberOfContours < 0) {
            var composites = [];
            var compositeGlyph = new _CompositeGlyph();
            while (true) { //eslint-disable-line
                var _b = compositeGlyph.parse(pos, data), n = _b[0], composite = _b[1];
                pos += n;
                composites.push(composite);
                if (!(composite.flags & _moreComponents)) {
                    break;
                }
            }
            return new _PdfGlyph({ header: header, composites: composites });
        }
        var simpleGlyph = new _SimpleGlyph();
        var simple = simpleGlyph.parse(pos, data, header.numberOfContours); //eslint-disable-line 
        return new _PdfGlyph({ header: header, simple: simple });
    };
    _PdfGlyph.prototype._getSize = function () {
        if (!this.header) {
            return 0;
        }
        var size = this.simple //eslint-disable-line
            ? this.simple.getSize()
            : this.composites.reduce(function (a, c) { return a + c.getSize(); }, 0); //eslint-disable-line 
        return this.header.getSize() + size;
    };
    _PdfGlyph.prototype._write = function (pos, buffer) {
        if (!this.header) {
            return 0;
        }
        var spos = pos;
        pos += this.header.write(pos, buffer);
        if (this.simple) {
            pos += this.simple.write(pos, buffer);
        }
        else {
            for (var _i = 0, _a = this.composites; _i < _a.length; _i++) {
                var composite = _a[_i];
                pos += composite.write(pos, buffer);
            }
        }
        return pos - spos;
    };
    _PdfGlyph.prototype._scale = function (factor) {
        if (!this.header) {
            return;
        }
        var xMiddle = (this.header.xMin + this.header.xMax) / 2;
        this.header.scale(xMiddle, factor);
        if (this.simple) {
            this.simple.scale(xMiddle, factor);
        }
    };
    return _PdfGlyph;
}());
export { _PdfGlyph };
var _GlyphHeader = /** @class */ (function () {
    function _GlyphHeader(params) {
        if (params) {
            this.numberOfContours = params.numberOfContours;
            this.xMin = params.xMin;
            this.yMin = params.yMin;
            this.xMax = params.xMax;
            this.yMax = params.yMax;
        }
        else {
            this.numberOfContours = 0;
            this.xMin = 0;
            this.yMin = 0;
            this.xMax = 0;
            this.yMax = 0;
        }
    }
    _GlyphHeader.prototype.parse = function (pos, data) {
        return [
            10,
            new _GlyphHeader({
                numberOfContours: data.getInt16(pos),
                xMin: data.getInt16(pos + 2),
                yMin: data.getInt16(pos + 4),
                xMax: data.getInt16(pos + 6),
                yMax: data.getInt16(pos + 8)
            })
        ];
    };
    _GlyphHeader.prototype.getSize = function () {
        return 10;
    };
    _GlyphHeader.prototype.write = function (pos, buffer) {
        buffer.setInt16(pos, this.numberOfContours);
        buffer.setInt16(pos + 2, this.xMin);
        buffer.setInt16(pos + 4, this.yMin);
        buffer.setInt16(pos + 6, this.xMax);
        buffer.setInt16(pos + 8, this.yMax);
        return 10;
    };
    _GlyphHeader.prototype.scale = function (x, factor) {
        this.xMin = Math.round(x + (this.xMin - x) * factor);
        this.xMax = Math.round(x + (this.xMax - x) * factor);
    };
    return _GlyphHeader;
}());
export { _GlyphHeader };
var _Contour = /** @class */ (function () {
    function _Contour(_a) {
        var flags = _a.flags, xCoordinates = _a.xCoordinates, yCoordinates = _a.yCoordinates;
        this.xCoordinates = xCoordinates;
        this.yCoordinates = yCoordinates;
        this.flags = flags;
    }
    return _Contour;
}());
export { _Contour };
var _SimpleGlyph = /** @class */ (function () {
    function _SimpleGlyph(params) {
        if (params) {
            this.contours = params.contours;
            this.instructions = params.instructions;
        }
        else {
            this.contours = [];
        }
    }
    _SimpleGlyph.prototype.parse = function (pos, data, numberOfContours) {
        var endPtsOfContours = [];
        for (var i = 0; i < numberOfContours; i++) {
            var endPt = data.getUint16(pos);
            pos += 2;
            endPtsOfContours.push(endPt);
        }
        var numberOfPt = endPtsOfContours[numberOfContours - 1] + 1;
        var instructionLength = data.getUint16(pos);
        pos += 2;
        var instructions = new Uint8Array(data.buffer, pos, instructionLength);
        pos += instructionLength;
        var flags = [];
        for (var i = 0; i < numberOfPt; pos++, i++) {
            var flag = data.getUint8(pos);
            flags.push(flag);
            if (flag & _repeatFlag) {
                var count = data.getUint8(++pos);
                flag ^= _repeatFlag;
                for (var m = 0; m < count; m++) {
                    flags.push(flag);
                }
                i += count;
            }
        }
        var allXCoordinates = [];
        var xCoordinates = [];
        var yCoordinates = [];
        var pointFlags = [];
        var contours = [];
        var endPtsOfContoursIndex = 0;
        var lastCoordinate = 0;
        for (var i = 0; i < numberOfPt; i++) {
            var flag = flags[Number.parseInt(i.toString(), 10)];
            if (flag & _xShortVector) {
                var x = data.getUint8(pos++);
                lastCoordinate += flag & _xOrPostiveXshortVector ? x : -x;
                xCoordinates.push(lastCoordinate);
            }
            else if (flag & _xOrPostiveXshortVector) {
                xCoordinates.push(lastCoordinate);
            }
            else {
                lastCoordinate += data.getInt16(pos);
                pos += 2;
                xCoordinates.push(lastCoordinate);
            }
            if (endPtsOfContours[Number.parseInt(endPtsOfContoursIndex.toString(), 10)] === i) {
                endPtsOfContoursIndex++;
                allXCoordinates.push(xCoordinates);
                xCoordinates = [];
            }
        }
        lastCoordinate = 0;
        endPtsOfContoursIndex = 0;
        for (var i = 0; i < numberOfPt; i++) {
            var flag = flags[Number.parseInt(i.toString(), 10)];
            if (flag & _yShortVector) {
                var y = data.getUint8(pos++);
                lastCoordinate += flag & _yOrPostiveXshortVector ? y : -y;
                yCoordinates.push(lastCoordinate);
            }
            else if (flag & _yOrPostiveXshortVector) {
                yCoordinates.push(lastCoordinate);
            }
            else {
                lastCoordinate += data.getInt16(pos);
                pos += 2;
                yCoordinates.push(lastCoordinate);
            }
            pointFlags.push((flag & _onCurvePoint) | (flag & _simpleOverlap));
            if (endPtsOfContours[Number.parseInt(endPtsOfContoursIndex.toString(), 10)] === i) {
                xCoordinates = allXCoordinates[Number.parseInt(endPtsOfContoursIndex.toString(), 10)];
                endPtsOfContoursIndex++;
                contours.push(new _Contour({
                    flags: pointFlags,
                    xCoordinates: xCoordinates,
                    yCoordinates: yCoordinates
                }));
                yCoordinates = [];
                pointFlags = [];
            }
        }
        return new _SimpleGlyph({
            contours: contours,
            instructions: instructions
        });
    };
    _SimpleGlyph.prototype.getSize = function () {
        var size = this.contours.length * 2 + 2 + this.instructions.length;
        var lastX = 0;
        var lastY = 0;
        for (var _i = 0, _a = this.contours; _i < _a.length; _i++) {
            var contour = _a[_i];
            size += contour.flags.length;
            for (var i = 0, ii = contour.xCoordinates.length; i < ii; i++) {
                var x = contour.xCoordinates[Number.parseInt(i.toString(), 10)];
                var y = contour.yCoordinates[Number.parseInt(i.toString(), 10)];
                var abs = Math.abs(x - lastX);
                if (abs > 255) {
                    size += 2;
                }
                else if (abs > 0) {
                    size += 1;
                }
                lastX = x;
                abs = Math.abs(y - lastY);
                if (abs > 255) {
                    size += 2;
                }
                else if (abs > 0) {
                    size += 1;
                }
                lastY = y;
            }
        }
        return size;
    };
    _SimpleGlyph.prototype.write = function (pos, buffer) {
        var spos = pos;
        var xCoordinates = [];
        var yCoordinates = [];
        var flags = [];
        var lastX = 0;
        var lastY = 0;
        for (var _i = 0, _a = this.contours; _i < _a.length; _i++) {
            var contour = _a[_i];
            for (var i = 0, ii = contour.xCoordinates.length; i < ii; i++) {
                var flag = contour.flags[Number.parseInt(i.toString(), 10)];
                var x = contour.xCoordinates[Number.parseInt(i.toString(), 10)];
                var delta = x - lastX;
                if (delta === 0) {
                    flag |= _xOrPostiveXshortVector;
                    xCoordinates.push(0);
                }
                else {
                    var abs = Math.abs(delta);
                    if (abs <= 255) {
                        flag |=
                            delta >= 0
                                ? _xShortVector | _xOrPostiveXshortVector
                                : _xShortVector;
                        xCoordinates.push(abs);
                    }
                    else {
                        xCoordinates.push(delta);
                    }
                }
                lastX = x;
                var y = contour.yCoordinates[Number.parseInt(i.toString(), 10)];
                delta = y - lastY;
                if (delta === 0) {
                    flag |= _yOrPostiveXshortVector;
                    yCoordinates.push(0);
                }
                else {
                    var abs = Math.abs(delta);
                    if (abs <= 255) {
                        flag |=
                            delta >= 0
                                ? _yShortVector | _yOrPostiveXshortVector
                                : _yShortVector;
                        yCoordinates.push(abs);
                    }
                    else {
                        yCoordinates.push(delta);
                    }
                }
                lastY = y;
                flags.push(flag);
            }
            buffer.setUint16(pos, xCoordinates.length - 1);
            pos += 2;
        }
        buffer.setUint16(pos, this.instructions.length);
        pos += 2;
        if (this.instructions.length) {
            new Uint8Array(buffer.buffer, 0, buffer.buffer.byteLength).set(this.instructions, pos);
            pos += this.instructions.length;
        }
        for (var _b = 0, flags_1 = flags; _b < flags_1.length; _b++) {
            var flag = flags_1[_b];
            buffer.setUint8(pos++, flag);
        }
        for (var i = 0, ii = xCoordinates.length; i < ii; i++) {
            var x = xCoordinates[Number.parseInt(i.toString(), 10)];
            var flag = flags[Number.parseInt(i.toString(), 10)];
            if (flag & _xShortVector) {
                buffer.setUint8(pos++, x);
            }
            else if (!(flag & _xOrPostiveXshortVector)) {
                buffer.setInt16(pos, x);
                pos += 2;
            }
        }
        for (var i = 0, ii = yCoordinates.length; i < ii; i++) {
            var y = yCoordinates[Number.parseInt(i.toString(), 10)];
            var flag = flags[Number.parseInt(i.toString(), 10)];
            if (flag & _yShortVector) {
                buffer.setUint8(pos++, y);
            }
            else if (!(flag & _yOrPostiveXshortVector)) {
                buffer.setInt16(pos, y);
                pos += 2;
            }
        }
        return pos - spos;
    };
    _SimpleGlyph.prototype.scale = function (x, factor) {
        for (var _i = 0, _a = this.contours; _i < _a.length; _i++) {
            var contour = _a[_i];
            if (contour.xCoordinates.length === 0) {
                continue;
            }
            for (var i = 0, ii = contour.xCoordinates.length; i < ii; i++) {
                contour.xCoordinates[Number.parseInt(i.toString(), 10)] = Math.round(x + (contour.xCoordinates[Number.parseInt(i.toString(), 10)] - x) * factor);
            }
        }
    };
    return _SimpleGlyph;
}());
export { _SimpleGlyph };
var _CompositeGlyph = /** @class */ (function () {
    function _CompositeGlyph(params) {
        if (params) {
            this.flags = params.flags;
            this.glyphIndex = params.glyphIndex;
            this.argument1 = params.argument1;
            this.argument2 = params.argument2;
            this.transform = params.transform;
            this.instructions = params.instructions;
        }
        else {
            this.flags = 0;
            this.glyphIndex = 0;
            this.argument1 = 0;
            this.argument2 = 0;
            this.transform = [];
            this.instructions = null;
        }
    }
    _CompositeGlyph.prototype.parse = function (pos, data) {
        var spos = pos;
        var transform = [];
        var flags = data.getUint16(pos);
        var glyphIndex = data.getUint16(pos + 2);
        pos += 4;
        var argument1;
        var argument2;
        if (flags & _words) {
            if (flags & _argsAreXYValues) {
                argument1 = data.getInt16(pos);
                argument2 = data.getInt16(pos + 2);
            }
            else {
                argument1 = data.getUint16(pos);
                argument2 = data.getUint16(pos + 2);
            }
            pos += 4;
            flags ^= _words;
        }
        else {
            if (flags & _argsAreXYValues) {
                argument1 = data.getInt8(pos);
                argument2 = data.getInt8(pos + 1);
            }
            else {
                argument1 = data.getUint8(pos);
                argument2 = data.getUint8(pos + 1);
            }
            pos += 2;
        }
        if (flags & _scale) {
            transform.push(data.getUint16(pos));
            pos += 2;
        }
        else if (flags & _xyScale) {
            transform.push(data.getUint16(pos), data.getUint16(pos + 2));
            pos += 4;
        }
        else if (flags & _twoByTwo) {
            transform.push(data.getUint16(pos), data.getUint16(pos + 2), data.getUint16(pos + 4), data.getUint16(pos + 6));
            pos += 8;
        }
        var instructions = null;
        if (flags & _instructions) {
            var instructionLength = data.getUint16(pos);
            pos += 2;
            instructions = new Uint8Array(data.buffer.slice(pos, pos + instructionLength));
            pos += instructionLength;
        }
        return [
            pos - spos,
            new _CompositeGlyph({
                flags: flags,
                glyphIndex: glyphIndex,
                argument1: argument1,
                argument2: argument2,
                transform: transform,
                instructions: instructions
            })
        ];
    };
    _CompositeGlyph.prototype.getSize = function () {
        var size = 2 + 2 + this.transform.length * 2;
        if (this.flags & _instructions) {
            size += 2 + (this.instructions ? this.instructions.length : 0);
        }
        size += 2;
        if (this.flags & 2) {
            if (!(this.argument1 >= -128 && this.argument1 <= 127 && this.argument2 >= -128 && this.argument2 <= 127)) {
                size += 2;
            }
        }
        else if (!(this.argument1 >= 0 && this.argument1 <= 255 && this.argument2 >= 0 && this.argument2 <= 255)) {
            size += 2;
        }
        return size;
    };
    _CompositeGlyph.prototype.write = function (pos, buffer) {
        var spos = pos;
        if (this.flags & _argsAreXYValues) {
            if (!(this.argument1 >= -128 && this.argument1 <= 127 && this.argument2 >= -128 && this.argument2 <= 127)) {
                this.flags |= _words;
            }
        }
        else if (!(this.argument1 >= 0 && this.argument1 <= 255 && this.argument2 >= 0 && this.argument2 <= 255)) {
            this.flags |= _words;
        }
        buffer.setUint16(pos, this.flags);
        buffer.setUint16(pos + 2, this.glyphIndex);
        pos += 4;
        if (this.flags & _words) {
            if (this.flags & _argsAreXYValues) {
                buffer.setInt16(pos, this.argument1);
                buffer.setInt16(pos + 2, this.argument2);
            }
            else {
                buffer.setUint16(pos, this.argument1);
                buffer.setUint16(pos + 2, this.argument2);
            }
            pos += 4;
        }
        else {
            buffer.setUint8(pos, this.argument1);
            buffer.setUint8(pos + 1, this.argument2);
            pos += 2;
        }
        if (this.flags & _instructions) {
            buffer.setUint16(pos, this.instructions ? this.instructions.length : 0);
            pos += 2;
            if (this.instructions && this.instructions.length) {
                new Uint8Array(buffer.buffer, 0, buffer.buffer.byteLength).set(this.instructions, pos);
                pos += this.instructions.length;
            }
        }
        return pos - spos;
    };
    return _CompositeGlyph;
}());
export { _CompositeGlyph };
