import api from '@iotize/device-client.js/protocol/api';
import rxjs from 'rxjs';
import common from '@iotize/common';
import promise from '@iotize/common/promise';
import rxjs$1 from '@iotize/common/rxjs';
import taskManager from '@iotize/common/task-manager';

var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};

function commonjsRequire () {
	throw new Error('Dynamic requires are not currently supported by rollup-plugin-commonjs');
}

function unwrapExports (x) {
	return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}

function createCommonjsModule(fn, module) {
	return module = { exports: {} }, fn(module, module.exports), module.exports;
}

function getCjsExportFromNamespace (n) {
	return n && n['default'] || n;
}

var debug = createCommonjsModule(function (module, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

const prefix = '@iotize:device-client.js:protocol/common';
exports.debug = common.createDebugger(prefix);

});

var debug$1 = unwrapExports(debug);
var debug_1 = debug.debug;

var abstractComProtocol = createCommonjsModule(function (module, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });



const TAG = 'ComProtocol';
class AbstractComProtocol {
    constructor() {
        this.connectionState = api.ConnectionState.DISCONNECTED;
        this._options = {
            connect: {
                timeout: 1000
            },
            disconnect: {
                timeout: 1000
            },
            send: {
                timeout: 500
            }
        };
    }
    get options() {
        return this._options;
    }
    set options(options) {
        this._options = options;
    }
    getConnectionState() {
        return this.connectionState;
    }
    isConnected() {
        return this.connectionState == api.ConnectionState.CONNECTED;
    }
    setConnectionState(connectionState) {
        debug.debug(TAG, 'setConnectionState', connectionState, 'Old: ', this.connectionState);
        let event = {
            newState: connectionState,
            oldState: this.connectionState
        };
        this.connectionState = connectionState;
        if (this._connectionStateChange) {
            this._connectionStateChange.next(event);
        }
        return this;
    }
    /**
     * Must be implemented in childs
     */
    receiveStream() {
        throw new Error('Method not implemented.');
    }
    onConnectionStateChange() {
        if (!this._connectionStateChange) {
            this._connectionStateChange = new rxjs.Subject();
        }
        return this._connectionStateChange;
    }
}
exports.AbstractComProtocol = AbstractComProtocol;

});

var abstractComProtocol$1 = unwrapExports(abstractComProtocol);
var abstractComProtocol_1 = abstractComProtocol.AbstractComProtocol;

var queueComProtocol = createCommonjsModule(function (module, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });







const TAG = 'ComProtocol';
/**
 *
 */
class QueueComProtocol extends abstractComProtocol.AbstractComProtocol {
    constructor() {
        super();
        this._jobQueue = new taskManager.TaskQueue();
    }
    _send(data, options) {
        try {
            if (!this.isConnected()) {
                let error = api.ComProtocol.Errors.notConnected({
                    protocol: this
                });
                return rxjs.throwError(error);
            }
            let startTime = new Date();
            return rxjs.from(promise.promiseTimeout(options.timeout, this.write(data), info => {
                return api.ComProtocol.Errors.timeoutError({
                    msg: `Communication timeout. Send request to device device timeout (${info.timeout}ms).`,
                    protocol: this,
                    timeout: info.timeout,
                    startTime: info.startTime
                });
            }).then(() => {
                let elapsedTime = new Date().getTime() - startTime.getTime();
                let newTimeout = options.timeout - elapsedTime;
                return promise.promiseTimeout(newTimeout, this.read(), info => {
                    return api.ComProtocol.Errors.timeoutError({
                        msg: `Communication timeout. Read response from device timeout (${newTimeout}ms).`,
                        protocol: this,
                        timeout: newTimeout,
                        startTime: info.startTime
                    });
                });
            }));
        }
        catch (error) {
            return rxjs.throwError(error);
        }
    }
    /**
     * Cancel pending requests
     */
    cancel() {
        debug.debug(TAG, `Canceling operations`);
        this._jobQueue.cancelAll(api.ComProtocol.Errors.operationCanceled());
    }
    /**
     *
     * @param data
     * @param options
     */
    send(data, options) {
        // debug(TAG, `QueueComProtocol`, `::send() ENQUEUE request (${data.length} bytes) ${toHexString(data)}. Queue position: ${this._queue.size}`);
        if (true) {
            // Copy data ? TODO can be removed ?
            data = data.slice(0);
        }
        return this._jobQueue.addExecutor(() => {
            let timeout = options
                ? options.timeout
                : this._options.send.timeout;
            return this._send(data, {
                timeout: timeout
            });
        });
    }
    /**
     * Connect with timeout
     *
     * If connect has already been called or is in progress / no further action
     *
     * @param options
     */
    connect(options) {
        if (this.connectionState === api.ConnectionState.CONNECTED) {
            debug.debug(TAG, `QueueComProtocol is already connected`);
            return rxjs.of(null);
        }
        if (this.connectionState == api.ConnectionState.CONNECTING) {
            return this._connect$;
        }
        let connectTimeout = options
            ? options.timeout
            : this._options.connect.timeout;
        let startTime = new Date();
        this._connect$ = rxjs$1.timeoutObservable(this._connect(options), connectTimeout, (err) => {
            return api.ComProtocol.Errors.timeoutError({
                msg: 'Protocol connection timeout',
                protocol: this,
                timeout: connectTimeout,
                startTime: startTime
            });
        });
        this.setConnectionState(api.ConnectionState.CONNECTING);
        this._connectionSubscription = this._connect$.subscribe(() => {
            this.setConnectionState(api.ConnectionState.CONNECTED);
        }, error => {
            this.setConnectionState(api.ConnectionState.DISCONNECTED);
        });
        return this._connect$;
    }
    disconnect(options) {
        if (this.connectionState === api.ConnectionState.DISCONNECTED) {
            return rxjs.of(null);
        }
        if (this.connectionState == api.ConnectionState.DISCONNECTING) {
            return this._disconnect$;
        }
        this._connect$ = undefined;
        let disconnectTimeout = options
            ? options.timeout
            : this._options.disconnect.timeout;
        let startTime = new Date();
        this._disconnect$ = rxjs$1.timeoutObservable(this._disconnect(options), disconnectTimeout, (err) => {
            return api.ComProtocol.Errors.timeoutError({
                msg: 'Protocol disconnection timeout',
                protocol: this,
                timeout: disconnectTimeout,
                startTime: startTime
            });
        });
        this.setConnectionState(api.ConnectionState.DISCONNECTING);
        this._disconnect$.subscribe(() => {
            this.setConnectionState(api.ConnectionState.DISCONNECTED);
        }, error => {
            this.setConnectionState(api.ConnectionState.DISCONNECTED);
        });
        return this._disconnect$;
    }
}
exports.QueueComProtocol = QueueComProtocol;

});

var queueComProtocol$1 = unwrapExports(queueComProtocol);
var queueComProtocol_1 = queueComProtocol.QueueComProtocol;

var public_api = createCommonjsModule(function (module, exports) {
"use strict";
function __export(m) {
    for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(abstractComProtocol);
__export(queueComProtocol);

});

var public_api$1 = unwrapExports(public_api);

var iotizeDeviceClient_jsProtocolCore = createCommonjsModule(function (module, exports) {
"use strict";
/**
 * Generated bundle index. Do not edit.
 */
function __export(m) {
    for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
__export(public_api);

});

var iotizeDeviceClient_jsProtocolCore$1 = unwrapExports(iotizeDeviceClient_jsProtocolCore);

export default iotizeDeviceClient_jsProtocolCore$1;
//# sourceMappingURL=iotize-device-client.js-protocol-core.js.map
