import '@iotize/tap/service/impl/interface';
import { Subject } from 'rxjs';
import { tap } from 'rxjs/operators';
import { createDebugger } from '@iotize/common/debug';

const prefix = '@iotize/tap/keepalive';
const debug = createDebugger(prefix);

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());
    });
};
const DEFAULT_KEEP_ALIVE_PERIOD_MS = 5000;
const TAG = 'KeepAliveEngine';
class KeepAliveEngine {
    constructor(tap$1, _options) {
        this.tap = tap$1;
        this._options = _options;
        this._lastResponseTime = 0;
        this._isStopped = true;
        this._frameCounter = 0;
        this._events = new Subject();
        debug(TAG, 'new KeepAliveEngine()');
        this.tap.client.addInterceptor((req, handle) => {
            return handle.handle(req).pipe(tap({
                next: () => {
                    debug(TAG, 'update last response time', this._lastResponseTime, '=>', new Date().getTime());
                    this._lastResponseTime = new Date().getTime();
                },
            }));
        });
    }
    /**
     * Keep alive request count
     */
    get counter() {
        return this._frameCounter;
    }
    /**
     * returns event observable
     */
    get events() {
        return this._events.asObservable();
    }
    /**
     * Change keep alive period
     */
    set period(p) {
        if (typeof p !== 'number') {
            p = 0;
        }
        this._options.period = p;
        if (this._options.period <= 0) {
            this.clearTimeout();
        }
        else if (!this.timeoutId && this.running) {
            this._setupNextTimeout(0);
        }
    }
    get running() {
        return !this._isStopped;
    }
    get options() {
        return this._options;
    }
    start() {
        this._isStopped = false;
        if (!this.timeoutId && this.options.period > 0) {
            this._setupNextTimeout(0);
        }
        this._events.next({
            type: 'start',
        });
    }
    stop() {
        this._isStopped = true;
        this.clearTimeout();
        this._events.next({
            type: 'stop',
        });
    }
    clearTimeout() {
        if (this.timeoutId) {
            clearTimeout(this.timeoutId);
            this.timeoutId = undefined;
        }
    }
    _setupNextTimeout(timeoutMs) {
        if (this._isStopped) {
            return;
        }
        this._events.next({
            type: 'rescheduleKeepAlive',
            timeout: timeoutMs,
        });
        this.timeoutId = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
            if (this.tap.isConnected()) {
                const remainingTime = this._options.period - elapsedTime(this._lastResponseTime);
                if (remainingTime > 0) {
                    debug(TAG, 'Reschedule keep alive in ', remainingTime);
                    this._setupNextTimeout(remainingTime);
                }
                else {
                    debug(TAG, 'Running keep alive');
                    this._frameCounter++;
                    try {
                        this._events.next({
                            type: 'tick',
                        });
                        yield this.tap.service.interface.keepAlive();
                    }
                    catch (err) {
                        this._events.next({
                            type: 'error',
                            error: err,
                        });
                    }
                    if (this._options.period > 0) {
                        this._setupNextTimeout(this._options.period);
                    }
                }
            }
        }), timeoutMs);
    }
}
function elapsedTime(time) {
    return new Date().getTime() - time;
}

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

export { DEFAULT_KEEP_ALIVE_PERIOD_MS, KeepAliveEngine };
//# sourceMappingURL=iotize-tap-keep-alive.js.map
