ONOS-1479 -- GUI - augmenting topology view for extensibility: WIP.
- Major refactoring of TopologyViewMessageHandler and related classes.

Change-Id: I920f7f9f7317f3987a9a8da35ac086e9f8cab8d3
diff --git a/web/gui/src/main/webapp/app/view/topo/topoForce.js b/web/gui/src/main/webapp/app/view/topo/topoForce.js
index 0595393..f3c053e 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoForce.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoForce.js
@@ -58,6 +58,7 @@
         showHosts = false,      // whether hosts are displayed
         showOffline = true,     // whether offline devices are displayed
         nodeLock = false,       // whether nodes can be dragged or not (locked)
+        fTimer,                 // timer for delayed force layout
         fNodesTimer,            // timer for delayed nodes update
         fLinksTimer,            // timer for delayed links update
         dim,                    // the dimensions of the force layout [w,h]
@@ -117,6 +118,7 @@
         network.nodes.push(d);
         lu[id] = d;
         updateNodes();
+        fStart();
     }
 
     function updateDevice(data) {
@@ -170,6 +172,7 @@
             lu[d.egress] = lnk;
             updateLinks();
         }
+        fStart();
     }
 
     function updateHost(data) {
@@ -215,6 +218,7 @@
             aggregateLink(d, data);
             lu[d.key] = d;
             updateLinks();
+            fStart();
         }
     }
 
@@ -322,6 +326,7 @@
             // remove from lookup cache
             delete lu[removed[0].key];
             updateLinks();
+            fResume();
         }
     }
 
@@ -343,6 +348,7 @@
         // NOTE: upd is false if we were called from removeDeviceElement()
         if (upd) {
             updateNodes();
+            fResume();
         }
     }
 
@@ -367,6 +373,7 @@
 
         // remove from SVG
         updateNodes();
+        fResume();
     }
 
     function updateHostVisibility() {
@@ -520,8 +527,9 @@
         fNodesTimer = $timeout(_updateNodes, 150);
     }
 
+    // IMPLEMENTATION NOTE: _updateNodes() should NOT stop, start, or resume
+    //  the force layout; that needs to be determined and implemented elsewhere
     function _updateNodes() {
-        force.stop();
         // select all the nodes in the layout:
         node = nodeG.selectAll('.node')
             .data(network.nodes, function (d) { return d.id; });
@@ -536,7 +544,10 @@
             .attr({
                 id: function (d) { return sus.safeId(d.id); },
                 class: mkSvgClass,
-                transform: function (d) { return sus.translate(d.x, d.y); },
+                transform: function (d) {
+                    // Need to guard against NaN here ??
+                    return sus.translate(d.x, d.y);
+                },
                 opacity: 0
             })
             .call(drag)
@@ -564,7 +575,6 @@
         // exiting node specifics:
         exiting.filter('.host').each(td3.hostExit);
         exiting.filter('.device').each(td3.deviceExit);
-        fStart();
     }
 
     // ==========================
@@ -659,9 +669,10 @@
         fLinksTimer = $timeout(_updateLinks, 150);
     }
 
+    // IMPLEMENTATION NOTE: _updateLinks() should NOT stop, start, or resume
+    //  the force layout; that needs to be determined and implemented elsewhere
     function _updateLinks() {
         var th = ts.theme();
-        force.stop();
 
         link = linkG.selectAll('.link')
             .data(network.links, function (d) { return d.key; });
@@ -714,7 +725,6 @@
             })
             .style('opacity', 0.0)
             .remove();
-        fStart();
     }
 
 
@@ -729,14 +739,23 @@
 
     function fStart() {
         if (!tos.isOblique()) {
-            $log.debug("Starting force-layout");
-            force.start();
+            if (fTimer) {
+                $timeout.cancel(fTimer);
+            }
+            fTimer = $timeout(function () {
+                $log.debug("Starting force-layout");
+                force.start();
+            }, 200);
         }
     }
 
     var tickStuff = {
         nodeAttr: {
-            transform: function (d) { return sus.translate(d.x, d.y); }
+            transform: function (d) {
+                var dx = isNaN(d.x) ? 0 : d.x,
+                    dy = isNaN(d.y) ? 0 : d.y;
+                return sus.translate(dx, dy);
+            }
         },
         linkAttr: {
             x1: function (d) { return d.position.x1; },
@@ -1046,6 +1065,9 @@
                 force = drag = null;
 
                 // clean up $timeout promises
+                if (fTimer) {
+                    $timeout.cancel(fTimer);
+                }
                 if (fNodesTimer) {
                     $timeout.cancel(fNodesTimer);
                 }
diff --git a/web/gui/src/main/webapp/app/view/topo/topoOverlay.js b/web/gui/src/main/webapp/app/view/topo/topoOverlay.js
index 41c8e1e..a049948 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoOverlay.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoOverlay.js
@@ -293,7 +293,7 @@
              findLinkById( id )
          */
 
-        var paths = data.paths;
+        var paths = data.links;
 
         api.clearLinkTrafficStyle();
         api.removeLinkLabels();
diff --git a/web/gui/src/main/webapp/app/view/topo/topoSelect.js b/web/gui/src/main/webapp/app/view/topo/topoSelect.js
index 2e73ea2..72a689f 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoSelect.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoSelect.js
@@ -114,7 +114,7 @@
         }
 
         if (!ev.shiftKey) {
-            deselectAll();
+            deselectAll(true);
         }
 
         selections[obj.id] = { obj: obj, el: el };
@@ -135,7 +135,7 @@
         }
     }
 
-    function deselectAll() {
+    function deselectAll(skipUpdate) {
         var something = (selectOrder.length > 0);
 
         // deselect all nodes in the network...
@@ -143,7 +143,9 @@
         selections = {};
         selectOrder = [];
         api.updateDeviceColors();
-        updateDetail();
+        if (!skipUpdate) {
+            updateDetail();
+        }
 
         // return true if something was selected
         return something;
diff --git a/web/gui/src/main/webapp/app/view/topo/topoTraffic.js b/web/gui/src/main/webapp/app/view/topo/topoTraffic.js
index 27ec979..9308542 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoTraffic.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoTraffic.js
@@ -42,9 +42,9 @@
 
     // invoked in response to change in selection and/or mouseover/out:
     function requestTrafficForMode() {
-        if (hoverMode === 'flows') {
+        if (trafficMode === 'flows') {
             requestDeviceLinkFlows();
-        } else if (hoverMode === 'intents') {
+        } else if (trafficMode === 'intents') {
             requestRelatedIntents();
         } else {
             cancelTraffic();
@@ -175,7 +175,6 @@
     }
 
 
-
     // === -----------------------------------------------------
     // === MODULE DEFINITION ===