/*
 * Copyright 2015-present Open Networking Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { Injectable, Inject } from '@angular/core';
import { FnService } from '../util/fn.service';
import { GlyphService } from '../svg/glyph.service';
import { LogService } from '../../log.service';
import { UrlFnService } from './urlfn.service';
import { VeilComponent } from '../layer/veil/veil.component';
import { WSock } from './wsock.service';

/**
 * Event Type structure for the WebSocketService
 */
export interface EventType {
    event: string;
    payload: Object;
}

export interface Callback {
    id: number;
    error: string;
    cb(host: string, url: string): void;
}

interface ClusterNode {
    id: string;
    ip: string;
    m_uiAttached: boolean;
}

interface Bootstrap {
    user: string;
    clusterNodes: ClusterNode[];
    glyphs: any[]; // TODO: narrow this down to a known type
}

interface ErrorData {
    message: string;
}

export interface WsOptions {
    wsport: number;
}

/**
 * ONOS GUI -- Remote -- Web Socket Service
 *
 * To see debug messages add ?debug=txrx to the URL
 */
@Injectable({
  providedIn: 'root',
})
export class WebSocketService {
    // internal state
    private webSockOpts: WsOptions; // web socket options
    private ws: WebSocket = null; // web socket reference
    private wsUp: boolean = false; // web socket is good to go

    // A map of event handler bindings - names and functions (that accept data and return void)
    private handlers = new Map<string, (data: any) => void>([]);
    private pendingEvents: EventType[] = []; // events TX'd while socket not up
    private host: string; // web socket host
    private url; // web socket URL
    private clusterNodes: ClusterNode[] = []; // ONOS instances data for failover
    private clusterIndex = -1; // the instance to which we are connected
    private glyphs = [];
    private connectRetries: number = 0; // limit our attempts at reconnecting

    // A map of registered Callbacks for websocket open()
    private openListeners = new Map<number, Callback>([]);
    private nextListenerId: number = 1; // internal ID for open listeners
    private loggedInUser = null; // name of logged-in user
    private lcd: any; // The loading component delegate
    private vcd: any; // The veil component delegate

    /**
     * built-in handler for the 'boostrap' event
     */
    private bootstrap(data: Bootstrap) {
        this.loggedInUser = data.user;

        this.clusterNodes = data.clusterNodes;
        this.clusterNodes.forEach((d, i) => {
            if (d.m_uiAttached) {
                this.clusterIndex = i;
                this.log.info('Connected to cluster node ' + d.ip);
                // TODO: add connect info to masthead somewhere
            }
        });
        this.glyphs = data.glyphs;
        const glyphsMap = new Map<string, string>([]);
        this.glyphs.forEach((d, i) => {
            glyphsMap.set('_' + d.id, d.viewbox);
            glyphsMap.set(d.id, d.path);
            this.gs.registerGlyphs(glyphsMap);
        });
    }

    private error(data: ErrorData) {
        const m: string = data.message || 'error from server';
        this.log.error(m, data);

        // Unrecoverable error - throw up the veil...
        if (this.vcd) {
            this.vcd.show([
                'Oops!',
                'Server reports error...',
                m,
            ]);
        }
    }

    constructor(
        private fs: FnService,
        private gs: GlyphService,
        private log: LogService,
        private ufs: UrlFnService,
        private wsock: WSock,
        @Inject('Window') private window: Window
    ) {
        this.log.debug(window.location.hostname);

        // Bind the boot strap event by default
        this.bindHandlers(new Map<string, (data) => void>([
            ['bootstrap', (data) => this.bootstrap(data)],
            ['error', (data) => this.error(data)]
        ]));

        this.log.debug('WebSocketService constructed');
    }


    // ==========================
    // === Web socket callbacks

    /**
     * Called when WebSocket has just opened
     *
     * Lift the Veil if it is displayed
     * If there are any events pending, send them
     * Mark the WSS as up and inform any listeners for this open event
     */
    handleOpen(): void {
        this.log.info('Web socket open - ', this.url);
        // Hide the veil
        if (this.vcd) {
            this.vcd.hide();
        }

        if (this.fs.debugOn('txrx')) {
            this.log.debug('Sending ' + this.pendingEvents.length + ' pending event(s)...');
        }
        this.pendingEvents.forEach((ev) => {
            this.send(ev);
        });
        this.pendingEvents = [];

        this.connectRetries = 0;
        this.wsUp = true;
        this.informListeners(this.host, this.url);
    }

    /**
     * Function called when WebSocket send a message
     */
    handleMessage(msgEvent: MessageEvent): void {
        let ev: EventType;
        let h;
        try {
            ev = JSON.parse(msgEvent.data);
        } catch (e) {
            this.log.error('Message.data is not valid JSON', msgEvent.data, e);
            return null;
        }
        if (this.fs.debugOn('txrx')) {
            this.log.debug(' << *Rx* ', ev.event, ev.payload);
        }
        h = this.handlers.get(ev.event);
        if (h) {
            try {
                h(ev.payload);
            } catch (e) {
                this.log.error('Problem handling event:', ev, e);
                return null;
            }
        } else {
            this.log.warn('Unhandled event:', ev);
        }
    }

    /**
     * Called by the WebSocket if it is closed from the server end
     *
     * If the loading component is shown, call stop() on it
     * Try to find another node in the cluster to connect to
     * If this is not possible then show the Veil Component
     */
    handleClose(): void {
        this.log.warn('Web socket closed');
        if (this.lcd) {
            this.lcd.stop();
        }
        this.wsUp = false;
        let gsucc;

        if (gsucc = this.findGuiSuccessor()) {
            this.url = this.createWebSocket(this.webSockOpts, gsucc);
        } else {
            // If no controllers left to contact, show the Veil...
            if (this.vcd) {
                this.vcd.show([
                    'Oops!',  // TODO: Localize this
                    'Web-socket connection to server closed...',
                    'Try refreshing the page.',
                ]);
            }
        }
    }

    // ==============================
    // === Private Helper Functions

    /**
     * Find the next node in the ONOS cluster.
     *
     * This is used if the WebSocket connection closes because a
     * node in the cluster ges down - fail over should be automatic
     */
    findGuiSuccessor(): string {
        const ncn = this.clusterNodes.length;
        let ip: string;
        let node;

        while (this.connectRetries < ncn && !ip) {
            this.connectRetries++;
            this.clusterIndex = (this.clusterIndex + 1) % ncn;
            node = this.clusterNodes[this.clusterIndex];
            ip = node && node.ip;
        }

        return ip;
    }

    /**
     * When the WebSocket is opened, inform any listeners that registered
     * for that event
     */
    informListeners(host: string, url: string): void {
        for (const [key, cb] of this.openListeners.entries()) {
            cb.cb(host, url);
        }
    }

    send(ev: EventType): void {
        if (this.fs.debugOn('txrx')) {
            this.log.debug(' *Tx* >> ', ev.event, ev.payload);
        }
        this.ws.send(JSON.stringify(ev));
    }

    /**
     * Check if there are no WSS event handlers left
     */
    noHandlersWarn(handlers: Map<string, Object>, caller: string): boolean {
        if (!handlers || handlers.size === 0) {
            this.log.warn('WSS.' + caller + '(): no event handlers');
            return true;
        }
        return false;
    }

    /* ===================
     * === API Functions
     */

    /**
     * Required for unit tests to set to known state
     */
    resetState(): void {
        this.webSockOpts = undefined;
        this.ws = null;
        this.wsUp = false;
        this.host = undefined;
        this.url = undefined;
        this.pendingEvents = [];
        this.handlers.clear();
        this.clusterNodes = [];
        this.clusterIndex = -1;
        this.glyphs = [];
        this.connectRetries = 0;
        this.openListeners.clear();
        this.nextListenerId = 1;

    }

    /*
     * Currently supported opts:
     *  wsport: web socket port (other than default 8181)
     *  host:   if defined, is the host address to use
     */
    createWebSocket(opts?: WsOptions, host?: string) {
        this.webSockOpts = opts; // preserved for future calls
        this.host = host === undefined ? this.window.location.host : host;
        this.url = this.ufs.wsUrl('core', opts === undefined ? '' : opts['wsport'].toString(), host);

        this.log.debug('Attempting to open websocket to: ' + this.url);
        this.ws = this.wsock.newWebSocket(this.url);
        if (this.ws) {
            // fat arrow => syntax means that the 'this' context passed will
            // be of WebSocketService, not the WebSocket
            this.ws.onopen = (() => this.handleOpen());
            this.ws.onmessage = ((msgEvent) => this.handleMessage(msgEvent));
            this.ws.onclose = (() => this.handleClose());

            this.sendEvent('authentication token', { token: 'testAuth' });
        }
        // Note: Wsock logs an error if the new WebSocket call fails
        return this.url;
    }

    /**
     * Tell the WebSocket to close - this should call the handleClose() method
     */
    closeWebSocket() {
        this.ws.close();
    }


    /**
     * Binds the message handlers to their message type (event type) as
     *  specified in the given map. Note that keys are the event IDs; values
     *  are either:
     *     * the event handler function, or
     *     * an API object which has an event handler for the key
     */
    bindHandlers(handlerMap: Map<string, (data) => void>): void {
        const dups: string[] = [];

        if (this.noHandlersWarn(handlerMap, 'bindHandlers')) {
            return null;
        }
        for (const [eventId, api] of handlerMap) {
            this.log.debug('Adding handler for ', eventId);
            const fn = this.fs.isF(api) || this.fs.isF(api[eventId]);
            if (!fn) {
                this.log.warn(eventId + ' handler not a function');
                return;
            }

            if (this.handlers.get(eventId)) {
                dups.push(eventId);
            } else {
                this.handlers.set(eventId, fn);
            }
        }
        if (dups.length) {
            this.log.warn('duplicate bindings ignored:', dups);
        }
    }

    /**
     * Unbinds the specified message handlers.
     *   Expected that the same map will be used, but we only care about keys
     */
    unbindHandlers(handlerIds: string[]): void {
        if ( handlerIds.length === 0 ) {
            this.log.warn('WSS.unbindHandlers(): no event handlers');
            return null;
        }
        for (const eventId of handlerIds) {
            this.handlers.delete(eventId);
        }
    }

    /**
     * Add a listener function for listening for WebSocket opening.
     * The function must give a host and url and return void
     */
    addOpenListener(callback: (host: string, url: string) => void ): Callback {
        const id: number = this.nextListenerId++;
        const cb = this.fs.isF(callback);
        const o: Callback = <Callback>{ id: id, cb: cb };

        if (cb) {
            this.openListeners.set(id, o);
        } else {
            this.log.error('WSS.addOpenListener(): callback not a function');
            o.error = 'No callback defined';
        }
        return o;
    }

    /**
     * Remove a listener of WebSocket opening
     */
    removeOpenListener(lsnr: Callback): void {
        const id = this.fs.isO(lsnr) && lsnr.id;
        let o;

        if (!id) {
            this.log.warn('WSS.removeOpenListener(): invalid listener', lsnr);
            return null;
        }
        o = this.openListeners[id];

        if (o) {
            this.openListeners.delete(id);
        }
    }

    /**
     * Formulates an event message and sends it via the web-socket.
     * If the websocket is not up yet, we store it in a pending list.
     */
    sendEvent(evType: string, payload: Object ): void {
        const ev = <EventType> {
            event: evType,
            payload: payload
        };

        if (this.wsUp) {
            this.send(ev);
        } else {
            this.pendingEvents.push(ev);
        }
    }

    /**
     * Binds the veil service as a delegate.
     */
    setVeilDelegate(vd: VeilComponent): void {
        this.vcd = vd;
    }

    /**
     * Binds the loading service as a delegate
     */
    setLoadingDelegate(ld: any): void {
        // TODO - Investigate changing Loading Service to LoadingComponent
        this.log.debug('Loading delegate set', ld);
        this.lcd = ld;
    }

    isConnected(): boolean {
        return this.wsUp;
    }
}
