GUI -- Added CSS classes for primary, secondary, animated, and optical links
 - refactored showTraffic(...) to handle the updated payload.
 - created 'traffic' scenario:: run with ... webapp/index2.html#topo,traffic?local

Change-Id: I5e3a33abcbc9c82f751165b4f52807f7cd59ef03
diff --git a/web/gui/src/main/webapp/json/ev/intentSketch/ev_3_ui.json b/web/gui/src/main/webapp/json/ev/intentSketch/ev_3_ui.json
index e15f211..f6a2b17 100644
--- a/web/gui/src/main/webapp/json/ev/intentSketch/ev_3_ui.json
+++ b/web/gui/src/main/webapp/json/ev/intentSketch/ev_3_ui.json
@@ -2,6 +2,7 @@
   "event": "requestTraffic",
   "sid": 2,
   "payload": {
-    "ids": [ "00:00:00:00:00:01/-1",  "00:00:00:00:00:02/-1" ]
+    "ids": [ "00:00:00:00:00:01/-1",  "00:00:00:00:00:02/-1" ],
+    "hover": ""
   }
 }
diff --git a/web/gui/src/main/webapp/json/ev/traffic/ev_10_onos.json b/web/gui/src/main/webapp/json/ev/traffic/ev_10_onos.json
new file mode 100644
index 0000000..b25604d
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/traffic/ev_10_onos.json
@@ -0,0 +1,15 @@
+{
+  "event": "addLink",
+  "payload": {
+    "id": "of:0000ffffffff0003/4-of:0000ffffffffff03/1",
+    "type": "direct",
+    "linkWidth": 2,
+    "src": "of:0000ffffffff0003",
+    "srcPort": "4",
+    "dst": "of:0000ffffffffff03",
+    "dstPort": "1",
+    "props" : {
+      "BW": "90 Gb"
+    }
+  }
+}
diff --git a/web/gui/src/main/webapp/json/ev/traffic/ev_11_onos.json b/web/gui/src/main/webapp/json/ev/traffic/ev_11_onos.json
new file mode 100644
index 0000000..2939f35
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/traffic/ev_11_onos.json
@@ -0,0 +1,15 @@
+{
+  "event": "addLink",
+  "payload": {
+    "id": "of:0000ffffffffff08/4-of:0000ffffffffff03/1",
+    "type": "direct",
+    "linkWidth": 2,
+    "src": "of:0000ffffffffff08",
+    "srcPort": "4",
+    "dst": "of:0000ffffffffff03",
+    "dstPort": "1",
+    "props" : {
+      "BW": "90 Gb"
+    }
+  }
+}
diff --git a/web/gui/src/main/webapp/json/ev/traffic/ev_12_onos.json b/web/gui/src/main/webapp/json/ev/traffic/ev_12_onos.json
new file mode 100644
index 0000000..a5ee5c9
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/traffic/ev_12_onos.json
@@ -0,0 +1,17 @@
+{
+  "event": "addHost",
+  "payload": {
+    "id": "0E:2A:69:30:13:86/-1",
+    "ingress": "0E:2A:69:30:13:86/-1/0-of:0000ffffffff0003/101",
+    "egress": "of:0000ffffffff0003/101-0E:2A:69:30:13:86/-1/0",
+    "cp": {
+      "device": "of:0000ffffffff0003",
+      "port": 101
+    },
+    "labels": [
+      "1.2.3.4",
+      "0E:2A:69:30:13:86"
+    ],
+    "props": {}
+  }
+}
diff --git a/web/gui/src/main/webapp/json/ev/traffic/ev_13_onos.json b/web/gui/src/main/webapp/json/ev/traffic/ev_13_onos.json
new file mode 100644
index 0000000..6efcda9
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/traffic/ev_13_onos.json
@@ -0,0 +1,17 @@
+{
+  "event": "addHost",
+  "payload": {
+    "id": "0E:2A:69:30:13:88/-1",
+    "ingress": "0E:2A:69:30:13:88/-1/0-of:0000ffffffff0007/101",
+    "egress": "of:0000ffffffff0007/101-0E:2A:69:30:13:86/-1/0",
+    "cp": {
+      "device": "of:0000ffffffff0007",
+      "port": 101
+    },
+    "labels": [
+      "4.5.7.6",
+      "0E:2A:69:30:13:88"
+    ],
+    "props": {}
+  }
+}
diff --git a/web/gui/src/main/webapp/json/ev/traffic/ev_14_onos.json b/web/gui/src/main/webapp/json/ev/traffic/ev_14_onos.json
new file mode 100644
index 0000000..af031a6
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/traffic/ev_14_onos.json
@@ -0,0 +1,17 @@
+{
+  "event": "addHost",
+  "payload": {
+    "id": "0E:2A:69:30:13:aa/-1",
+    "ingress": "0E:2A:69:30:13:aa/-1/0-of:0000ffffffff0008/101",
+    "egress": "of:0000ffffffff0008/101-0E:2A:69:30:13:aa/-1/0",
+    "cp": {
+      "device": "of:0000ffffffff0008",
+      "port": 101
+    },
+    "labels": [
+      "12.13.14.15",
+      "0E:2A:69:30:13:aa"
+    ],
+    "props": {}
+  }
+}
diff --git a/web/gui/src/main/webapp/json/ev/traffic/ev_15_onos.json b/web/gui/src/main/webapp/json/ev/traffic/ev_15_onos.json
new file mode 100644
index 0000000..657900c
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/traffic/ev_15_onos.json
@@ -0,0 +1,25 @@
+{
+  "event": "showTraffic",
+  "sid": 1,
+  "payload": {
+    "paths": [
+      {
+        "intentId": "0x4321",
+        "links": [
+          "0E:2A:69:30:13:86/-1/0-of:0000ffffffff0003/101",
+          "0E:2A:69:30:13:aa/-1/0-of:0000ffffffff0008/101"
+        ],
+        "class": "primary"
+      },
+      {
+        "intentId": "0xbab3",
+        "links": [
+          "of:0000ffffffff0003/4-of:0000ffffffffff03/1",
+          "of:0000ffffffff0008/4-of:0000ffffffffff08/1",
+          "of:0000ffffffffff08/4-of:0000ffffffffff03/1"
+        ],
+        "class": "primary optical"
+      }
+    ]
+  }
+}
diff --git a/web/gui/src/main/webapp/json/ev/traffic/ev_16_onos.json b/web/gui/src/main/webapp/json/ev/traffic/ev_16_onos.json
new file mode 100644
index 0000000..5198454
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/traffic/ev_16_onos.json
@@ -0,0 +1,25 @@
+{
+  "event": "showTraffic",
+  "sid": 1,
+  "payload": {
+    "paths": [
+      {
+        "intentId": "0x4321",
+        "links": [
+          "0E:2A:69:30:13:86/-1/0-of:0000ffffffff0003/101",
+          "0E:2A:69:30:13:aa/-1/0-of:0000ffffffff0008/101"
+        ],
+        "class": "secondary"
+      },
+      {
+        "intentId": "0xbab3",
+        "links": [
+          "of:0000ffffffff0003/4-of:0000ffffffffff03/1",
+          "of:0000ffffffff0008/4-of:0000ffffffffff08/1",
+          "of:0000ffffffffff08/4-of:0000ffffffffff03/1"
+        ],
+        "class": "secondary optical"
+      }
+    ]
+  }
+}
diff --git a/web/gui/src/main/webapp/json/ev/traffic/ev_17_onos.json b/web/gui/src/main/webapp/json/ev/traffic/ev_17_onos.json
new file mode 100644
index 0000000..0a1fd74
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/traffic/ev_17_onos.json
@@ -0,0 +1,25 @@
+{
+  "event": "showTraffic",
+  "sid": 1,
+  "payload": {
+    "paths": [
+      {
+        "intentId": "0x4321",
+        "links": [
+          "0E:2A:69:30:13:86/-1/0-of:0000ffffffff0003/101",
+          "0E:2A:69:30:13:aa/-1/0-of:0000ffffffff0008/101"
+        ],
+        "class": "animated"
+      },
+      {
+        "intentId": "0xbab3",
+        "links": [
+          "of:0000ffffffff0003/4-of:0000ffffffffff03/1",
+          "of:0000ffffffff0008/4-of:0000ffffffffff08/1",
+          "of:0000ffffffffff08/4-of:0000ffffffffff03/1"
+        ],
+        "class": "animated optical"
+      }
+    ]
+  }
+}
diff --git a/web/gui/src/main/webapp/json/ev/traffic/ev_18_onos.json b/web/gui/src/main/webapp/json/ev/traffic/ev_18_onos.json
new file mode 100644
index 0000000..571ba99
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/traffic/ev_18_onos.json
@@ -0,0 +1,50 @@
+{
+  "event": "showTraffic",
+  "sid": 1,
+  "payload": {
+    "paths": [
+      {
+        "intentId": "0x1234",
+        "links": [
+          "of:0000ffffffff0008/2-of:0000ffffffff0003/1"
+        ],
+        "class": "primary"
+      },
+      {
+        "intentId": "0x4321",
+        "links": [
+          "of:0000ffffffff0003/9-of:0000ffffffff0007/2"
+        ],
+        "class": "secondary"
+      },
+      {
+        "intentId": "0xbabe",
+        "links": [
+          "of:0000ffffffff0008/4-of:0000ffffffff0007/1"
+        ],
+        "class": "animated"
+      },
+      {
+        "intentId": "0xbab1",
+        "links": [
+          "of:0000ffffffff0008/4-of:0000ffffffffff08/1"
+        ],
+        "class": "primary optical"
+      },
+      {
+        "intentId": "0xbab2",
+        "links": [
+          "of:0000ffffffff0003/4-of:0000ffffffffff03/1"
+        ],
+        "class": "secondary optical"
+      },
+      {
+        "intentId": "0xbab3",
+        "links": [
+          "of:0000ffffffffff08/4-of:0000ffffffffff03/1"
+        ],
+        "class": "animated optical"
+      }
+    ]
+  }
+}
diff --git a/web/gui/src/main/webapp/json/ev/traffic/ev_19_onos.json b/web/gui/src/main/webapp/json/ev/traffic/ev_19_onos.json
new file mode 100644
index 0000000..6d3c08a
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/traffic/ev_19_onos.json
@@ -0,0 +1,8 @@
+{
+  "event": "showTraffic",
+  "sid": 1,
+  "payload": {
+    "paths": [
+    ]
+  }
+}
diff --git a/web/gui/src/main/webapp/json/ev/traffic/ev_1_onos.json b/web/gui/src/main/webapp/json/ev/traffic/ev_1_onos.json
new file mode 100644
index 0000000..1357cef
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/traffic/ev_1_onos.json
@@ -0,0 +1,17 @@
+{
+  "event": "addDevice",
+  "payload": {
+    "id": "of:0000ffffffff0008",
+    "type": "switch",
+    "online": true,
+    "labels": [
+      "0000ffffffff0008",
+      "FF:FF:FF:FF:00:08",
+      "sw-8"
+    ],
+    "metaUi": {
+      "x": 734,
+      "y": 477
+    }
+  }
+}
diff --git a/web/gui/src/main/webapp/json/ev/traffic/ev_2_onos.json b/web/gui/src/main/webapp/json/ev/traffic/ev_2_onos.json
new file mode 100644
index 0000000..df9b623
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/traffic/ev_2_onos.json
@@ -0,0 +1,17 @@
+{
+  "event": "addDevice",
+  "payload": {
+    "id": "of:0000ffffffff0003",
+    "type": "switch",
+    "online": true,
+    "labels": [
+      "0000ffffffff0003",
+      "FF:FF:FF:FF:00:03",
+      "sw-3"
+    ],
+    "metaUi": {
+      "x": 282,
+      "y": 503
+    }
+  }
+}
diff --git a/web/gui/src/main/webapp/json/ev/traffic/ev_3_onos.json b/web/gui/src/main/webapp/json/ev/traffic/ev_3_onos.json
new file mode 100644
index 0000000..d49d597
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/traffic/ev_3_onos.json
@@ -0,0 +1,17 @@
+{
+  "event": "addDevice",
+  "payload": {
+    "id": "of:0000ffffffff0007",
+    "type": "switch",
+    "online": true,
+    "labels": [
+      "0000ffffffff0007",
+      "FF:FF:FF:FF:00:07",
+      "sw-7"
+    ],
+    "metaUi": {
+      "x": 530,
+      "y": 330
+    }
+  }
+}
diff --git a/web/gui/src/main/webapp/json/ev/traffic/ev_4_onos.json b/web/gui/src/main/webapp/json/ev/traffic/ev_4_onos.json
new file mode 100644
index 0000000..631ed27
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/traffic/ev_4_onos.json
@@ -0,0 +1,17 @@
+{
+  "event": "addDevice",
+  "payload": {
+    "id": "of:0000ffffffffff08",
+    "type": "roadm",
+    "online": true,
+    "labels": [
+      "0000ffffffffff08",
+      "FF:FF:FF:FF:FF:08",
+      "opt-8"
+    ],
+    "metaUi": {
+      "x": 734,
+      "y": 577
+    }
+  }
+}
diff --git a/web/gui/src/main/webapp/json/ev/traffic/ev_5_onos.json b/web/gui/src/main/webapp/json/ev/traffic/ev_5_onos.json
new file mode 100644
index 0000000..4c8cc7c
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/traffic/ev_5_onos.json
@@ -0,0 +1,17 @@
+{
+  "event": "addDevice",
+  "payload": {
+    "id": "of:0000ffffffffff03",
+    "type": "roadm",
+    "online": true,
+    "labels": [
+      "0000ffffffffff03",
+      "FF:FF:FF:FF:FF:03",
+      "opt-3"
+    ],
+    "metaUi": {
+      "x": 282,
+      "y": 603
+    }
+  }
+}
diff --git a/web/gui/src/main/webapp/json/ev/traffic/ev_6_onos.json b/web/gui/src/main/webapp/json/ev/traffic/ev_6_onos.json
new file mode 100644
index 0000000..70dc216
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/traffic/ev_6_onos.json
@@ -0,0 +1,15 @@
+{
+  "event": "addLink",
+  "payload": {
+    "id": "of:0000ffffffff0003/9-of:0000ffffffff0007/2",
+    "type": "direct",
+    "linkWidth": 2,
+    "src": "of:0000ffffffff0003",
+    "srcPort": "9",
+    "dst": "of:0000ffffffff0007",
+    "dstPort": "2",
+    "props" : {
+      "BW": "120 Gb"
+    }
+  }
+}
diff --git a/web/gui/src/main/webapp/json/ev/traffic/ev_7_onos.json b/web/gui/src/main/webapp/json/ev/traffic/ev_7_onos.json
new file mode 100644
index 0000000..78e6a39
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/traffic/ev_7_onos.json
@@ -0,0 +1,15 @@
+{
+  "event": "addLink",
+  "payload": {
+    "id": "of:0000ffffffff0008/2-of:0000ffffffff0003/1",
+    "type": "direct",
+    "linkWidth": 2,
+    "src": "of:0000ffffffff0008",
+    "srcPort": "2",
+    "dst": "of:0000ffffffff0003",
+    "dstPort": "1",
+    "props" : {
+      "BW": "70 Gb"
+    }
+  }
+}
diff --git a/web/gui/src/main/webapp/json/ev/traffic/ev_8_onos.json b/web/gui/src/main/webapp/json/ev/traffic/ev_8_onos.json
new file mode 100644
index 0000000..d9d27e7
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/traffic/ev_8_onos.json
@@ -0,0 +1,15 @@
+{
+  "event": "addLink",
+  "payload": {
+    "id": "of:0000ffffffff0008/4-of:0000ffffffff0007/1",
+    "type": "direct",
+    "linkWidth": 2,
+    "src": "of:0000ffffffff0008",
+    "srcPort": "4",
+    "dst": "of:0000ffffffff0007",
+    "dstPort": "1",
+    "props" : {
+      "BW": "90 Gb"
+    }
+  }
+}
diff --git a/web/gui/src/main/webapp/json/ev/traffic/ev_9_onos.json b/web/gui/src/main/webapp/json/ev/traffic/ev_9_onos.json
new file mode 100644
index 0000000..8437c21
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/traffic/ev_9_onos.json
@@ -0,0 +1,15 @@
+{
+  "event": "addLink",
+  "payload": {
+    "id": "of:0000ffffffff0008/4-of:0000ffffffffff08/1",
+    "type": "direct",
+    "linkWidth": 2,
+    "src": "of:0000ffffffff0008",
+    "srcPort": "4",
+    "dst": "of:0000ffffffffff08",
+    "dstPort": "1",
+    "props" : {
+      "BW": "90 Gb"
+    }
+  }
+}
diff --git a/web/gui/src/main/webapp/json/ev/traffic/scenario.json b/web/gui/src/main/webapp/json/ev/traffic/scenario.json
new file mode 100644
index 0000000..06f9bf8
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/traffic/scenario.json
@@ -0,0 +1,16 @@
+{
+  "comments": [
+    "Stepping through showTraffic"
+  ],
+  "title": "Show Traffic Scenario",
+  "params": {
+    "lastAuto": 14
+  },
+  "description": [
+    "Figure out primary, secondary and animated link visualizations.",
+    "",
+    "Press 'S' to load initial events.",
+    "",
+    "Press spacebar to complete the scenario..."
+  ]
+}
diff --git a/web/gui/src/main/webapp/topo2.css b/web/gui/src/main/webapp/topo2.css
index 0d76c3b..0dcb470 100644
--- a/web/gui/src/main/webapp/topo2.css
+++ b/web/gui/src/main/webapp/topo2.css
@@ -108,10 +108,33 @@
     opacity: .7;
 }
 
-#topo svg .link.showPath {
-    stroke: #f00;
+#topo svg .link.primary {
+    stroke: #f11;
     stroke-width: 6px;
 }
+#topo svg .link.secondary {
+    stroke: rgba(255,100,100,0.5);
+    stroke-width: 4px;
+}
+#topo svg .link.animated {
+    stroke: #f11;
+    stroke-width: 10px;
+    stroke-dasharray: 8 8
+}
+
+#topo svg .link.primary.optical {
+    stroke: #74f;
+    stroke-width: 6px;
+}
+#topo svg .link.secondary.optical {
+    stroke: rgba(128,64,255,0.5);
+    stroke-width: 4px;
+}
+#topo svg .link.animated.optical {
+    stroke: #74f;
+    stroke-width: 10px;
+    stroke-dasharray: 8 8
+}
 
 
 /* Fly-in details pane */
diff --git a/web/gui/src/main/webapp/topo2.js b/web/gui/src/main/webapp/topo2.js
index 8e99e5f..ea3c6e6 100644
--- a/web/gui/src/main/webapp/topo2.js
+++ b/web/gui/src/main/webapp/topo2.js
@@ -120,9 +120,9 @@
 
     // key bindings
     var keyDispatch = {
-        //M: testMe,                  // TODO: remove (testing only)
-        //S: injectStartupEvents,     // TODO: remove (testing only)
-        //space: injectTestEvent,     // TODO: remove (testing only)
+        M: testMe,                  // TODO: remove (testing only)
+        S: injectStartupEvents,     // TODO: remove (testing only)
+        space: injectTestEvent,     // TODO: remove (testing only)
 
         B: toggleBg,
         L: cycleLabels,
@@ -159,8 +159,8 @@
         selectOrder = [],
         selections = {},
         hovered = null,
+        antTimer = null,
 
-        highlighted = null,
         viewMode = 'showAll',
         portLabelsOn = false;
 
@@ -503,23 +503,19 @@
     }
 
     function showTraffic(data) {
-        // TODO: review - making sure we are handling the payload correctly.
-        // TODO: handle 'class' of link: primary, secondary, animated...
         fnTrace('showTraffic', data.payload.id);
         var paths = data.payload.paths;
 
         // Revert any links hilighted previously.
-        network.links.forEach(function (d) {
-            d.el.classed('showPath', false);
-        });
+        link.classed('primary secondary animated optical', false);
 
         // Now hilight all links in the paths payload.
-        paths.forEach(function (d) {
-            var links = d.links;
-            links.forEach(function (d, i) {
-                var link = network.lookup[d];
-                if (link) {
-                    link.el.classed('showPath', true);
+        paths.forEach(function (p) {
+            var cls = p.class;
+            p.links.forEach(function (id) {
+                var lnk = network.lookup[id];
+                if (lnk) {
+                    lnk.el.classed(cls, true);
                 }
             });
         });
@@ -1174,8 +1170,10 @@
         _send : function(message) {
             if (webSock.ws) {
                 webSock.ws.send(message);
-            } else {
+            } else if (config.useLiveData) {
                 network.view.alert('no web socket open\n\n' + message);
+            } else {
+                console.log('WS Send: ' + JSON.stringify(message));
             }
         }
 
@@ -1536,6 +1534,8 @@
             d3.select(self).classed('fixed', true);
             if (config.useLiveData) {
                 sendUpdateMeta(d);
+            } else {
+                console.log('Moving node ' + d.id + ' to [' + d.x + ',' + d.y + ']');
             }
         }
 
@@ -1599,6 +1599,21 @@
 
         // Load map data asynchronously; complete startup after that..
         loadGeoJsonData();
+
+        // start the and timer
+        var dashIdx = 0;
+        antTimer = setInterval(function () {
+            // TODO: figure out how to choose Src-->Dst and Dst-->Src, per link
+            dashIdx = dashIdx === 0 ? 14 : dashIdx - 2;
+            d3.selectAll('.animated').style('stroke-dashoffset', dashIdx);
+        }, 35);
+    }
+
+    function unload(view, ctx, flags) {
+        if (antTimer) {
+            clearInterval(antTimer);
+            antTimer = null;
+        }
     }
 
     // TODO: move these to config/state portion of script
@@ -1687,6 +1702,7 @@
     onos.ui.addView('topo', {
         preload: preload,
         load: load,
+        unload: unload,
         resize: resize
     });