import { SinglePacket } from '../generated/models';
import { SinglePacketError } from './definitions';
import { computePadding } from './util';
var TAG = "SinglePacketBuilder";
export var ZEROS_PADDING_GENERATOR = function (length) { return new Uint8Array(length); };
var SinglePacketBuilder = /** @class */ (function () {
    function SinglePacketBuilder(type, paddingGenerator) {
        if (paddingGenerator === void 0) { paddingGenerator = ZEROS_PADDING_GENERATOR; }
        this.paddingGenerator = paddingGenerator;
        this.model = {
            sendTime: 0,
            header: {
                ack: false,
                configVersion: 0,
                encryption: false,
                isExtended: false,
                messageType: type,
                packetId: 0,
                packetLength: 0,
                salt: Math.round(Math.random() * 0xffff),
                senderId: 0
            },
            payload: {
                data: new Uint8Array(),
                dataSize: 0,
                logTime: SinglePacketBuilder.getTimestampInSeconds(),
                padding: undefined // TODO
            }
        };
    }
    // static fillComputedField(packet: SinglePacket): SinglePacket {
    //     if (!packet.sendTime) {
    //         packet.sendTime = SinglePacketBuilder.getTimestampInSeconds();
    //     }
    //     packet.payload.dataSize = packet.payload.data.length;
    //     packet.header.packetLength =
    //         computePadding(packet.payload.data.length + 10, 4) +
    //         packet.payload.data.length +
    //         SinglePacketBuilder.PACKET_HEADER_SIZE_WITH_SEND_TIME;
    //     let multiplicator = SinglePacketBuilder.getLengthMultiplicator(packet);
    //     if (packet.header.packetLength % multiplicator !==  0){
    //         throw new Error(`Packet length must be a multiple of ${multiplicator}. But length is ${packet.header.packetLength}`);
    //     }
    //     return packet;
    // }
    SinglePacketBuilder.getTimestampInSeconds = function () {
        return Math.round(new Date().getTime() / 1000);
    };
    SinglePacketBuilder.getLengthMultiplicator = function (packet) {
        if (packet.header.isExtended) {
            return 256;
        }
        else if (packet.header.encryption || packet.header.messageType === SinglePacket.PacketType.CODE_EXEC) {
            return 16;
        }
        else {
            return 1;
        }
    };
    SinglePacketBuilder.create = function (data, type, paddingGenertor) {
        if (paddingGenertor === void 0) { paddingGenertor = ZEROS_PADDING_GENERATOR; }
        var builder = new SinglePacketBuilder(type, paddingGenertor);
        builder.setData(data);
        return builder;
    };
    SinglePacketBuilder.prototype.setLogTime = function (logTime) {
        this.model.payload.logTime = logTime;
        return this;
    };
    /**
     *
     * @param id
     */
    SinglePacketBuilder.prototype.setPacketId = function (id) {
        // TODO check length ?
        this.model.header.packetId = id;
        return this;
    };
    SinglePacketBuilder.prototype.setSalt = function (salt) {
        this.model.header.salt = salt;
        return this;
    };
    SinglePacketBuilder.prototype.setExtended = function (value) {
        this.model.header.isExtended = value;
        return this;
    };
    /**
     *
     * @param id
     */
    SinglePacketBuilder.prototype.setEncryption = function (enabled) {
        // TODO check length ?
        this.model.header.encryption = enabled;
        return this;
    };
    /**
     *
     * @param id
     */
    SinglePacketBuilder.prototype.setSenderId = function (id) {
        // TODO check length ?
        this.model.header.senderId = id;
        return this;
    };
    /**
     *
     * @param id
     */
    SinglePacketBuilder.prototype.setSendTime = function (time) {
        this.model.sendTime = time;
        return this;
    };
    /**
     *
     * @param id
     */
    SinglePacketBuilder.prototype.setConfigVersion = function (configVersion) {
        this.model.header.configVersion = configVersion;
        return this;
    };
    SinglePacketBuilder.prototype.setData = function (data) {
        this.model.payload.data = data;
        return this;
    };
    SinglePacketBuilder.prototype.getLengthMultiplicator = function () {
        return SinglePacketBuilder.getLengthMultiplicator(this.model);
    };
    SinglePacketBuilder.prototype.build = function () {
        if (!this.model.sendTime) {
            this.model.sendTime = SinglePacketBuilder.getTimestampInSeconds();
        }
        var multiplicator = this.getLengthMultiplicator();
        if (this.model.payload.data.length > (0xFFFF * multiplicator)) {
            this.model.header.isExtended = true;
        }
        multiplicator = this.getLengthMultiplicator(); // Refresh multiplicator if isExtended
        var paddingMultiple = Math.max(4, multiplicator); // TODO constant
        // debug(TAG, 'Multiplicator', multiplicator, 'padding mult', paddingMultiple);
        var requiredPadding = computePadding(this.model.payload.data.length + SinglePacketBuilder.PACKET_PAYLOAD_HEADER_SIZE, paddingMultiple);
        // debug(TAG, 'requiredPadding', requiredPadding);
        this.model.payload.padding = this.paddingGenerator(requiredPadding);
        // debug(TAG, 'this.model.payload.padding', this.model.payload.padding);
        var payloadLengthInBytes = this.model.payload.data.length + SinglePacketBuilder.PACKET_PAYLOAD_HEADER_SIZE + this.model.payload.padding.length;
        var packetLengthInBytes = SinglePacketBuilder.PACKET_HEADER_SIZE + this.model.payload.data.length + this.model.payload.padding.length;
        this.model.payload.dataSize = this.model.payload.data.length > 0xFFFF
            ? undefined
            : this.model.payload.data.length;
        if (payloadLengthInBytes % multiplicator !== 0) {
            throw SinglePacketError.internalError("Packet length " + packetLengthInBytes + " must be a multiple of " + multiplicator);
        }
        if (packetLengthInBytes > SinglePacketBuilder.MAX_FULL_SIZE) {
            throw SinglePacketError.maxSinglePacketSizeExceeded(packetLengthInBytes, SinglePacketBuilder.MAX_FULL_SIZE);
        }
        this.model.header.packetLength = payloadLengthInBytes / multiplicator;
        if (multiplicator === 1) {
            this.model.header.packetLength += SinglePacketBuilder.PACKET_OUTER_HEADER_SIZE;
        }
        return this.model;
    };
    SinglePacketBuilder.MAX_FULL_SIZE = 0x200000;
    SinglePacketBuilder.MAX_PART_SIZE = 0xc0;
    SinglePacketBuilder.PACKET_PAYLOAD_HEADER_SIZE = 4 + 2 + 4;
    SinglePacketBuilder.PACKET_OUTER_HEADER_SIZE = 12;
    SinglePacketBuilder.PACKET_HEADER_SIZE = SinglePacketBuilder.PACKET_OUTER_HEADER_SIZE + SinglePacketBuilder.PACKET_PAYLOAD_HEADER_SIZE;
    SinglePacketBuilder.PACKET_HEADER_SIZE_WITH_SEND_TIME = SinglePacketBuilder.PACKET_HEADER_SIZE + 4;
    SinglePacketBuilder.MAX_DATA_SIZE = SinglePacketBuilder.MAX_FULL_SIZE - (SinglePacketBuilder.PACKET_HEADER_SIZE_WITH_SEND_TIME + 0xFF);
    return SinglePacketBuilder;
}());
export { SinglePacketBuilder };
//# sourceMappingURL=data:application/json;base64, 