GUI -- added removeHost code; augmented 'simple' scenario to include removeHost.
- flattened lat/long in device props "bag" - example events.

Change-Id: I1e619c84842c5fc4ab7a9dc59452c358f0ce7b10
diff --git a/web/gui/src/main/webapp/json/ev/_capture/rx/addDevice_ex1.json b/web/gui/src/main/webapp/json/ev/_capture/rx/addDevice_ex1.json
index 822fc25..b82fda8 100644
--- a/web/gui/src/main/webapp/json/ev/_capture/rx/addDevice_ex1.json
+++ b/web/gui/src/main/webapp/json/ev/_capture/rx/addDevice_ex1.json
@@ -11,11 +11,8 @@
       null
     ],
     "props": {
-      "location": {
-        "type": "latlng",
-        "lat": 123.5,
-        "lng": 67.8
-      },
+      "latitude": 123.5,
+      "longitude": 67.8,
       "anotherProp": "foobar"
     }
   }
diff --git a/web/gui/src/main/webapp/json/ev/_capture/rx/addDevice_ex2_memo.json b/web/gui/src/main/webapp/json/ev/_capture/rx/addDevice_ex2_memo.json
index cc8f459..5f519ff 100644
--- a/web/gui/src/main/webapp/json/ev/_capture/rx/addDevice_ex2_memo.json
+++ b/web/gui/src/main/webapp/json/ev/_capture/rx/addDevice_ex2_memo.json
@@ -11,11 +11,8 @@
       null
     ],
     "props": {
-      "location": {
-        "type": "latlng",
-        "lat": 123.5,
-        "lng": 67.8
-      },
+      "latitude": 123.5,
+      "longitude": 67.8,
       "anotherProp": "foobar"
     },
     "metaUi": {
diff --git a/web/gui/src/main/webapp/json/ev/simple/ev_13_onos.json b/web/gui/src/main/webapp/json/ev/simple/ev_13_onos.json
new file mode 100644
index 0000000..5320841
--- /dev/null
+++ b/web/gui/src/main/webapp/json/ev/simple/ev_13_onos.json
@@ -0,0 +1,17 @@
+{
+  "event": "removeHost",
+  "payload": {
+    "id": "A6:96:E5:03:52:5F/-1",
+    "ingress": "A6:96:E5:03:52:5F/-1/0-of:0000ffffffff0008/1",
+    "egress": "of:0000ffffffff0008/1-A6:96:E5:03:52:5F/-1/0",
+    "cp": {
+      "device": "of:0000ffffffff0008",
+      "port": 1
+    },
+    "labels": [
+      "10.0.0.17",
+      "A6:96:E5:03:52:5F"
+    ],
+    "props": {}
+  }
+}
diff --git a/web/gui/src/main/webapp/json/ev/simple/ev_13_ui.json b/web/gui/src/main/webapp/json/ev/simple/ev_13_ui.json
deleted file mode 100644
index 9d6e737..0000000
--- a/web/gui/src/main/webapp/json/ev/simple/ev_13_ui.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "event": "noop",
-  "payload": {
-    "id": "xyyzy"
-  }
-}
diff --git a/web/gui/src/main/webapp/json/ev/simple/scenario.json b/web/gui/src/main/webapp/json/ev/simple/scenario.json
index c47d40e..4c55b2d 100644
--- a/web/gui/src/main/webapp/json/ev/simple/scenario.json
+++ b/web/gui/src/main/webapp/json/ev/simple/scenario.json
@@ -20,6 +20,6 @@
     "10. update link (increase width, update props)",
     "11. update link (reduce width, update props)",
     "12. remove link",
-    ""
+    "13. remove host (10.0.0.17)"
   ]
 }
diff --git a/web/gui/src/main/webapp/topo2.js b/web/gui/src/main/webapp/topo2.js
index 86aca72..64825dc 100644
--- a/web/gui/src/main/webapp/topo2.js
+++ b/web/gui/src/main/webapp/topo2.js
@@ -352,7 +352,7 @@
         updateHost: updateHost,
         removeDevice: stillToImplement,
         removeLink: removeLink,
-        removeHost: stillToImplement,
+        removeHost: removeHost,
         showPath: showPath
     };
 
@@ -389,6 +389,7 @@
 
         lnk = createHostLink(host);
         if (lnk) {
+            node.linkData = lnk;    // cache ref on its host
             network.links.push(lnk);
             network.lookup[host.ingress] = lnk;
             network.lookup[host.egress] = lnk;
@@ -397,6 +398,7 @@
         network.force.start();
     }
 
+    // TODO: fold updateX(...) methods into one base method; remove duplication
     function updateDevice(data) {
         fnTrace('updateDevice', data.payload.id);
         var device = data.payload,
@@ -436,6 +438,7 @@
         }
     }
 
+    // TODO: fold removeX(...) methods into base method - remove dup code
     function removeLink(data) {
         fnTrace('removeLink', data.payload.id);
         var link = data.payload,
@@ -448,6 +451,18 @@
         }
     }
 
+    function removeHost(data) {
+        fnTrace('removeHost', data.payload.id);
+        var host = data.payload,
+            id = host.id,
+            hostData = network.lookup[id];
+        if (hostData) {
+            removeHostElement(hostData);
+        } else {
+            logicError('removeHost lookup fail. ID = "' + id + '"');
+        }
+    }
+
     function showPath(data) {
         fnTrace('showPath', data.payload.id);
         var links = data.payload.links,
@@ -604,7 +619,6 @@
         //link .foo() .bar() ...
 
         // operate on exiting links:
-        // TODO: better transition (longer as a dashed, grey line)
         link.exit()
             .attr({
                 'stroke-dasharray': '3, 3'
@@ -873,11 +887,12 @@
         // TODO: figure out how to remove the node 'g' AND its children
         node.exit()
             .transition()
-            .duration(750)
+            .style('opacity', 0.4)
+            .attr('fill', '#888')
+            .transition()
+            .duration(2000)
             .attr({
                 opacity: 0,
-                cx: 0,
-                cy: 0,
                 r: 0
             })
             .remove();
@@ -897,12 +912,27 @@
         delete network.lookup[linkData.id];
         // remove from links array
         var idx = find(linkData.id, network.links);
-
         network.links.splice(idx, 1);
         // remove from SVG
         updateLinks();
+        network.force.resume();
     }
 
+    function removeHostElement(hostData) {
+        // first, remove associated hostLink...
+        removeLinkElement(hostData.linkData);
+
+        // remove from lookup cache
+        delete network.lookup[hostData.id];
+        // remove from nodes array
+        var idx = find(hostData.id, network.nodes);
+        network.nodes.splice(idx, 1);
+        // remove from SVG
+        updateNodes();
+        network.force.resume();
+    }
+
+
     function tick() {
         node.attr({
             transform: function (d) { return translate(d.x, d.y); }