GUI -- ONOS-1172 - Added 'dash' keystroke to report on bad links.

Change-Id: Ie4226b25d4219001be17add8b501e1a77585334a
diff --git a/web/gui/src/main/webapp/app/fw/layer/quickhelp.js b/web/gui/src/main/webapp/app/fw/layer/quickhelp.js
index 4e8ac05a..d5e8c0d 100644
--- a/web/gui/src/main/webapp/app/fw/layer/quickhelp.js
+++ b/web/gui/src/main/webapp/app/fw/layer/quickhelp.js
@@ -50,7 +50,6 @@
     // key-logical-name to key-display lookup..
     var keyDisp = {
         equals: '=',
-        dash: '-',
         slash: '/',
         backSlash: '\\',
         backQuote: '`',
diff --git a/web/gui/src/main/webapp/app/view/topo/topo.js b/web/gui/src/main/webapp/app/view/topo/topo.js
index 4ce8348..0579a98 100644
--- a/web/gui/src/main/webapp/app/view/topo/topo.js
+++ b/web/gui/src/main/webapp/app/view/topo/topo.js
@@ -49,8 +49,9 @@
 
             H: [tfs.toggleHosts, 'Toggle host visibility'],
             M: [tfs.toggleOffline, 'Toggle offline visibility'],
-            B: [toggleMap, 'Toggle background map'],
             P: [tfs.togglePorts, 'Toggle Port Highlighting'],
+            dash: [tfs.showBadLinks, 'Show bad links'],
+            B: [toggleMap, 'Toggle background map'],
 
             //X: [toggleNodeLock, 'Lock / unlock node positions'],
             Z: [tos.toggleOblique, 'Toggle oblique view (Experimental)'],
@@ -73,7 +74,7 @@
             _keyListener: ttbs.keyListener,
 
             _helpFormat: [
-                ['I', 'O', 'D', '-', 'H', 'M', 'P', 'B' ],
+                ['I', 'O', 'D', '-', 'H', 'M', 'P', 'dash', 'B' ],
                 ['X', 'Z', 'L', 'U', 'R', '-', 'dot'],
                 ['V', 'rightArrow', 'leftArrow', 'W', 'A', 'F', '-', 'E' ]
             ]
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 11f4934..bbc697d 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoForce.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoForce.js
@@ -23,7 +23,7 @@
     'use strict';
 
     // injected refs
-    var $log, fs, sus, is, ts, flash, wss,
+    var $log, $timeout, fs, sus, is, ts, flash, wss,
         tis, tms, td3, tss, tts, tos, fltr, tls,
         icfg, uplink, svg;
 
@@ -263,6 +263,7 @@
             online = ldata.online(),
             delay = immediate ? 0 : 1000;
 
+        // TODO: understand why el is sometimes undefined on addLink events...
         el.classed('link', true);
         el.classed('inactive', !online);
         el.classed(allLinkTypes, false);
@@ -450,6 +451,21 @@
 //        d3.selectAll('svg .portText').classed('inactive', b);
     }
 
+    function showBadLinks() {
+        var badLinks = tms.findBadLinks();
+        flash.flash('Bad Links: ' + badLinks.length);
+        $log.debug('Bad Link List (' + badLinks.length + '):');
+        badLinks.forEach(function (d) {
+            $log.debug('bad link: (' + d.bad + ') ' + d.key, d);
+            if (d.el) {
+                d.el.attr('stroke-width', linkScale(2.8))
+                    .attr('stroke', 'red');
+            }
+        });
+        // back to normal after 2 seconds...
+        $timeout(updateLinks, 2000);
+    }
+
     // ==========================================
 
     function updateNodes() {
@@ -749,15 +765,16 @@
 
     angular.module('ovTopo')
     .factory('TopoForceService',
-        ['$log', 'FnService', 'SvgUtilService', 'IconService', 'ThemeService',
-            'FlashService', 'WebSocketService',
+        ['$log', '$timeout', 'FnService', 'SvgUtilService', 'IconService',
+            'ThemeService', 'FlashService', 'WebSocketService',
             'TopoInstService', 'TopoModelService',
             'TopoD3Service', 'TopoSelectService', 'TopoTrafficService',
             'TopoObliqueService', 'TopoFilterService', 'TopoLinkService',
 
-        function (_$log_, _fs_, _sus_, _is_, _ts_, _flash_, _wss_,
+        function (_$log_, _$timeout_, _fs_, _sus_, _is_, _ts_, _flash_, _wss_,
                   _tis_, _tms_, _td3_, _tss_, _tts_, _tos_, _fltr_, _tls_) {
             $log = _$log_;
+            $timeout = _$timeout_;
             fs = _fs_;
             sus = _sus_;
             is = _is_;
@@ -874,6 +891,7 @@
                 cycleDeviceLabels: cycleDeviceLabels,
                 unpin: unpin,
                 showMastership: showMastership,
+                showBadLinks: showBadLinks,
 
                 addDevice: addDevice,
                 updateDevice: updateDevice,
diff --git a/web/gui/src/main/webapp/app/view/topo/topoModel.js b/web/gui/src/main/webapp/app/view/topo/topoModel.js
index 0a75652..6bec7e8 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoModel.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoModel.js
@@ -341,15 +341,37 @@
     }
 
     function findAttachedLinks(devId) {
-        var links = [];
+        var lnks = [];
         links.forEach(function (d) {
             if (d.source.id === devId || d.target.id === devId) {
-                links.push(d);
+                lnks.push(d);
             }
         });
-        return links;
+        return lnks;
     }
 
+    // returns one-way links or where the internal link types differ
+    function findBadLinks() {
+        var lnks = [],
+            src, tgt;
+        links.forEach(function (d) {
+            // NOTE: skip edge links, which are synthesized
+            if (d.type() !== 'hostLink') {
+                delete d.bad;
+                src = d.fromSource;
+                tgt = d.fromTarget;
+                if (src && !tgt) {
+                    d.bad = 'missing link';
+                } else if (src.type !== tgt.type) {
+                    d.bad = 'type mismatch';
+                }
+                if (d.bad) {
+                    lnks.push(d);
+                }
+            }
+        });
+        return lnks;
+    }
 
     // ==========================
     // Module definition
@@ -394,7 +416,8 @@
                 findLinkById: findLinkById,
                 findDevices: findDevices,
                 findAttachedHosts: findAttachedHosts,
-                findAttachedLinks: findAttachedLinks
+                findAttachedLinks: findAttachedLinks,
+                findBadLinks: findBadLinks
             }
         }]);
 }());