/*
 * 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 {
    ChangeDetectionStrategy,
    ChangeDetectorRef,
    Component,
    EventEmitter,
    HostListener,
    Input,
    OnChanges,
    OnInit,
    Output,
    QueryList,
    SimpleChange,
    SimpleChanges,
    ViewChildren
} from '@angular/core';
import {LocMeta, LogService, MetaUi, SvgUtilService, WebSocketService, ZoomUtils} from 'gui2-fw-lib';
import {
    Device,
    DeviceProps,
    ForceDirectedGraph,
    Host,
    HostLabelToggle,
    LabelToggle,
    LayerType,
    Link,
    LinkHighlight,
    Location,
    ModelEventMemo,
    ModelEventType,
    Node,
    Options,
    Region,
    RegionLink,
    SubRegion,
    UiElement
} from './models';
import {LocationType} from '../backgroundsvg/backgroundsvg.component';
import {DeviceNodeSvgComponent} from './visuals/devicenodesvg/devicenodesvg.component';
import {HostNodeSvgComponent} from './visuals/hostnodesvg/hostnodesvg.component';
import {LinkSvgComponent} from './visuals/linksvg/linksvg.component';
import {SelectedEvent} from './visuals/nodevisual';

interface UpdateMeta {
    id: string;
    class: string;
    memento: MetaUi;
}

const SVGCANVAS = <Options>{
    width: 1000,
    height: 1000
};

interface ChangeSummary {
    numChanges: number;
    locationChanged: boolean;
}

/**
 * ONOS GUI -- Topology Forces Graph Layer View.
 *
 * The regionData is set by Topology Service on WebSocket topo2CurrentRegion callback
 * This drives the whole Force graph
 */
@Component({
    selector: '[onos-forcesvg]',
    templateUrl: './forcesvg.component.html',
    styleUrls: ['./forcesvg.component.css'],
    changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ForceSvgComponent implements OnInit, OnChanges {
    @Input() deviceLabelToggle: LabelToggle.Enum = LabelToggle.Enum.NONE;
    @Input() hostLabelToggle: HostLabelToggle.Enum = HostLabelToggle.Enum.NONE;
    @Input() showHosts: boolean = false;
    @Input() highlightPorts: boolean = true;
    @Input() onosInstMastership: string = '';
    @Input() visibleLayer: LayerType = LayerType.LAYER_DEFAULT;
    @Input() selectedLink: RegionLink = null;
    @Input() scale: number = 1;
    @Input() regionData: Region = <Region>{devices: [ [], [], [] ], hosts: [ [], [], [] ], links: []};
    @Output() linkSelected = new EventEmitter<RegionLink>();
    @Output() selectedNodeEvent = new EventEmitter<UiElement[]>();
    public graph: ForceDirectedGraph;
    private selectedNodes: UiElement[] = [];

    // References to the children of this component - these are created in the
    // template view with the *ngFor and we get them by a query here
    @ViewChildren(DeviceNodeSvgComponent) devices: QueryList<DeviceNodeSvgComponent>;
    @ViewChildren(HostNodeSvgComponent) hosts: QueryList<HostNodeSvgComponent>;
    @ViewChildren(LinkSvgComponent) links: QueryList<LinkSvgComponent>;

    constructor(
        protected log: LogService,
        private ref: ChangeDetectorRef,
        protected wss: WebSocketService
    ) {
        this.selectedLink = null;
        this.log.debug('ForceSvgComponent constructed');
    }

    /**
     * Utility for extracting a node name from an endpoint string
     * In some cases - have to remove the port number from the end of a device
     * name
     * @param endPtStr The end point name
     */
    static extractNodeName(endPtStr: string, portStr: string): string {
        if (portStr === undefined || endPtStr === undefined) {
            return endPtStr;
        } else if (endPtStr.includes('/')) {
            return endPtStr.substr(0, endPtStr.length - portStr.length - 1);
        }
        return endPtStr;
    }

    /**
     * Recursive method to compare 2 objects attribute by attribute and update
     * the first where a change is detected
     * @param existingNode 1st object
     * @param updatedNode 2nd object
     */
    private static updateObject(existingNode: Object, updatedNode: Object): ChangeSummary {
        const changed = <ChangeSummary>{numChanges: 0, locationChanged: false};
        for (const key of Object.keys(updatedNode)) {
            const o = updatedNode[key];
            if (['id', 'x', 'y', 'fx', 'fy', 'vx', 'vy', 'index'].some(k => k === key)) {
                continue;
            } else if (o && typeof o === 'object' && o.constructor === Object) {
                const subChanged = ForceSvgComponent.updateObject(existingNode[key], updatedNode[key]);
                changed.numChanges += subChanged.numChanges;
                changed.locationChanged = subChanged.locationChanged ? true : changed.locationChanged;
            } else if (existingNode === undefined) {
                // Copy the whole object
                existingNode = updatedNode;
                changed.locationChanged = true;
                changed.numChanges++;
            } else if (existingNode[key] !== updatedNode[key]) {
                if (['locType', 'latOrY', 'longOrX', 'latitude', 'longitude', 'gridX', 'gridY'].some(k => k === key)) {
                    changed.locationChanged = true;
                }
                changed.numChanges++;
                existingNode[key] = updatedNode[key];
            }
        }
        return changed;
    }

    @HostListener('window:resize', ['$event'])
    onResize(event) {
        this.graph.restartSimulation();
        this.log.debug('Simulation restart after resize', event);
    }

    /**
     * After the component is initialized create the Force simulation
     * The list of devices, hosts and links will not have been receieved back
     * from the WebSocket yet as this time - they will be updated later through
     * ngOnChanges()
     */
    ngOnInit() {
        // Receiving an initialized simulated graph from our custom d3 service
        this.graph = new ForceDirectedGraph(SVGCANVAS, this.log);

        /** Binding change detection check on each tick
         * This along with an onPush change detection strategy should enforce
         * checking only when relevant! This improves scripting computation
         * duration in a couple of tests I've made, consistently. Also, it makes
         * sense to avoid unnecessary checks when we are dealing only with
         * simulations data binding.
         */
        this.graph.ticker.subscribe((simulation) => {
            // this.log.debug("Force simulation has ticked. Alpha",
            //     Math.round(simulation.alpha() * 1000) / 1000);
            this.ref.markForCheck();
        });

        this.log.debug('ForceSvgComponent initialized - waiting for nodes and links');

    }

    /**
     * When any one of the inputs get changed by a containing component, this
     * gets called automatically. In addition this is called manually by
     * topology.service when a response is received from the WebSocket from the
     * server
     *
     * The Devices, Hosts and SubRegions are all added to the Node list for the simulation
     * The Links are added to the Link list of the simulation.
     * Before they are added the Links are associated with Nodes based on their endPt
     *
     * @param changes - a list of changed @Input(s)
     */
    ngOnChanges(changes: SimpleChanges) {
        if (changes['regionData']) {
            const devices: Device[] =
                changes['regionData'].currentValue.devices[this.visibleLayerIdx()];
            const hosts: Host[] =
                changes['regionData'].currentValue.hosts[this.visibleLayerIdx()];
            const subRegions: SubRegion[] = changes['regionData'].currentValue.subRegion;
            this.graph.nodes = [];
            if (devices) {
                this.graph.nodes = devices;
            }
            if (hosts) {
                this.graph.nodes = this.graph.nodes.concat(hosts);
            }
            if (subRegions) {
                this.graph.nodes = this.graph.nodes.concat(subRegions);
            }

            this.graph.nodes.forEach((n) => this.fixPosition(n));

            // Associate the endpoints of each link with a real node
            this.graph.links = [];
            for (const linkIdx of Object.keys(this.regionData.links)) {
                const link = this.regionData.links[linkIdx];
                const epA = ForceSvgComponent.extractNodeName(link.epA, link.portA);
                if (!this.graph.nodes.find((node) => node.id === epA)) {
                    this.log.error('ngOnChange Could not find endpoint A', epA, 'for', link);
                    continue;
                }
                const epB = ForceSvgComponent.extractNodeName(
                    link.epB, link.portB);
                if (!this.graph.nodes.find((node) => node.id === epB)) {
                    this.log.error('ngOnChange Could not find endpoint B', epB, 'for', link);
                    continue;
                }
                this.regionData.links[linkIdx].source =
                    this.graph.nodes.find((node) =>
                        node.id === epA);
                this.regionData.links[linkIdx].target =
                    this.graph.nodes.find((node) =>
                        node.id === epB);
                this.regionData.links[linkIdx].index = Number(linkIdx);
            }

            this.graph.links = this.regionData.links;
            if (this.graph.nodes.length > 0) {
                this.graph.reinitSimulation();
            }
            this.log.debug('ForceSvgComponent input changed',
                this.graph.nodes.length, 'nodes,', this.graph.links.length, 'links');
        }
    }

    /**
     * If instance has a value then mute colors of devices not connected to it
     * Otherwise if instance does not have a value unmute all
     * @param instanceName name of the selected instance
     */
    changeInstSelection(instanceName: string) {
        this.log.debug('Mastership changed', instanceName);
        this.devices.filter((d) => d.device.master !== instanceName)
            .forEach((d) => {
                const isMuted = Boolean(instanceName);
                d.ngOnChanges({'colorMuted': new SimpleChange(!isMuted, isMuted, true)});
            }
        );
    }

    /**
     * If a node has a fixed location then assign it to fx and fy so
     * that it doesn't get affected by forces
     * @param graphNode The node whose location should be processed
     */
    private fixPosition(graphNode: Node): void {
        const loc: Location = <Location>graphNode['location'];
        const props: DeviceProps = <DeviceProps>graphNode['props'];
        const metaUi = <MetaUi>graphNode['metaUi'];
        if (loc && loc.locType === LocationType.GEO) {
            const position: MetaUi =
                ZoomUtils.convertGeoToCanvas(
                    <LocMeta>{lng: loc.longOrX, lat: loc.latOrY});
            graphNode.fx = position.x;
            graphNode.fy = position.y;
            this.log.debug('Found node', graphNode.id, 'with', loc.locType);
        } else if (loc && loc.locType === LocationType.GRID) {
            graphNode.fx = loc.longOrX;
            graphNode.fy = loc.latOrY;
            this.log.debug('Found node', graphNode.id, 'with', loc.locType);
        } else if (props && props.locType === LocationType.NONE && metaUi) {
            graphNode.fx = metaUi.x;
            graphNode.fy = metaUi.y;
            this.log.debug('Found node', graphNode.id, 'with locType=none and metaUi');
        } else {
            graphNode.fx = null;
            graphNode.fy = null;
        }
    }

    /**
     * Get the index of LayerType so it can drive the visibility of nodes and
     * hosts on layers
     */
    visibleLayerIdx(): number {
        const layerKeys: string[] = Object.keys(LayerType);
        for (const idx in layerKeys) {
            if (LayerType[layerKeys[idx]] === this.visibleLayer) {
                return Number(idx);
            }
        }
        return -1;
    }

    selectLink(link: RegionLink): void {
        this.selectedLink = link;
        this.linkSelected.emit(link);
    }

    /**
     * Iterate through all hosts and devices and links to deselect the previously selected
     * node. The emit an event to the parent that lets it know the selection has
     * changed.
     *
     * This function collates all of the nodes that have been selected and passes
     * a collection of nodes up to the topology component
     *
     * @param selectedNode the newly selected node
     */
    updateSelected(selectedNode: SelectedEvent): void {
        this.log.debug('Node or link ',
            selectedNode.uiElement ? selectedNode.uiElement.id : '--',
            selectedNode.deselecting ? 'deselected' : 'selected',
            selectedNode.isShift ? 'Multiple' : '');

        if (selectedNode.isShift && selectedNode.deselecting) {
            const idx = this.selectedNodes.findIndex((n) =>
                n.id === selectedNode.uiElement.id
            );
            this.selectedNodes.splice(idx, 1);
            this.log.debug('Removed node', idx);

        } else if (selectedNode.isShift) {
            this.selectedNodes.push(selectedNode.uiElement);

        } else if (selectedNode.deselecting) {
            this.devices
                .forEach((d) => d.deselect());
            this.hosts
                .forEach((h) => h.deselect());
            this.links
                .forEach((l) => l.deselect());
            this.selectedNodes = [];

        } else {
            const selNodeId = selectedNode.uiElement.id;
            // Otherwise if shift was not pressed deselect previous
            this.devices
                .filter((d) => d.device.id !== selNodeId)
                .forEach((d) => d.deselect());
            this.hosts
                .filter((h) => h.host.id !== selNodeId)
                .forEach((h) => h.deselect());

            this.links
                .filter((l) => l.link.id !== selNodeId)
                .forEach((l) => l.deselect());

            this.selectedNodes = [selectedNode.uiElement];
        }
        // Push the changes back up to parent (Topology Component)
        this.selectedNodeEvent.emit(this.selectedNodes);
    }

    /**
     * We want to filter links to show only those not related to hosts if the
     * 'showHosts' flag has been switched off. If 'showHosts' is true, then
     * display all links.
     */
    filteredLinks(): Link[] {
        return this.regionData.links.filter((h) =>
            this.showHosts ||
            ((<Host>h.source).nodeType !== 'host' &&
            (<Host>h.target).nodeType !== 'host'));
    }

    /**
     * When changes happen in the model, then model events are sent up through the
     * Web Socket
     * @param type - the type of the change
     * @param memo - a qualifier on the type
     * @param subject - the item that the update is for
     * @param data - the new definition of the item
     */
    handleModelEvent(type: ModelEventType, memo: ModelEventMemo, subject: string, data: UiElement): void {
        switch (type) {
            case ModelEventType.DEVICE_ADDED_OR_UPDATED:
                if (memo === ModelEventMemo.ADDED) {
                    this.fixPosition(<Device>data);
                    this.graph.nodes.push(<Device>data);
                    this.regionData.devices[this.visibleLayerIdx()].push(<Device>data);
                    this.log.debug('Device added', (<Device>data).id);
                } else if (memo === ModelEventMemo.UPDATED) {
                    const oldDevice: Device =
                        this.regionData.devices[this.visibleLayerIdx()]
                            .find((d) => d.id === subject);
                    const changes = ForceSvgComponent.updateObject(oldDevice, <Device>data);
                    if (changes.numChanges > 0) {
                        this.log.debug('Device ', oldDevice.id, memo, ' - ', changes, 'changes');
                        if (changes.locationChanged) {
                            this.fixPosition(oldDevice);
                        }
                        const svgDevice: DeviceNodeSvgComponent =
                            this.devices.find((svgdevice) => svgdevice.device.id === subject);
                        svgDevice.ngOnChanges({'device':
                                new SimpleChange(<Device>{}, oldDevice, true)
                        });
                    }
                } else {
                    this.log.warn('Device ', memo, ' - not yet implemented', data);
                }
                break;
            case ModelEventType.HOST_ADDED_OR_UPDATED:
                if (memo === ModelEventMemo.ADDED) {
                    this.fixPosition(<Host>data);
                    this.graph.nodes.push(<Host>data);
                    this.regionData.hosts[this.visibleLayerIdx()].push(<Host>data);
                    this.log.debug('Host added', (<Host>data).id);
                } else if (memo === ModelEventMemo.UPDATED) {
                    const oldHost: Host = this.regionData.hosts[this.visibleLayerIdx()]
                        .find((h) => h.id === subject);
                    const changes = ForceSvgComponent.updateObject(oldHost, <Host>data);
                    if (changes.numChanges > 0) {
                        this.log.debug('Host ', oldHost.id, memo, ' - ', changes, 'changes');
                        if (changes.locationChanged) {
                            this.fixPosition(oldHost);
                        }
                    }
                } else {
                    this.log.warn('Host change', memo, ' - unexpected');
                }
                break;
            case ModelEventType.DEVICE_REMOVED:
                if (memo === ModelEventMemo.REMOVED || memo === undefined) {
                    const removeIdx: number =
                        this.regionData.devices[this.visibleLayerIdx()]
                            .findIndex((d) => d.id === subject);
                    this.regionData.devices[this.visibleLayerIdx()].splice(removeIdx, 1);
                    this.removeRelatedLinks(subject);
                    this.log.debug('Device ', subject, 'removed. Links', this.regionData.links);
                } else {
                    this.log.warn('Device removed - unexpected memo', memo);
                }
                break;
            case ModelEventType.HOST_REMOVED:
                if (memo === ModelEventMemo.REMOVED || memo === undefined) {
                    const removeIdx: number =
                        this.regionData.hosts[this.visibleLayerIdx()]
                            .findIndex((h) => h.id === subject);
                    this.regionData.hosts[this.visibleLayerIdx()].splice(removeIdx, 1);
                    this.removeRelatedLinks(subject);
                    this.log.debug('Host ', subject, 'removed');
                } else {
                    this.log.warn('Host removed - unexpected memo', memo);
                }
                break;
            case ModelEventType.LINK_ADDED_OR_UPDATED:
                if (memo === ModelEventMemo.ADDED &&
                    this.regionData.links.findIndex((l) => l.id === subject) === -1) {
                    const newLink = <RegionLink>data;


                    const epA = ForceSvgComponent.extractNodeName(
                        newLink.epA, newLink.portA);
                    if (!this.graph.nodes.find((node) => node.id === epA)) {
                        this.log.error('Could not find endpoint A', epA, 'of', newLink);
                        break;
                    }
                    const epB = ForceSvgComponent.extractNodeName(
                        newLink.epB, newLink.portB);
                    if (!this.graph.nodes.find((node) => node.id === epB)) {
                        this.log.error('Could not find endpoint B', epB, 'of link', newLink);
                        break;
                    }

                    const listLen = this.regionData.links.push(<RegionLink>data);
                    this.regionData.links[listLen - 1].source =
                        this.graph.nodes.find((node) => node.id === epA);
                    this.regionData.links[listLen - 1].target =
                        this.graph.nodes.find((node) => node.id === epB);
                    this.log.debug('Link added', subject);
                } else if (memo === ModelEventMemo.UPDATED) {
                    const oldLink = this.regionData.links.find((l) => l.id === subject);
                    const changes = ForceSvgComponent.updateObject(oldLink, <RegionLink>data);
                    this.log.debug('Link ', subject, '. Updated', changes, 'items');
                } else {
                    this.log.warn('Link event ignored', subject, data);
                }
                break;
            case ModelEventType.LINK_REMOVED:
                if (memo === ModelEventMemo.REMOVED) {
                    const removeIdx = this.regionData.links.findIndex((l) => l.id === subject);
                    this.regionData.links.splice(removeIdx, 1);
                    this.log.debug('Link ', subject, 'removed');
                }
                break;
            default:
                this.log.error('Unexpected model event', type, 'for', subject, 'Data', data);
        }
        this.graph.links = this.regionData.links;
        this.graph.reinitSimulation();
    }

    private removeRelatedLinks(subject: string) {
        const len = this.regionData.links.length;
        for (let i = 0; i < len; i++) {
            const linkIdx = this.regionData.links.findIndex((l) =>
                (ForceSvgComponent.extractNodeName(l.epA, l.portA) === subject ||
                    ForceSvgComponent.extractNodeName(l.epB, l.portB) === subject));
            if (linkIdx >= 0) {
                this.regionData.links.splice(linkIdx, 1);
                this.log.debug('Link ', linkIdx, 'removed on attempt', i);
            }
        }
    }

    /**
     * When traffic monitoring is turned on (A key) highlights will be sent back
     * from the WebSocket through the Traffic Service
     * @param devices - an array of device highlights
     * @param hosts - an array of host highlights
     * @param links - an array of link highlights
     */
    handleHighlights(devices: Device[], hosts: Host[], links: LinkHighlight[], fadeMs: number = 0): void {

        if (devices.length > 0) {
            this.log.debug(devices.length, 'Devices highlighted');
            devices.forEach((dh) => {
                const deviceComponent: DeviceNodeSvgComponent = this.devices.find((d) => d.device.id === dh.id );
                if (deviceComponent) {
                    deviceComponent.ngOnChanges(
                        {'deviceHighlight': new SimpleChange(<Device>{}, dh, true)}
                    );
                    this.log.debug('Highlighting device', deviceComponent.device.id);
                } else {
                    this.log.warn('Device component not found', dh.id);
                }
            });
        }
        if (hosts.length > 0) {
            this.log.debug(hosts.length, 'Hosts highlighted');
            hosts.forEach((hh) => {
                const hostComponent: HostNodeSvgComponent = this.hosts.find((h) => h.host.id === hh.id );
                if (hostComponent) {
                    hostComponent.ngOnChanges(
                        {'hostHighlight': new SimpleChange(<Host>{}, hh, true)}
                    );
                    this.log.debug('Highlighting host', hostComponent.host.id);
                }
            });
        }
        if (links.length > 0) {
            this.log.debug(links.length, 'Links highlighted');
            links.forEach((lh) => {
                const linkComponent: LinkSvgComponent =
                    this.links.find((l) => l.link.id === Link.linkIdFromShowHighlights(lh.id) );
                if (linkComponent) { // A link might not be present if hosts viewing is switched off
                    if (fadeMs > 0) {
                        lh.fadems = fadeMs;
                    }
                    linkComponent.ngOnChanges(
                        {'linkHighlight': new SimpleChange(<LinkHighlight>{}, lh, true)}
                    );
                }
            });
        }
    }

    /**
     * As nodes are dragged around the graph, their new location should be sent
     * back to server
     * @param klass The class of node e.g. 'host' or 'device'
     * @param id - the ID of the node
     * @param newLocation - the new Location of the node
     */
    nodeMoved(klass: string, id: string, newLocation: MetaUi) {
        this.wss.sendEvent('updateMeta2', <UpdateMeta>{
            id: id,
            class: klass,
            memento: newLocation
        });
        this.log.debug(klass, id, 'has been moved to', newLocation);
    }

    /**
     * If any nodes with fixed positions had been dragged out of place
     * then put back where they belong
     * If there are some devices selected reset only these
     */
    resetNodeLocations(): number {
        let numbernodes = 0;
        if (this.selectedNodes.length > 0) {
            this.devices
                .filter((d) => this.selectedNodes.some((s) => s.id === d.device.id))
                .forEach((dev) => {
                    Node.resetNodeLocation(<Node>dev.device);
                    numbernodes++;
                });
            this.hosts
                .filter((h) => this.selectedNodes.some((s) => s.id === h.host.id))
                .forEach((h) => {
                    Host.resetNodeLocation(<Host>h.host);
                    numbernodes++;
                });
        } else {
            this.devices.forEach((dev) => {
                Node.resetNodeLocation(<Node>dev.device);
                numbernodes++;
            });
            this.hosts.forEach((h) => {
                Host.resetNodeLocation(<Host>h.host);
                numbernodes++;
            });
        }
        this.graph.reinitSimulation();
        return numbernodes;
    }

    /**
     * Toggle floating nodes between unpinned and frozen
     * There may be frozen and unpinned in the selection
     *
     * If there are nodes selected toggle only these
     */
    unpinOrFreezeNodes(freeze: boolean): number {
        let numbernodes = 0;
        if (this.selectedNodes.length > 0) {
            this.devices
                .filter((d) => this.selectedNodes.some((s) => s.id === d.device.id))
                .forEach((d) => {
                    Node.unpinOrFreezeNode(<Node>d.device, freeze);
                    numbernodes++;
                });
            this.hosts
                .filter((h) => this.selectedNodes.some((s) => s.id === h.host.id))
                .forEach((h) => {
                    Node.unpinOrFreezeNode(<Node>h.host, freeze);
                    numbernodes++;
                });
        } else {
            this.devices.forEach((d) => {
                Node.unpinOrFreezeNode(<Node>d.device, freeze);
                numbernodes++;
            });
            this.hosts.forEach((h) => {
                Node.unpinOrFreezeNode(<Node>h.host, freeze);
                numbernodes++;
            });
        }
        this.graph.reinitSimulation();
        return numbernodes;
    }

}

