﻿declare var baseUrl: string;

import { debugSettings } from "../debugsettings";
import { CancelToken } from "./cancelToken";
import { ConnectionWrapper } from "./connectionwrapper";
import { slowInternetService } from "./index";

export class ConnectionService {
    public static stateConversion = {
        0: "connecting",
        1: "connected",
        2: "reconnecting",
        4: "disconnected",
    };
    public isStopped: boolean;
    public isDisconnected: boolean;
    public isConnected: boolean;
    public connectionSlow: Signal;
    public reconnecting: Signal;
    public reconnected: Signal;
    public received: Signal;
    public disconnected: Signal;
    public recoverableError = new signals.Signal();
    public newConnection = new signals.Signal();
    public terminatedConnection = new signals.Signal();
    public attempts = 0;
    public lastAttempt = 0;
    public currentConnection: ConnectionWrapper = null;
    private lastConnection: JQueryDeferred<any> = null;
    private cancelCurrentConnection: (reason: string) => void | null = null;

    constructor() {
        this.connectionSlow = new signals.Signal();
        this.reconnecting = new signals.Signal();
        this.reconnected = new signals.Signal();
        this.received = new signals.Signal();
        this.disconnected = new signals.Signal();
    }
    public initializeConnection() {
        if (this.currentConnection !== null) {
            return;
        }

        const connection = $.hubConnection(baseUrl);
        connection.logging = $.connection.hub.logging;
        if (authToken == null) {
            connection.qs = null;
        } else {
            connection.qs = { token: authToken };
        }

        this.isDisconnected = true;
        this.currentConnection = new ConnectionWrapper(connection);
        $.extend(connection, connection.createHubProxies());
        this.newConnection.dispatch(this.currentConnection);
    }
    public terminateConnection(forceDisconnect = false) {
        this.isStopped = true;
        this.isDisconnected = true;
        slowInternetService.manualDisconnect = true;

        if (this.currentConnection == null) {
            this.logEvent("No active connection to terminate");
            return;
        }

        let hubId: string;
        if (this.currentConnection.connection == null) {
            hubId = this.currentConnection.connection.id;
        } else {
            hubId = "NULL";
        }

        const connectionInfo = "HID:" + hubId;
        this.logEvent("Terminating connection " + connectionInfo);
        const oldConnection = this.currentConnection;
        this.currentConnection.terminateConnection();
        this.currentConnection = null;
        this.terminatedConnection.dispatch(oldConnection);
    }
    public establishConnection(maxAttempts = 3) {
        const attempts = this.attempts++;
        this.lastAttempt = attempts;
        this.cancelConnection();
        const result = this.currentConnection.establishConnection(maxAttempts);
        this.lastConnection = result;
        return result;
    }
    public async establishConnectionAsync(maxAttempts = 3) {
        const attempts = this.attempts++;
        this.lastAttempt = attempts;
        this.cancelConnection();
        const cancelToken = CancelToken.source();
        this.cancelCurrentConnection = cancelToken.cancel;
        const result = await this.currentConnection.establishConnectionAsync(maxAttempts, cancelToken.token);
        return result;
    }
    public cancelConnection() {
        if (this.lastConnection !== null && this.lastConnection.state() === "pending") {
            this.lastConnection.notify("cancel");
            this.lastConnection = null;
        }

        if (this.cancelCurrentConnection !== null) {
            this.cancelCurrentConnection("Requested connection cancel");
        }
    }
    public buildStartConnection() {
        if (this.currentConnection === null) {
            this.logEvent("No active connection to terminate");
            return null;
        }

        return this.currentConnection.buildStartConnection();
    }
    public async buildStartConnectionAsync() {
        if (this.currentConnection === null) {
            this.logEvent("No active connection to terminate");
            return null;
        }

        return await this.currentConnection.buildStartConnectionAsync();
    }
    private logEvent(message: string, ...params: any[]) {
        if (debugSettings.connection.signalR) {
            // tslint:disable-next-line:no-console
            console.log(message, params);
        }
    }
}
