var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
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());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
import { bufferToHexString } from '@iotize/common/byte-converter';
import { promiseSerial } from '@iotize/common/promise';
import { QueueComProtocol } from '@iotize/tap/protocol/core';
import { BleConfig } from './ble-config';
import { BLEPacketBuilder } from './ble-packet-builder';
import { BLEPacketSplitter } from './ble-packet-splitter';
import { debug } from './debug';
import { InvalidBleFrameChecksum } from './errors';
/**
 * @deprecated use UniversalBleProtocolAdpater
 * Abstract class for BLE communication
 *
 * With ble communication, data is split into sub packets.
 * This class handles creation of packet chunks.
 *
 * - You must only implement the function to send one packet chunk writeLwm2mPacketChunk()
 * -
 */
var AbstractBleProtocol = /** @class */ (function (_super) {
    __extends(AbstractBleProtocol, _super);
    function AbstractBleProtocol(bleOptions) {
        if (bleOptions === void 0) { bleOptions = { mtu: BleConfig.maxPacketLengthWithoutOffset + 1 }; }
        var _this = _super.call(this) || this;
        _this.bleOptions = bleOptions;
        return _this;
    }
    AbstractBleProtocol.prototype.onNewLwm2mMessage = function (data) {
        if (this._readResolve) {
            debug('onNewLwm2mMessage()', bufferToHexString(data));
            this._readResolve(data);
        }
        else {
            console.warn("No listener for new message... 0x" + bufferToHexString(data));
            this._pendingRead = data;
        }
    };
    AbstractBleProtocol.prototype.onNewLwm2mMessageError = function (err) {
        console.error("Error lwm2m response...", err);
    };
    AbstractBleProtocol.prototype.onLwm2mDataChunkError = function (error) {
        if (this._readReject) {
            this._readReject(error);
        }
        else {
            console.warn("No listener for read message error...", error);
        }
    };
    AbstractBleProtocol.prototype.getLwm2mResponsePromise = function () {
        debug('getLwm2mResponsePromise');
        if (this._pendingRead) {
            var data = this._pendingRead;
            this._pendingRead = undefined;
            return Promise.resolve(data);
        }
        if (!this._readPromise) {
            this.createLwm2mResponsePromise();
        }
        return this._readPromise;
    };
    AbstractBleProtocol.prototype.createLwm2mResponsePromise = function () {
        var _this = this;
        debug('createLwm2mResponsePromise');
        this._readPromise = new Promise(function (resolve, reject) {
            _this._readResolve = resolve;
            _this._readReject = reject;
        });
        return this._readPromise;
    };
    // send(data: Uint8Array): Observable<Uint8Array> {
    //     debug("BLEProtocol:send() " + bufferToHexString(data));
    //     return from(
    //         this
    //             .write(data)
    //             .then(() => this.waitForLwm2mResponse())
    //             .catch((err) => {
    //                 console.error("ERROR SEND " + err);
    //                 throw err;
    //             })
    //     );
    // }
    AbstractBleProtocol.prototype.read = function () {
        var _this = this;
        debug('read()...');
        if (this.packetBuilder) {
            if (this.packetBuilder.hasAllChunks()) {
                var data = this.packetBuilder.getData();
                this.packetBuilder = undefined;
                return Promise.resolve(data);
            }
            // TODO manage error
            console.warn("AbstractBleProtocol::read() There is already a read operation in progress but a new call to ::read has been made.");
        }
        return this
            .getLwm2mResponsePromise()
            .then(function (response) {
            _this.packetBuilder = undefined;
            return response;
        })
            .catch(function (err) {
            _this.packetBuilder = undefined;
            throw err;
        });
    };
    AbstractBleProtocol.prototype.write = function (data) {
        return __awaiter(this, void 0, void 0, function () {
            var packets, promise;
            var _this = this;
            return __generator(this, function (_a) {
                if (this.packetSplitter != null) {
                    console.warn('BLEProtocol', 'write', 'There are already data being sent but a new call to ::write has been made');
                }
                this.packetSplitter = BLEPacketSplitter.wrapWithChecksum(data, this.bleOptions.mtu - 1);
                packets = this.packetSplitter.getPackets();
                this._pendingRead = undefined;
                this.packetBuilder = new BLEPacketBuilder(AbstractBleProtocol.RECEIVED_BUFFER_LENGTH);
                if (packets.length > 0) {
                    // this.createLwm2mResponsePromise()
                    //     .catch((err) => {
                    //         this.onNewLwm2mMessageError(err);
                    //     })
                    promise = promiseSerial(packets, function (packet, index) {
                        return _this.writeLwm2mPacketChunk(packet).then(function (value) {
                            debug("Done sending packet " + (index + 1) + "/" + packets.length);
                            return value;
                        });
                    });
                    // packets.forEach((value: Uint8Array, index: number) => {
                    //     if (!promise){
                    //         promise = this.writeLwm2mPacketChunk(packets[index]);
                    //     }
                    //     else{
                    //         promise = promise.then(() => this.writeLwm2mPacketChunk(packets[index]))
                    //     }
                    //     // promise.then(() => {
                    //         // debug("BLEProtocol", "write", `Done sending packet ${index+1}/${packets.length}`);
                    //     // });
                    // });
                }
                else {
                    console.warn('BLEProtocol', 'write', "Nothing to write...");
                    promise = Promise.resolve();
                }
                return [2 /*return*/, promise
                        .then(function () {
                        _this.packetSplitter = undefined;
                    })
                        .catch(function (err) {
                        _this.packetSplitter = undefined;
                        throw err;
                    })];
            });
        });
    };
    /**
     *
     * @param data data chunk
     */
    AbstractBleProtocol.prototype.onNewLwm2mPacket = function (data) {
        if (!this.packetBuilder) {
            debug("Ignoring lwm2m packet 0x" + bufferToHexString(data) + " as not request has been made yet");
            return;
        }
        this.packetBuilder.append(data);
        if (this.packetBuilder.hasAllChunks()) {
            if (this.packetBuilder.isChecksumValid()) {
                this.onNewLwm2mMessage(this.packetBuilder.getData());
            }
            else {
                var error = InvalidBleFrameChecksum.create(this.packetBuilder);
                this.onLwm2mDataChunkError(error);
            }
        }
    };
    // TODO set an option instead ?
    AbstractBleProtocol.RECEIVED_BUFFER_LENGTH = 255;
    return AbstractBleProtocol;
}(QueueComProtocol));
export { AbstractBleProtocol };
//# sourceMappingURL=data:application/json;base64, 