Add GUI badging to hosts

Change-Id: I5c791acd6696b455b4416d2dd413edcf30d41886
diff --git a/core/api/src/main/java/org/onosproject/ui/topo/TopoJson.java b/core/api/src/main/java/org/onosproject/ui/topo/TopoJson.java
index 4030abd..efe69f5 100644
--- a/core/api/src/main/java/org/onosproject/ui/topo/TopoJson.java
+++ b/core/api/src/main/java/org/onosproject/ui/topo/TopoJson.java
@@ -131,6 +131,10 @@
         if (hh.subdued()) {
             n.put(SUBDUE, true);
         }
+        NodeBadge badge = hh.badge();
+        if (badge != null) {
+            n.set(BADGE, json(badge));
+        }
         return n;
     }
 
diff --git a/web/gui/src/main/webapp/app/view/topo/topoD3.js b/web/gui/src/main/webapp/app/view/topo/topoD3.js
index 1d2c5b1..168e9ce 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoD3.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoD3.js
@@ -265,6 +265,51 @@
         }
     }
 
+    function updateHostRendering(d) {
+        var node = d.el,
+            dim = icfg.host.radius.withGlyph,
+            box, dx, dy, bsel,
+            bdg = d.badge,
+            bcr = badgeConfig.radius,
+            bcgd = badgeConfig.gdelta;
+
+
+        updateHostLabel(d);
+        
+        // TODO: fine-tune dx, dy for badge placement relative to host Circle.
+            dx = -dim/2;
+            dy = -dim/2;
+
+        // handle badge, if defined
+        if (bdg) {
+            node.select('g.badge').remove();
+
+            bsel = node.append('g')
+                .classed('badge', true)
+                .classed(badgeStatus(bdg), true)
+                .attr('transform', sus.translate(dx + dim, dy));
+
+            bsel.append('circle')
+                .attr('r', bcr);
+
+            if (bdg.txt) {
+                bsel.append('text')
+                    .attr('dy', badgeConfig.yoff)
+                    .attr('text-anchor', 'middle')
+                    .text(bdg.txt);
+            } else if (bdg.gid) {
+                bsel.append('use')
+                    .attr({
+                        width: bcgd * 2,
+                        height: bcgd * 2,
+                        transform: sus.translate(-bcgd, -bcgd),
+                        'xlink:href': '#' + bdg.gid
+                    });
+
+            }
+        }
+    }
+
     function updateHostLabel(d) {
         var label = trimLabel(hostLabel(d));
         d.el.select('text').text(label);
@@ -292,7 +337,7 @@
     }
 
     function hostExisting(d) {
-        updateHostLabel(d);
+        updateHostRendering(d);
         api.posNode(d, true);
     }
 
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 2dee4c4..fb7921a 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoOverlay.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoOverlay.js
@@ -312,8 +312,11 @@
         }
 
         data.hosts.forEach(function (host) {
-            var hdata = api.findNodeById(host.id);
+            var hdata = api.findNodeById(host.id),
+                badgeData = host.badge || null;
+
             if (hdata && !hdata.el.empty()) {
+                hdata.badge = badgeData;
                 if (!host.subdue) {
                     api.unsupNode(hdata.id, less);
                 }