(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core'), require('@angular-ru/cdk/utils'), require('rxjs'), require('rxjs/operators'), require('rxjs/webSocket')) :
    typeof define === 'function' && define.amd ? define('@angular-ru/cdk/websocket', ['exports', '@angular/core', '@angular-ru/cdk/utils', 'rxjs', 'rxjs/operators', 'rxjs/webSocket'], factory) :
    (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global['angular-ru'] = global['angular-ru'] || {}, global['angular-ru'].cdk = global['angular-ru'].cdk || {}, global['angular-ru'].cdk.websocket = {}), global.ng.core, global['angular-ru'].cdk.utils, global.rxjs, global.rxjs.operators, global.rxjs.webSocket));
}(this, (function (exports, i0, utils, rxjs, operators, webSocket) { 'use strict';

    function _interopNamespace(e) {
        if (e && e.__esModule) return e;
        var n = Object.create(null);
        if (e) {
            Object.keys(e).forEach(function (k) {
                if (k !== 'default') {
                    var d = Object.getOwnPropertyDescriptor(e, k);
                    Object.defineProperty(n, k, d.get ? d : {
                        enumerable: true,
                        get: function () {
                            return e[k];
                        }
                    });
                }
            });
        }
        n['default'] = e;
        return Object.freeze(n);
    }

    var i0__namespace = /*#__PURE__*/_interopNamespace(i0);

    var WebsocketConfig = /** @class */ (function () {
        function WebsocketConfig() {
            this.reconnectionDelay = 2000;
            this.binaryType = 'arraybuffer';
        }
        return WebsocketConfig;
    }());
    /** @nocollapse */ /** @nocollapse */ WebsocketConfig.ɵfac = function WebsocketConfig_Factory(t) { return new (t || WebsocketConfig)(); };
    /** @nocollapse */ /** @nocollapse */ WebsocketConfig.ɵprov = /** @pureOrBreakMyCode */ i0__namespace.ɵɵdefineInjectable({ token: WebsocketConfig, factory: WebsocketConfig.ɵfac });
    (function () {
        (typeof ngDevMode === "undefined" || ngDevMode) && i0__namespace.ɵsetClassMetadata(WebsocketConfig, [{
                type: i0.Injectable
            }], null, null);
    })();

    var PLAIN_TEXT = {};
    var BINARY = {};
    var AbstractWebsocketClient = /** @class */ (function () {
        function AbstractWebsocketClient(wsConfig, ngZone) {
            this.wsConfig = wsConfig;
            this.ngZone = ngZone;
            this.connected = false;
            this.messages$ = new rxjs.Subject();
            this.connected$ = new rxjs.ReplaySubject(Number.POSITIVE_INFINITY);
            this.disconnected$ = new rxjs.ReplaySubject(Number.POSITIVE_INFINITY);
            this.destroy$ = new rxjs.Subject();
        }
        Object.defineProperty(AbstractWebsocketClient.prototype, "isConnected", {
            get: function () {
                return this.connected;
            },
            enumerable: false,
            configurable: true
        });
        Object.defineProperty(AbstractWebsocketClient.prototype, "isDisconnected", {
            get: function () {
                return !this.connected;
            },
            enumerable: false,
            configurable: true
        });
        Object.defineProperty(AbstractWebsocketClient.prototype, "connectionPath", {
            get: function () {
                return "" + this.baseUrl + this.handlerPath;
            },
            enumerable: false,
            configurable: true
        });
        Object.defineProperty(AbstractWebsocketClient.prototype, "webSocketSubjectConfig", {
            get: function () {
                var _this = this;
                return {
                    openObserver: { next: function (event) { return _this.onOpenObserver(event); } },
                    closeObserver: { next: function (event) { return _this.onCloseObserver(event); } },
                    serializer: function (message) { return _this.serialize(message); },
                    deserializer: function (event) { return _this.deserialize(event); },
                    url: this.connectionPath,
                    binaryType: this.wsConfig.binaryType
                };
            },
            enumerable: false,
            configurable: true
        });
        AbstractWebsocketClient.isArrayBuffer = function (value) {
            return value instanceof ArrayBuffer || value instanceof Blob;
        };
        AbstractWebsocketClient.prototype.onConnected = function (_event) {
            // noop
        };
        AbstractWebsocketClient.prototype.onDisconnected = function (_event) {
            // noop
        };
        AbstractWebsocketClient.prototype.connect = function (path) {
            var _this = this;
            this.handlerPath = path;
            this.ngZone.runOutsideAngular(function () { return _this._connect(); });
            this.destroy$ = new rxjs.Subject();
        };
        AbstractWebsocketClient.prototype.disconnect = function () {
            var _a, _b;
            (_a = this.socketSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
            (_b = this.socket$) === null || _b === void 0 ? void 0 : _b.complete();
            this.destroy$.next(true);
            this.destroy$.complete();
        };
        AbstractWebsocketClient.prototype.on = function (type) {
            return this.messages$.pipe(operators.filter(function (message) { return message.type === type; }), operators.map(function (message) { return message.data; }), operators.catchError(function (err) { return rxjs.throwError(function () { return err; }); }), operators.takeUntil(this.destroy$));
        };
        AbstractWebsocketClient.prototype.single = function (type) {
            return this.on(type).pipe(operators.take(1));
        };
        AbstractWebsocketClient.prototype.sendMessage = function (type, data) {
            var _a;
            (_a = this.socket$) === null || _a === void 0 ? void 0 : _a.next({ type: type, data: data });
        };
        AbstractWebsocketClient.prototype.ngOnDestroy = function () {
            this.disconnect();
        };
        AbstractWebsocketClient.prototype.serialize = function (message) {
            switch (message.type) {
                case BINARY:
                case PLAIN_TEXT:
                    return message.data;
                default:
                    return JSON.stringify(message);
            }
        };
        AbstractWebsocketClient.prototype.deserialize = function (_c) {
            var data = _c.data;
            var _a;
            if (AbstractWebsocketClient.isArrayBuffer(data)) {
                return { type: BINARY, data: data };
            }
            else {
                return (_a = utils.tryParseJson(data)) !== null && _a !== void 0 ? _a : { type: PLAIN_TEXT, data: data };
            }
        };
        AbstractWebsocketClient.prototype.onOpenObserver = function (event) {
            this.connected = true;
            this.connected$.next(event);
            this.onConnected(event);
        };
        AbstractWebsocketClient.prototype.onCloseObserver = function (event) {
            this.connected = false;
            this.disconnected$.next(event);
            this.onDisconnected(event);
        };
        AbstractWebsocketClient.prototype._connect = function () {
            var _this = this;
            this.socket$ = webSocket.webSocket(this.webSocketSubjectConfig);
            this.socketSubscription = this.socket$.pipe(operators.takeUntil(this.destroy$)).subscribe({
                next: function (message) {
                    window.requestAnimationFrame(function () { return _this.messages$.next(message); });
                },
                error: function () { return _this.reconnect(); }
            });
        };
        AbstractWebsocketClient.prototype.reconnect = function () {
            var _this = this;
            this.completeStoppedSocket();
            this.socketUnsubscribe();
            this.ngZone.runOutsideAngular(function () {
                // eslint-disable-next-line no-restricted-properties
                window.setTimeout(function () { return _this._connect(); }, _this.wsConfig.reconnectionDelay);
            });
        };
        AbstractWebsocketClient.prototype.completeStoppedSocket = function () {
            var _a, _b;
            // TODO: need replace isStopped
            // eslint-disable-next-line deprecation/deprecation
            if (utils.isFalsy((_a = this.socket$) === null || _a === void 0 ? void 0 : _a.isStopped)) {
                (_b = this.socket$) === null || _b === void 0 ? void 0 : _b.complete();
            }
        };
        AbstractWebsocketClient.prototype.socketUnsubscribe = function () {
            var _a, _b;
            if (utils.isFalsy((_a = this.socketSubscription) === null || _a === void 0 ? void 0 : _a.closed)) {
                (_b = this.socketSubscription) === null || _b === void 0 ? void 0 : _b.unsubscribe();
            }
        };
        return AbstractWebsocketClient;
    }());
    /** @nocollapse */ /** @nocollapse */ AbstractWebsocketClient.ɵfac = function AbstractWebsocketClient_Factory(t) { return new (t || AbstractWebsocketClient)(i0__namespace.ɵɵinject(WebsocketConfig), i0__namespace.ɵɵinject(i0__namespace.NgZone)); };
    /** @nocollapse */ /** @nocollapse */ AbstractWebsocketClient.ɵprov = /** @pureOrBreakMyCode */ i0__namespace.ɵɵdefineInjectable({ token: AbstractWebsocketClient, factory: AbstractWebsocketClient.ɵfac });
    (function () {
        (typeof ngDevMode === "undefined" || ngDevMode) && i0__namespace.ɵsetClassMetadata(AbstractWebsocketClient, [{
                type: i0.Injectable
            }], function () { return [{ type: WebsocketConfig }, { type: i0__namespace.NgZone }]; }, null);
    })();

    var WEBSOCKET_CONFIGS = new i0.InjectionToken('WEBSOCKET_CONFIGS');

    var WebsocketModule = /** @class */ (function () {
        function WebsocketModule() {
        }
        WebsocketModule.forRoot = function (config) {
            if (config === void 0) { config = {}; }
            return {
                ngModule: WebsocketModule,
                providers: [
                    {
                        provide: WEBSOCKET_CONFIGS,
                        useValue: config
                    },
                    {
                        provide: WebsocketConfig,
                        useFactory: WebsocketModule.configFactory,
                        deps: [WEBSOCKET_CONFIGS]
                    }
                ]
            };
        };
        WebsocketModule.configFactory = function (options) {
            return Object.assign(Object.assign({}, new WebsocketConfig()), options);
        };
        return WebsocketModule;
    }());
    /** @nocollapse */ /** @nocollapse */ WebsocketModule.ɵfac = function WebsocketModule_Factory(t) { return new (t || WebsocketModule)(); };
    /** @nocollapse */ /** @nocollapse */ WebsocketModule.ɵmod = /** @pureOrBreakMyCode */ i0__namespace.ɵɵdefineNgModule({ type: WebsocketModule });
    /** @nocollapse */ /** @nocollapse */ WebsocketModule.ɵinj = /** @pureOrBreakMyCode */ i0__namespace.ɵɵdefineInjector({});
    (function () {
        (typeof ngDevMode === "undefined" || ngDevMode) && i0__namespace.ɵsetClassMetadata(WebsocketModule, [{
                type: i0.NgModule
            }], null, null);
    })();

    /**
     * Generated bundle index. Do not edit.
     */

    exports.AbstractWebsocketClient = AbstractWebsocketClient;
    exports.BINARY = BINARY;
    exports.PLAIN_TEXT = PLAIN_TEXT;
    exports.WEBSOCKET_CONFIGS = WEBSOCKET_CONFIGS;
    exports.WebsocketConfig = WebsocketConfig;
    exports.WebsocketModule = WebsocketModule;

    Object.defineProperty(exports, '__esModule', { value: true });

})));
//# sourceMappingURL=angular-ru-cdk-websocket.umd.js.map
