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 '@iotize/tap/auth';
import '@iotize/tap/service/impl/single-packet';
import { retryWithDelay } from '@iotize/common/rxjs';
import { StepOperations } from '@iotize/common/task-manager';
import { ComProtocol } from '@iotize/tap/protocol/api';
import { SinglePacketStoreInfo, SinglePacketStoreLoader, } from '@iotize/tap/service/impl/single-packet';
import { defer } from 'rxjs';
import { map } from 'rxjs/operators';
export class TapNLinkUpdater extends StepOperations {
    constructor(steps, options = {}) {
        super(StepOperations.createSequentialContainers(steps));
        this.options = options;
    }
    static create(tap, firmwareUpdateData, options = TapNLinkUpdater.DEFAULT_OPTIONS) {
        if (!options.loader) {
            options.loader = TapNLinkUpdater.DEFAULT_OPTIONS.loader;
        }
        const loadFirmwareUpdateOperations = SinglePacketStoreLoader.createOperationsFromBytes(firmwareUpdateData, tap.service.singlePacket, options.loader);
        const expectedCRC = SinglePacketStoreLoader.computeCRC(firmwareUpdateData);
        const operations = [
            (observer, context) => __awaiter(this, void 0, void 0, function* () {
                observer.next({
                    step: 'setup',
                });
                if (!tap.encryption.isStarted) {
                    yield tap.encryption.start();
                }
            }),
            ...loadFirmwareUpdateOperations,
            // singlePacketStoreLoader
            //     .asObservable()
            //     .pipe(
            //         map<SinglePacketStoreLoader.Event, TapNLinkUpdater.Progress>(
            //             (progress: SinglePacketStoreLoader.Event, index: number) => {
            //                 return {
            //                     step: 'load',
            //                     payload: progress
            //                 };
            //             }
            //         )
            //     ),
            (observer, context) => __awaiter(this, void 0, void 0, function* () {
                var _a;
                try {
                    observer.next({
                        step: 'apply',
                    });
                    (yield tap.service.singlePacket.executeSinglePacketInStore(expectedCRC)).successful();
                    observer.next({
                        step: 'finish',
                        executeRequestTimeout: false,
                    });
                }
                catch (err) {
                    // Fix for old firmware that do not respond to execute command
                    if (((_a = err === null || err === void 0 ? void 0 : err.cause) === null || _a === void 0 ? void 0 : _a.code) === ComProtocol.ErrorCode.TimeoutError) {
                        observer.next({
                            step: 'finish',
                            executeRequestTimeout: true,
                        });
                        return;
                    }
                    throw err;
                }
            }),
        ];
        if (options.reconnectAfterUpdate) {
            operations.push(TapNLinkUpdater.waitingForReconnection(tap, options));
        }
        return new TapNLinkUpdater(operations, options);
    }
    // public start(
    //     firmwareUpdateData: Uint8Array
    // ): Observable<TapNLinkUpdater.Progress> {
    //     // const singlePacketStoreLoader = tap.service.singlePacket
    //     //     .createStoreLoaderFromBytes(firmwareUpdateData);
    // }
    isFirmwareUpdateAvailable(tap) {
        return __awaiter(this, void 0, void 0, function* () {
            const info = (yield tap.service.singlePacket.getInfo()).body();
            return info.state === SinglePacketStoreInfo.State.EMPTY;
        });
    }
    static waitingForReconnection(tap, options) {
        const maxRetry = (options === null || options === void 0 ? void 0 : options.reconnectRetryCount) === undefined
            ? TapNLinkUpdater.DEFAULT_OPTIONS.reconnectRetryCount
            : options.reconnectRetryCount;
        return retryWithDelay(defer(() => tap.connect()), {
            delay: (options === null || options === void 0 ? void 0 : options.reconnectRetryDelay) === undefined
                ? TapNLinkUpdater.DEFAULT_OPTIONS.reconnectRetryDelay
                : options.reconnectRetryDelay,
            retryCount: maxRetry,
        }).pipe(map((v, index) => {
            return {
                step: 'restart',
                attempt: index + 1,
                maxRetry,
                message: `Tap reconnection attempt n°${index + 1}/${maxRetry + 1}`,
            };
        }));
    }
}
(function (TapNLinkUpdater) {
    TapNLinkUpdater.DEFAULT_OPTIONS = {
        reconnectAfterUpdate: true,
        reconnectRetryCount: 5,
        reconnectRetryDelay: 5000,
        loader: {
            execute: false,
            maxRetry: 10,
            retryDelay: 1000,
        },
    };
})(TapNLinkUpdater || (TapNLinkUpdater = {}));
//# sourceMappingURL=data:application/json;base64, 