/*
 * Copyright 2019-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 {
    AfterContentInit,
    Component, HostListener, Inject, Input,
    OnDestroy,
    OnInit, SimpleChange,
    ViewChild
} from '@angular/core';
import * as d3 from 'd3';
import {
    FnService, IconService,
    KeysService,
    KeysToken, LionService,
    LogService,
    PrefsService,
    SvgUtilService,
    WebSocketService,
    TopoZoomPrefs, ZoomUtils
} from 'gui2-fw-lib';
import {InstanceComponent} from '../panel/instance/instance.component';
import {DetailsComponent} from '../panel/details/details.component';
import {BackgroundSvgComponent} from '../layer/backgroundsvg/backgroundsvg.component';
import {ForceSvgComponent} from '../layer/forcesvg/forcesvg.component';
import {TopologyService} from '../topology.service';
import {
    GridDisplayToggle,
    HostLabelToggle,
    LabelToggle,
    UiElement
} from '../layer/forcesvg/models';
import {
    INSTANCE_TOGGLE, SUMMARY_TOGGLE, DETAILS_TOGGLE,
    HOSTS_TOGGLE, OFFLINE_TOGGLE, PORTS_TOGGLE,
    BKGRND_TOGGLE, CYCLELABELS_BTN, CYCLEHOSTLABEL_BTN,
    CYCLEGRIDDISPLAY_BTN, RESETZOOM_BTN, EQMASTER_BTN,
    CANCEL_TRAFFIC, ALL_TRAFFIC, QUICKHELP_BTN, BKGRND_SELECT
} from '../panel/toolbar/toolbar.component';
import {TrafficService} from '../traffic.service';
import {ZoomableDirective} from '../layer/zoomable.directive';
import {MapObject} from '../layer/maputils';

const TOPO2_PREFS = 'topo2_prefs';
const TOPO_MAPID_PREFS = 'topo_mapid';

const PREF_BG = 'bg';
const PREF_DETAIL = 'detail';
const PREF_DLBLS = 'dlbls';
const PREF_HLBLS = 'hlbls';
const PREF_GRID = 'grid';
const PREF_HOSTS = 'hosts';
const PREF_INSTS = 'insts';
const PREF_OFFDEV = 'offdev';
const PREF_PORTHL = 'porthl';
const PREF_SUMMARY = 'summary';
const PREF_TOOLBAR = 'toolbar';

/**
 * Model of the topo2_prefs object - this is a subset of the overall Prefs returned
 * by the server
 */
export interface Topo2Prefs {
    bg: number;
    detail: number;
    dlbls: number;
    hlbls: number;
    hosts: number;
    insts: number;
    offdev: number;
    porthl: number;
    spr: number;
    ovid: string;
    summary: number;
    toolbar: number;
    grid: number;
}

/**
 * ONOS GUI Topology View
 *
 * This Topology View component is the top level component in a hierarchy that
 * comprises the whole Topology View
 *
 * There are three main parts (panels, graphical and breadcrumbs)
 * The panel hierarchy
 * |-- Instances Panel (shows ONOS instances)
 * |-- Summary Panel (summary of ONOS)
 * |-- Toolbar Panel (the toolbar)
 * |-- Details Panel (when a node is selected in the Force graphical view (see below))
 *
 * The graphical hierarchy contains
 * Topology (this)
 *  |-- No Devices Connected (only of there are no nodes to show)
 *  |-- Zoom Layer (everything beneath this can be zoomed and panned)
 *      |-- Background (container for any backgrounds - can be toggled on and off)
 *          |-- Map
 *      |-- Forces (all of the nodes and links laid out by a d3.force simulation)
 *
 * The breadcrumbs
 * |-- Breadcrumb (in region view a way of navigating back up through regions)
 */
@Component({
  selector: 'onos-topology',
  templateUrl: './topology.component.html',
  styleUrls: ['./topology.component.css']
})
export class TopologyComponent implements AfterContentInit, OnInit, OnDestroy {
    @Input() bannerHeight: number = 48;
    // These are references to the components inserted in the template
    @ViewChild(InstanceComponent) instance: InstanceComponent;
    @ViewChild(DetailsComponent) details: DetailsComponent;
    @ViewChild(BackgroundSvgComponent) background: BackgroundSvgComponent;
    @ViewChild(ForceSvgComponent) force: ForceSvgComponent;
    @ViewChild(ZoomableDirective) zoomDirective: ZoomableDirective;

    flashMsg: string = '';
    // These are used as defaults if nothing is set on the server
    prefsState: Topo2Prefs = <Topo2Prefs>{
        bg: 0,
        detail: 1,
        dlbls: 0,
        hlbls: 2,
        hosts: 0,
        insts: 1,
        offdev: 1,
        ovid: 'traffic', // default to traffic overlay
        porthl: 1,
        spr: 0,
        summary: 1,
        toolbar: 0,
        grid: 0
    };

    mapIdState: MapObject = <MapObject>{
        id: undefined,
        scale: 1.0
    };
    mapSelShown: boolean = false;
    lionFn; // Function

    gridShown: boolean = true;
    geoGridShown: boolean = true;

    constructor(
        protected log: LogService,
        protected fs: FnService,
        protected ks: KeysService,
        protected sus: SvgUtilService,
        protected ps: PrefsService,
        protected wss: WebSocketService,
        protected ts: TopologyService,
        protected trs: TrafficService,
        protected is: IconService,
        private lion: LionService,
        @Inject('Window') public window: any,
    ) {
        if (this.lion.ubercache.length === 0) {
            this.lionFn = this.dummyLion;
            this.lion.loadCbs.set('topo-toolbar', () => this.doLion());
        } else {
            this.doLion();
        }

        this.is.loadIconDef('bird');
        this.is.loadIconDef('active');
        this.is.loadIconDef('uiAttached');
        this.is.loadIconDef('m_switch');
        this.is.loadIconDef('m_roadm');
        this.is.loadIconDef('m_router');
        this.is.loadIconDef('m_uiAttached');
        this.is.loadIconDef('m_endstation');
        this.is.loadIconDef('m_ports');
        this.is.loadIconDef('m_summary');
        this.is.loadIconDef('m_details');
        this.is.loadIconDef('m_map');
        this.is.loadIconDef('m_selectMap');
        this.is.loadIconDef('m_cycleLabels');
        this.is.loadIconDef('m_cycleGridDisplay');
        this.is.loadIconDef('m_resetZoom');
        this.is.loadIconDef('m_eqMaster');
        this.is.loadIconDef('m_unknown');
        this.is.loadIconDef('m_allTraffic');
        this.is.loadIconDef('deviceTable');
        this.is.loadIconDef('flowTable');
        this.is.loadIconDef('portTable');
        this.is.loadIconDef('groupTable');
        this.is.loadIconDef('meterTable');
        this.is.loadIconDef('triangleUp');
        this.log.debug('Topology component constructed');
    }

    /**
     * Static functions must come before member variables
     * @param index Corresponds to LabelToggle.Enum index
     */
    private static deviceLabelFlashMessage(index: number): string {
        switch (index) {
            case 0: return 'fl_device_labels_hide';
            case 1: return 'fl_device_labels_show_friendly';
            case 2: return 'fl_device_labels_show_id';
        }
    }

    private static hostLabelFlashMessage(index: number): string {
        switch (index) {
            case 0: return 'fl_host_labels_hide';
            case 1: return 'fl_host_labels_show_friendly';
            case 2: return 'fl_host_labels_show_ip';
            case 3: return 'fl_host_labels_show_mac';
        }
    }

    private static gridDisplayFlashMessage(index: number): string {
        switch (index) {
            case 0: return 'fl_grid_display_hide';
            case 1: return 'fl_grid_display_1000';
            case 2: return 'fl_grid_display_geo';
            case 3: return 'fl_grid_display_both';
        }
    }

    /**
     * Pass the list of Key Commands to the KeyService, and initialize the Topology
     * Service - which communicates with through the WebSocket to the ONOS server
     * to get the nodes and links.
     */
    ngOnInit() {
        this.bindCommands();
        // The components from the template are handed over to TopologyService here
        // so that WebSocket responses can be passed back in to them
        // The handling of the WebSocket call is delegated out to the Topology
        // Service just to compartmentalize things a bit
        this.ts.init(this.instance, this.background, this.force);

        this.ps.addListener((data) => this.prefsUpdateHandler(data));
        this.prefsState = this.ps.getPrefs(TOPO2_PREFS, this.prefsState);
        this.mapIdState = this.ps.getPrefs(TOPO_MAPID_PREFS, this.mapIdState);

        this.log.debug('Topology component initialized');
    }

    ngAfterContentInit(): void {
        // Scale the window initially - then after resize
        const zoomMapExtents = ZoomUtils.zoomToWindowSize(
            this.bannerHeight, this.window.innerWidth, this.window.innerHeight);
        this.zoomDirective.changeZoomLevel(zoomMapExtents, true);
        this.log.debug('Topology zoom initialized',
            this.bannerHeight, this.window.innerWidth, this.window.innerHeight,
            zoomMapExtents);
    }

    /**
     * Callback function that's called whenever new Prefs are received from WebSocket
     *
     * Note: At present the backend server does not filter updated by logged in user,
     * so you might get updates pertaining to a different user
     */
    prefsUpdateHandler(data: any): void {
        // Extract the TOPO2 prefs from it
        if (data[TOPO2_PREFS]) {
            this.prefsState = data[TOPO2_PREFS];
        }
        this.log.debug('Updated topo2 prefs', this.prefsState, this.mapIdState);
    }

    /**
     * When this component is being stopped, disconnect the TopologyService from
     * the WebSocket
     */
    ngOnDestroy() {
        this.ts.destroy();
        this.ps.removeListener((data) => this.prefsUpdateHandler(data));
        this.log.debug('Topology component destroyed');
    }

    @HostListener('window:resize', ['$event'])
    onResize(event) {
        const zoomMapExtents = ZoomUtils.zoomToWindowSize(
                this.bannerHeight, event.target.innerWidth, event.target.innerHeight);
        this.zoomDirective.changeZoomLevel(zoomMapExtents, true);
        this.log.debug('Topology window resize',
            event.target.innerWidth, event.target.innerHeight, this.bannerHeight, zoomMapExtents);
    }

    /**
     * When ever a toolbar button is clicked, an event is sent up from toolbar
     * component which is caught and passed on to here.
     * @param name The name of the button that was clicked
     */
    toolbarButtonClicked(name: string) {
        switch (name) {
            case INSTANCE_TOGGLE:
                this.toggleInstancePanel();
                break;
            case SUMMARY_TOGGLE:
                this.toggleSummary();
                break;
            case DETAILS_TOGGLE:
                this.toggleDetails();
                break;
            case HOSTS_TOGGLE:
                this.toggleHosts();
                break;
            case OFFLINE_TOGGLE:
                this.toggleOfflineDevices();
                break;
            case PORTS_TOGGLE:
                this.togglePorts();
                break;
            case BKGRND_TOGGLE:
                this.toggleBackground();
                break;
            case BKGRND_SELECT:
                this.mapSelShown = !this.mapSelShown;
                break;
            case CYCLELABELS_BTN:
                this.cycleDeviceLabels();
                break;
            case CYCLEHOSTLABEL_BTN:
                this.cycleHostLabels();
                break;
            case CYCLEGRIDDISPLAY_BTN:
                this.cycleGridDisplay();
                break;
            case RESETZOOM_BTN:
                this.resetZoom();
                break;
            case EQMASTER_BTN:
                this.equalizeMasters();
                break;
            case CANCEL_TRAFFIC:
                this.cancelTraffic();
                break;
            case ALL_TRAFFIC:
                this.monitorAllTraffic();
                break;
            case QUICKHELP_BTN:
                this.ks.quickHelpShown = true;
                break;
            default:
                this.log.warn('Unhandled Toolbar action', name);
        }
    }

    /**
     * The list of key strokes that will be active in the Topology View.
     *
     * This action map is passed to the KeyService through the bindCommands()
     * when this component is being initialized
     */
    actionMap() {
        return {
            A: [() => {this.monitorAllTraffic(); }, 'Monitor all traffic'],
            B: [(token) => {this.toggleBackground(token); }, 'Toggle background'],
            D: [(token) => {this.toggleDetails(token); }, 'Toggle details panel'],
            E: [() => {this.equalizeMasters(); }, 'Equalize mastership roles'],
            H: [() => {this.toggleHosts(); }, 'Toggle host visibility'],
            I: [(token) => {this.toggleInstancePanel(token); }, 'Toggle ONOS Instance Panel'],
            G: [() => {this.mapSelShown = !this.mapSelShown; }, 'Show map selection dialog'],
            L: [() => {this.cycleDeviceLabels(); }, 'Cycle device labels'],
            M: [() => {this.toggleOfflineDevices(); }, 'Toggle offline visibility'],
            O: [() => {this.toggleSummary(); }, 'Toggle the Summary Panel'],
            P: [(token) => {this.togglePorts(token); }, 'Toggle Port Highlighting'],
            Q: [() => {this.cycleGridDisplay(); }, 'Cycle grid display'],
            R: [() => {this.resetZoom(); }, 'Reset pan / zoom'],
            U: [() => {this.unpinNode(); }, 'Unpin node (mouse over)'],
            X: [() => {this.resetNodeLocation(); }, 'Reset Node Location'],
            dot: [() => {this.toggleToolbar(); }, 'Toggle Toolbar'],
            0: [() => {this.cancelTraffic(); }, 'Cancel traffic monitoring'],
            'shift-L': [() => {this.cycleHostLabels(); }, 'Cycle host labels'],

            // -- instance color palette debug
            9: () => {
                this.sus.cat7().testCard(d3.select('svg#topo2'));
            },

            esc: [() => {this.handleEscape(); }, 'Cancel commands'],

            // TODO update after adding in Background Service
            // topology overlay selections
            // F1: function () { t2tbs.fnKey(0); },
            // F2: function () { t2tbs.fnKey(1); },
            // F3: function () { t2tbs.fnKey(2); },
            // F4: function () { t2tbs.fnKey(3); },
            // F5: function () { t2tbs.fnKey(4); },
            //
            // _keyListener: t2tbs.keyListener.bind(t2tbs),

            _helpFormat: [
                ['I', 'O', 'D', 'H', 'M', 'P', 'dash', 'B'],
                ['X', 'Z', 'N', 'L', 'shift-L', 'U', 'R', 'E', 'dot'],
                [], // this column reserved for overlay actions
            ],
        };
    }


    bindCommands(additional?: any) {

        const am = this.actionMap();
        const add = this.fs.isO(additional);

        this.ks.keyBindings(am);

        this.ks.gestureNotes([
            ['click', 'Select the item and show details'],
            ['shift-click', 'Toggle selection state'],
            ['drag', 'Reposition (and pin) device / host'],
            ['cmd-scroll', 'Zoom in / out'],
            ['cmd-drag', 'Pan'],
        ]);
    }

    handleEscape() {

        if (false) {
            // TODO: Cancel show mastership
            // TODO: Cancel Active overlay
            // TODO: Reinstate with components
        } else {
            this.nodeSelected(undefined);
            this.log.debug('Handling escape');
            // } else if (t2rs.deselectAllNodes()) {
            //     // else if we have node selections, deselect them all
            //     // (work already done)
            // } else if (t2rs.deselectLink()) {
            //     // else if we have a link selection, deselect it
            //     // (work already done)
            // } else if (t2is.isVisible()) {
            //     // If the instance panel is visible, close it
            //     t2is.toggle();
            // } else if (t2sp.isVisible()) {
            //     // If the summary panel is visible, close it
            //     t2sp.toggle();
        }
    }

    /**
     * Updates the cache of preferences locally and onwards to the PrefsService
     * @param what The attribute of the local topo2-prefs cache to update
     * @param b the value to update it with
     */
    updatePrefsState(what: string, b: number) {
        this.prefsState[what] = b;
        this.ps.setPrefs(TOPO2_PREFS, this.prefsState);
    }

    /**
     * When the button is clicked on the toolbar or the L key is pressed
     * 1) cycle through options
     * 2) flash up a message
     * 3a) Update the local prefs cache
     * 3b) And passes on to the global prefs service which sends back to the server
     * 3c) It also has a knock on effect of passing it on to ForceSvgComponent
     *      because prefsState.dlbls is given as an input to it
     * 3d) This will in turn pass it down to the DeviceSvgComponent which
     *       displays the label
     */
    protected cycleDeviceLabels() {
        const old: LabelToggle.Enum = this.prefsState.dlbls;
        const next = LabelToggle.next(old);
        this.flashMsg = this.lionFn(TopologyComponent.deviceLabelFlashMessage(next));
        this.updatePrefsState(PREF_DLBLS, next);
        this.log.debug('Cycling device labels', old, next);
    }

    protected cycleHostLabels() {
        const old: HostLabelToggle.Enum = this.prefsState.hlbls;
        const next = HostLabelToggle.next(old);
        this.flashMsg = this.lionFn(TopologyComponent.hostLabelFlashMessage(next));
        this.updatePrefsState(PREF_HLBLS, next);
        this.log.debug('Cycling host labels', old, next);
    }

    protected cycleGridDisplay() {
        const old: GridDisplayToggle.Enum = this.prefsState.grid;
        const next = GridDisplayToggle.next(old);
        this.flashMsg = this.lionFn(TopologyComponent.gridDisplayFlashMessage(next));
        this.updatePrefsState(PREF_GRID, next);
        this.log.debug('Cycling grid display', old, next);
    }

    /**
     * When the button is clicked on the toolbar or the B key is pressed
     * 1) Find the inverse of the current state (held as 1 or 0)
     * 2) Flash up a message on screen
     * 3b) And passes on to the global prefs service which sends back to the server
     * 3c) It also has a knock on effect of passing it on to ToolbarComponent
     *      because prefsState.bg is given as an input to it
     * @param token not currently used
     */
    protected toggleBackground(token?: KeysToken) {
        const bg: boolean = !Boolean(this.prefsState.bg);
        this.flashMsg = this.lionFn(bg ? 'show' : 'hide') +
            ' ' + this.lionFn('fl_background_map');
        this.updatePrefsState(PREF_BG, bg ? 1 : 0);
        this.log.debug('Toggling background', token, bg ? 'shown' : 'hidden');
    }

    protected toggleDetails(token?: KeysToken) {
        const on: boolean = !Boolean(this.prefsState.detail);
        this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
            ' ' + this.lionFn('fl_panel_details');
        this.updatePrefsState(PREF_DETAIL, on ? 1 : 0);
        this.log.debug('Toggling details', token);
    }

    protected toggleInstancePanel(token?: KeysToken) {
        const on: boolean = !Boolean(this.prefsState.insts);
        this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
            ' ' + this.lionFn('fl_panel_instances');
        this.updatePrefsState(PREF_INSTS, on ? 1 : 0);
        this.log.debug('Toggling instances', token, on);
    }

    protected toggleSummary() {
        const on: boolean = !Boolean(this.prefsState.summary);
        this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
            ' ' + this.lionFn('fl_panel_summary');
        this.updatePrefsState(PREF_SUMMARY, on ? 1 : 0);
    }

    protected togglePorts(token?: KeysToken) {
        const current: boolean = !Boolean(this.prefsState.porthl);
        this.flashMsg = this.lionFn(current ? 'enable' : 'disable') +
            ' ' + this.lionFn('fl_port_highlighting');
        this.updatePrefsState(PREF_PORTHL, current ? 1 : 0);
        this.log.debug(current ? 'Enable' : 'Disable', 'port highlighting');
    }

    protected toggleToolbar() {
        const on: boolean = !Boolean(this.prefsState.toolbar);
        this.updatePrefsState(PREF_TOOLBAR, on ? 1 : 0);
        this.log.debug('toggling toolbar', on ? 'shown' : 'hidden');
    }

    protected toggleHosts() {
        const current: boolean = !Boolean(this.prefsState.hosts);
        this.flashMsg = this.lionFn('hosts') + ' ' +
                        this.lionFn(this.force.showHosts ? 'visible' : 'hidden');
        this.updatePrefsState(PREF_HOSTS, current ? 1 : 0);
        this.log.debug('toggling hosts: ', this.prefsState.hosts ? 'Show' : 'Hide');
    }

    protected toggleOfflineDevices() {
        const on: boolean = !Boolean(this.prefsState.offdev);
        this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
            ' ' + this.lionFn('fl_offline_devices');
        this.updatePrefsState(PREF_OFFDEV, on ? 1 : 0);
        this.log.debug('toggling offline devices', this.prefsState.offdev);
    }

    protected resetZoom() {
        const zoomMapExtents = ZoomUtils.zoomToWindowSize(
            this.bannerHeight, this.window.innerWidth, this.window.innerHeight);
        this.zoomDirective.changeZoomLevel(zoomMapExtents, false);
        this.flashMsg = this.lionFn('fl_pan_zoom_reset');
    }

    protected equalizeMasters() {
        this.wss.sendEvent('equalizeMasters', null);
        this.flashMsg = this.lionFn('fl_eq_masters');
        this.log.debug('equalizing masters');
    }

    protected resetNodeLocation() {
        // TODO: Implement reset locations
        this.force.resetNodeLocations();
        this.flashMsg = this.lionFn('fl_reset_node_locations');
        this.log.debug('resetting node location');
    }

    protected unpinNode() {
        // TODO: Implement this
        this.log.debug('unpinning node');
    }

    /**
     * Check to see if this is needed anymore
     * @param what - a key stroke
     */
    protected notValid(what) {
        this.log.warn('topo.js getActionEntry(): Not a valid ' + what);
    }

    /**
     * Check to see if this is needed anymore
     * @param key - a key stroke
     */
    getActionEntry(key) {
        let entry;

        if (!key) {
            this.notValid('key');
            return null;
        }

        entry = this.actionMap()[key];

        if (!entry) {
            this.notValid('actionMap (' + key + ') entry');
            return null;
        }
        return this.fs.isA(entry) || [entry, ''];
    }

    /**
     * An event handler that updates the details panel as items are
     * selected in the forcesvg layer
     * @param nodeOrLink the item to display details of
     */
    nodeSelected(nodeOrLink: UiElement) {
        this.details.ngOnChanges({'selectedNode':
            new SimpleChange(undefined, nodeOrLink, true)});
    }

    /**
     * Enable traffic monitoring
     */
    monitorAllTraffic() {
        // TODO: Implement support for toggling between bits, packets and octets
        this.flashMsg = this.lionFn('tr_fl_pstats_bits');
        this.trs.init(this.force);
    }

    /**
     * Cancel traffic monitoring
     */
    cancelTraffic() {
        this.flashMsg = this.lionFn('fl_monitoring_canceled');
        this.trs.destroy();
    }

    changeMap(map: MapObject) {
        this.mapSelShown = false; // Hide the MapSelector component
        this.mapIdState = map;
        this.ps.setPrefs(TOPO_MAPID_PREFS, this.mapIdState);
        this.log.debug('Map has been changed to ', map);
    }

    mapExtentsZoom(zoomMapExtents: TopoZoomPrefs) {
        // this.zoomDirective.updateZoomState(zoomPrefs.tx, zoomPrefs.ty, zoomPrefs.sc);
        this.zoomDirective.changeZoomLevel(zoomMapExtents);
        this.log.debug('Map zoom prefs updated', zoomMapExtents);
    }

    /**
     * Read the LION bundle for Toolbar and set up the lionFn
     */
    doLion() {
        this.lionFn = this.lion.bundle('core.view.Topo');
    }

    /**
     * A dummy implementation of the lionFn until the response is received and the LION
     * bundle is received from the WebSocket
     */
    dummyLion(key: string): string {
        return '%' + key + '%';
    }
}
