var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import '../generated/service-container-extension';
import { StepOperations } from '@iotize/common/task-manager';
import { sleep } from '@iotize/common/utility';
import { TapError } from '@iotize/tap';
import { ResultCode } from '@iotize/tap/client/api';
import { CRC } from '@iotize/tap/client/impl';
import { SinglePacketChunk } from '../generated/models';
import { debug } from '../logger';
import { SinglePacketError } from './definitions';
import { SinglePacketBuilder } from './single-packet-builder';
import { SinglePacketSplitter } from './single-packet-splitter';
export class SinglePacketStoreLoader extends StepOperations {
    constructor(steps, 
    // public readonly crc: number,
    singlePacketService) {
        super(StepOperations.createSequentialContainers(steps));
        this.singlePacketService = singlePacketService;
    }
    static createOperationsFromBytes(data, singlePacketService, options) {
        const chunkSize = (options === null || options === void 0 ? void 0 : options.chunkSize) || SinglePacketBuilder.MAX_PART_SIZE;
        const offsetFitsOn2Bytes = data.length / chunkSize <= 0xffff;
        const singlePacketSplitter = new SinglePacketSplitter({
            chunkSize,
            format: offsetFitsOn2Bytes
                ? SinglePacketChunk.Format.OFFSET_ON_2_BYTES
                : SinglePacketChunk.Format.OFFSET_ON_4_BYTES,
            pad: options && 'pad' in options ? options.pad : true,
        });
        const packets = singlePacketSplitter.chunk(data);
        return SinglePacketStoreLoader.createOperationsFromChunk(packets, singlePacketService, options);
    }
    static createFromBytes(data, singlePacketService, options) {
        const steps = SinglePacketStoreLoader.createOperationsFromBytes(data, singlePacketService, options);
        return new SinglePacketStoreLoader(steps, 
        // expectedCRC,
        singlePacketService);
    }
    /**
     * Create single packet loading operations
     * @param packets Single packet chunks to load to the Tap
     * @param expectedCRC expected CRC sent to the Tap when executing the single packet. if you don't plan to execute single packet, you pass a dummy value
     * @param singlePacketService
     * @param options
     */
    static createOperationsFromChunk(packets, singlePacketService, options, output = {
        expectedCRC: 0,
    }) {
        output.expectedCRC = CRC.FIRST_VALUE;
        const operations = packets.map((packet, index) => {
            return (observer, context) => __awaiter(this, void 0, void 0, function* () {
                if (packet.data.length > SinglePacketBuilder.MAX_PART_SIZE) {
                    throw SinglePacketError.maxSinglePacketPartSizeExceeded(packet, SinglePacketBuilder.MAX_PART_SIZE);
                }
                debug('createSinglePacketLoadOperations', `sendSinglePacket`, `sending packet ${index + 1}/${packets.length} offset: ${packet.offset}...${packet.offset + (packet.length || 0)}`);
                let retryCount = 0;
                const maxRetry = (options === null || options === void 0 ? void 0 : options.maxRetry) || 3;
                output.expectedCRC = CRC.fromBytes(packet.data, output.expectedCRC);
                while (true) {
                    retryCount++;
                    // if (userIncrementalSinglePacketPart) {
                    // const call = { ...this.tap.service.singlePacket.resources.writeChunk };
                    // call.bodyEncoder = undefined;
                    // call.body = encodePartialSinglePacketBig(packet.data, packet.offset * this.singlePacketSplitter.options.sizeMultiplicator);
                    // response = await this.tap.lwm2m.execute(call);
                    const response = yield singlePacketService.writeChunk(packet);
                    // }
                    // else {
                    //     response = await singlePacketService.writeChunk(packet);
                    // }
                    if (retryCount < maxRetry &&
                        (response.status === ResultCode.SERVICE_UNAVAILABLE ||
                            response.status === ResultCode.NVM_ERROR)) {
                        debug('createSinglePacketLoadOperations', `Attempt ${retryCount + 1}/${maxRetry} failed with error ${TapError.reponseStatusError(response).toString()}`);
                        yield sleep((options === null || options === void 0 ? void 0 : options.retryDelay) || 500);
                        continue;
                    }
                    response.successful();
                    observer.next({
                        step: SinglePacketStoreLoader.Step.loadPacketChunk,
                        progress: {
                            total: packets.length,
                            loaded: index + 1,
                        },
                    });
                    return;
                }
                // debug(TAG, `sendSinglePacket`, `Packet ${index + 1}/${packets.length} SENT!`);
            });
        });
        if (options === null || options === void 0 ? void 0 : options.execute) {
            operations.push((observer, context) => __awaiter(this, void 0, void 0, function* () {
                observer.next({
                    step: SinglePacketStoreLoader.Step.executeSinglePacket,
                    expectedCRC: output.expectedCRC,
                });
                (yield singlePacketService.executeSinglePacketInStore(output.expectedCRC)).successful();
            }));
        }
        return operations;
    }
    static createFromChunks(packets, singlePacketService, options) {
        return new SinglePacketStoreLoader(SinglePacketStoreLoader.createOperationsFromChunk(packets, singlePacketService, options), singlePacketService);
    }
    static computeCRC(data) {
        if (data instanceof Uint8Array) {
            return CRC.mpeg2().compute(data);
        }
        else {
            return data.reduce((crc, packet) => {
                return CRC.mpeg2().compute(packet.data, crc);
            }, CRC.FIRST_VALUE);
        }
    }
}
(function (SinglePacketStoreLoader) {
    let Step;
    (function (Step) {
        Step["loadPacketChunk"] = "loadPacketChunk";
        Step["executeSinglePacket"] = "executeSinglePacket";
    })(Step = SinglePacketStoreLoader.Step || (SinglePacketStoreLoader.Step = {}));
})(SinglePacketStoreLoader || (SinglePacketStoreLoader = {}));
//# sourceMappingURL=data:application/json;base64, 