GUI - Converted Devices to use Glyph icons instead of png's.

Change-Id: I5d979f6e515168fda2c2eabe97780beaa5206691
diff --git a/web/gui/src/main/webapp/_sdh/icons.html b/web/gui/src/main/webapp/_sdh/icons.html
new file mode 100644
index 0000000..50807de
--- /dev/null
+++ b/web/gui/src/main/webapp/_sdh/icons.html
@@ -0,0 +1,215 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <title>Icons</title>
+
+    <script src="../libs/d3.js"></script>
+    <script src="../libs/topojson.v1.min.js"></script>
+    <script src="../libs/jquery-2.1.1.min.js"></script>
+
+    <style>
+        html,
+        body {
+            background-color: #ddf;
+            font-family: Arial, Helvetica, sans-serif;
+            font-size: 9pt;
+        }
+
+        svg {
+            background-color: #fff;
+        }
+
+        svg .glyph {
+            stroke: none;
+            fill: black;
+            fill-rule: evenodd;
+        }
+
+        svg .device rect.iconBg {
+            fill: #ddd;
+            stroke: #000;
+        }
+
+        .hide {
+            visibility: hidden;
+        }
+
+    </style>
+</head>
+<body>
+    <svg width="1000px" height="600px" viewBox="0 0 1000 600"  >
+        <defs>
+            <symbol id="router" class="glyph" viewBox="-55 -55 110 110">
+                <path d="M-45 0 A45 45 0 0 1 45 0 A45 45 0 0 1 -45 0
+                M -35 -5 l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z
+                M 35 -5 l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z
+                M -5 -8 l 0 -12, -8 0, 13 -18, 13 18, -8 0, 0 12 z
+                M -5 8 l 0 12, -8 0, 13 18, 13 -18, -8 0, 0 -12 z
+                "></path>
+            </symbol>
+
+            <symbol id="bgpSpeaker" class="glyph" viewBox="-55 -55 110 110">
+                <path d="M-45 -15
+                a45 35 0 0 1 90 0
+                Q45 22 0 45
+                Q-45 22 -45 -15
+                z
+
+                M -5 -26 l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z
+                M 5 2 l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z
+
+                "></path>
+                <!--                a45 45 0 0 1 -10 30
+                -->
+            </symbol>
+
+            <symbol id="switch" class="glyph" viewBox="-55 -55 110 110">
+                <path d="M-45 -35 a10 10 0 0 1 10 -10 h70
+                a 10 10 0 0 1 10 10 v70
+                a 10 10 0 0 1 -10 10 h -70
+                a 10 10 0 0 1 -10 -10 z
+                M 5 -29 l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z
+                M 5 5 l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z
+                M -5 -15 l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z
+                M -5 19 l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z
+                "></path>
+            </symbol>
+
+            <symbol id="roadm" class="glyph" viewBox="-55 -55 110 110">
+                <path d="M-45 -20 l25 -25 h40 l25 25 v40
+                l-25 25 h-40 l-25 -25 z
+
+                M 3 -29 l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z
+                M 3 5 l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z
+                M -3 -15 l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z
+                M -3 19 l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z
+                "></path>
+            </symbol>
+
+            <symbol id="node" class="glyph" viewBox="-55 -55 110 110">
+                <path d="M-40 45 a5 5 0 0 1 -5 -5 v-65 a5 5 0 0 1 5 -5
+                 h80 a5 5 0 0 1 5 5 v65 a5 5 0 0 1 -5 5 z
+                 M-41 -32.5 l11 -11  a10 3 0 0 1 10 -2 h40
+                  a10 3 0 0 1 10 2 l11 11 z
+                 M-39 -20 a5 5 0 0 1 10 0 a5 5 0 0 1 -10 0 z
+                "></path>
+            </symbol>
+
+            <symbol id="nodeSlave" class="glyph" viewBox="-55 -55 110 110">
+                <path d="M-40 45 a5 5 0 0 1 -5 -5 v-65 a5 5 0 0 1 5 -5
+                 h80 a5 5 0 0 1 5 5 v65 a5 5 0 0 1 -5 5 z
+                 M-41 -32.5 l11 -11  a10 3 0 0 1 10 -2 h40
+                  a10 3 0 0 1 10 2 l11 11 z
+                 M-39 -20 a5 5 0 0 1 10 0 a5 5 0 0 1 -10 0 z
+
+                 M-6 -6
+                 l6 -6
+                 a8.485 8.485 0 0 1 12 12
+                 l-6 6
+                 a8.485 8.485 0 0 1 -13 -2
+                 l3 -3
+                 a4 4 0 0 0 6 1
+                 l8 -8
+                 a2.8 2.8 0 0 0 -5 -5
+                 l-5 5
+                 z
+
+                "></path>
+            </symbol>
+
+            <symbol id="host" class="glyph" viewBox="-55 -55 110 110">
+                <path d="M-45 -40 a5 5 0 0 1 5 -5 h65 a5 5 0 0 1 5 5
+                 v80 a5 5 0 0 1 -5 5 h-65 a5 5 0 0 1 -5 -5 z
+                 M32.5 -41 l11 11  a3 10 0 0 1 2 10 v40
+                  a3 10 0 0 1 -2 10 l-11 11 z
+
+                  M-38 -36
+                   a2 2 0 0 1 2 -2 h56
+                   a2 2 0 0 1 2 2 v26
+                   a2 2 0 0 1 -2 2 h-56
+                   a2 2 0 0 1 -2 -2
+                   z
+
+                  M-35 -35 h54 v10 h-54 z
+                  M-35 -22 h54 v10 h-54 z
+
+                 M-13 15 a5 5 0 0 1 10 0 a5 5 0 0 1 -10 0 z
+                "></path>
+            </symbol>
+
+            <symbol id="unknown" class="glyph" viewBox="-55 -55 110 110">
+                <path d="M-20 -15 a5 5 0 0 1 5 -5 h30 a5 5 0 0 1 5 5 v30 a5 5 0 0 1 -5 5 h-30 a5 5 0 0 1 -5 -5 z "></path>
+            </symbol>
+
+
+
+
+        </defs>
+        
+
+        <g transform="translate(10,10)scale(4)translate(0,20)" >
+
+            <g class="hide">
+                    <!--link-->
+                    <path fill="#010101" d="M459.654,233.373l-90.531,90.5c-49.969,50-131.031,50-181,0c-7.875-7.844-14.031-16.688-19.438-25.813
+                l42.063-42.063c2-2.016,4.469-3.172,6.828-4.531c2.906,9.938,7.984,19.344,15.797,27.156c24.953,24.969,65.563,24.938,90.5,0
+                l90.5-90.5c24.969-24.969,24.969-65.563,0-90.516c-24.938-24.953-65.531-24.953-90.5,0l-32.188,32.219
+                c-26.109-10.172-54.25-12.906-81.641-8.891l68.578-68.578c50-49.984,131.031-49.984,181.031,0
+                C509.623,102.342,509.623,183.389,459.654,233.373z M220.326,382.186l-32.203,32.219c-24.953,24.938-65.563,24.938-90.516,0
+                c-24.953-24.969-24.953-65.563,0-90.531l90.516-90.5c24.969-24.969,65.547-24.969,90.5,0c7.797,7.797,12.875,17.203,15.813,27.125
+                c2.375-1.375,4.813-2.5,6.813-4.5l42.063-42.047c-5.375-9.156-11.563-17.969-19.438-25.828c-49.969-49.984-131.031-49.984-181.016,0
+                l-90.5,90.5c-49.984,50-49.984,131.031,0,181.031c49.984,49.969,131.031,49.969,181.016,0l68.594-68.594
+                C274.561,395.092,246.42,392.342,220.326,382.186z"></path>
+
+
+                    <!--crown-->
+                    <path d="M94.257,32.808c0,4.466-3.62,8.085-8.085,8.085c-0.495,0-0.979-0.051-1.449-0.136l-6.637,23.695v8.518H21.914v-8.849
+                l-6.579-23.373c-0.489,0.092-0.992,0.145-1.507,0.145c-4.465,0-8.085-3.619-8.085-8.085c0-4.466,3.62-8.086,8.085-8.086
+                c4.465,0,8.085,3.62,8.085,8.086c0,1.099-0.222,2.146-0.619,3.102c8.078,2.726,20.551,4.947,26.163-4.449
+                c-3.219-1.066-5.543-4.095-5.543-7.671c0-4.466,3.62-8.086,8.085-8.086s8.085,3.62,8.085,8.086c0,3.573-2.32,6.6-5.536,7.669
+                c3.276,6.052,10.577,12.374,26.494,5.165c-0.608-1.137-0.957-2.435-0.957-3.815c0-4.466,3.62-8.086,8.085-8.086
+                S94.257,28.342,94.257,32.808z M21.915,84.297h56.173v-7.658H21.915V84.297z"></path>
+            </g>
+
+
+            <g class="show">
+                <g class="device" transform="translate(0,0)">
+                    <rect x="0" y="0" width="40" height="40" rx="4" class="iconBg"></rect>
+                    <use xlink:href="#router" width="40" height="40"></use>
+                </g>
+
+                <g class="device" transform="translate(50,0)">
+                    <rect x="0" y="0" width="40" height="40" rx="4" class="iconBg"></rect>
+                    <use xlink:href="#switch" width="40" height="40"></use>
+                </g>
+
+                <g class="device" transform="translate(100,0)">
+                    <rect x="0" y="0" width="40" height="40" rx="4" class="iconBg"></rect>
+                    <use xlink:href="#roadm" width="40" height="40"></use>
+                </g>
+
+                <g class="device" transform="translate(0,50)">
+                    <rect x="0" y="0" width="40" height="40" rx="4" class="iconBg"></rect>
+                    <use xlink:href="#node" width="40" height="40"></use>
+                </g>
+
+                <g class="device" transform="translate(50,50)">
+                    <rect x="0" y="0" width="40" height="40" rx="4" class="iconBg"></rect>
+                    <use xlink:href="#host" width="40" height="40"></use>
+                </g>
+
+                <g class="device" transform="translate(100,50)">
+                    <rect x="0" y="0" width="40" height="40" rx="4" class="iconBg"></rect>
+                    <use xlink:href="#bgpSpeaker" width="40" height="40"></use>
+                </g>
+
+                <g class="device" transform="translate(150,0)">
+                    <rect x="0" y="0" width="40" height="40" rx="4" class="iconBg"></rect>
+                    <use xlink:href="#unknown" width="40" height="40"></use>
+                </g>
+            </g>
+        </g>
+    </svg>
+</body>
+</html>
diff --git a/web/gui/src/main/webapp/glyphs.js b/web/gui/src/main/webapp/glyphs.js
index a794c62..49a0269 100644
--- a/web/gui/src/main/webapp/glyphs.js
+++ b/web/gui/src/main/webapp/glyphs.js
@@ -65,10 +65,64 @@
             .append('path').attr('d', bullhornData);
     }
 
+    var glyphData = {
+        unknown: "M-20 -15 a5 5 0 0 1 5 -5 h30 a5 5 0 0 1 5 5 v30 " +
+                "a5 5 0 0 1 -5 5 h-30 a5 5 0 0 1 -5 -5 z ",
+        router: "M-45 0 A45 45 0 0 1 45 0 A45 45 0 0 1 -45 0 M -35 -5 " +
+                "l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z M 35 -5 " +
+                "l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z M -5 -8 " +
+                "l 0 -12, -8 0, 13 -18, 13 18, -8 0, 0 12 z M -5 8 " +
+                "l 0 12, -8 0, 13 18, 13 -18, -8 0, 0 -12 z ",
+        bgpSpeaker: "M-45 -15 a45 35 0 0 1 90 0 Q45 22 0 45 Q-45 22 -45 -15 z " +
+                    "M -5 -26 l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z M 5 2" +
+                    " l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z ",
+
+        switch: "M-45 -35 a10 10 0 0 1 10 -10 h70 a 10 10 0 0 1 10 10 v70 a 10 10 0 0 1 -10 10 h -70 a 10 10 0 0 1 -10 -10 z M 5 -29 l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z M 5 5 l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z M -5 -15 l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z M -5 19 l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z",
+
+
+        Xswitch: "M-45 -35 a10 10 0 0 1 10 -10 h70 a 10 10 0 0 1 10 10 v70 " +
+                "a 10 10 0 0 1 -10 10 h -70 a 10 10 0 0 1 -10 -10 z M 5 -29 " +
+                "l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z M 5 5 " +
+                "l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z M -5 -15 " +
+                "l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z M -5 19 " +
+                "l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z " ,
+        roadm: "M-45 -20 l25 -25 h40 l25 25 v40 l-25 25 h-40 l-25 -25 z " +
+                "M 3 -29 l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z M 3 5 " +
+                "l 12 0, 0 -8, 18 13, -18 13, 0 -8, -12 0 z M -3 -15 " +
+                "l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z M -3 19 " +
+                "l -12 0, 0 -8, -18 13, 18 13, 0 -8, 12 0 z ",
+        node: "M-40 45 a5 5 0 0 1 -5 -5 v-65 a5 5 0 0 1 5 -5 h80 " +
+                "a5 5 0 0 1 5 5 v65 a5 5 0 0 1 -5 5 z M-41 -32.5 l11 -11  " +
+                "a10 3 0 0 1 10 -2 h40 a10 3 0 0 1 10 2 l11 11 z M-39 -20 " +
+                "a5 5 0 0 1 10 0 a5 5 0 0 1 -10 0 z ",
+        host: "M-45 -40 a5 5 0 0 1 5 -5 h65 a5 5 0 0 1 5 5 v80 " +
+                "a5 5 0 0 1 -5 5 h-65 a5 5 0 0 1 -5 -5 z M32.5 -41 l11 11  " +
+                "a3 10 0 0 1 2 10 v40 a3 10 0 0 1 -2 10 l-11 11 z M-38 -36 " +
+                "a2 2 0 0 1 2 -2 h56 a2 2 0 0 1 2 2 v26 a2 2 0 0 1 -2 2 h-56 " +
+                "a2 2 0 0 1 -2 -2 z M-35 -35 h54 v10 h-54 z M-35 -22 h54 v10 " +
+                "h-54 z M-13 15 a5 5 0 0 1 10 0 a5 5 0 0 1 -10 0 z "
+    };
+
+    var glyphParams = {
+        viewBox: '-55 -55 110 110'
+    };
+
+    function defGlyphs(defs) {
+        d3.map(glyphData).keys().forEach(function (key) {
+                defs.append('symbol')
+                    .attr({
+                        id: key,
+                        viewBox: glyphParams.viewBox
+                    })
+                    .append('path').attr('d', glyphData[key]);
+        });
+    }
+
     // === register the functions as a library
     onos.ui.addLib('glyphs', {
         defBird: defBird,
-        defBullhorn: defBullhorn
+        defBullhorn: defBullhorn,
+        defGlyphs: defGlyphs
     });
 
 }(ONOS));
diff --git a/web/gui/src/main/webapp/topo2.css b/web/gui/src/main/webapp/topo2.css
index 0514a6f..6c0b3b6 100644
--- a/web/gui/src/main/webapp/topo2.css
+++ b/web/gui/src/main/webapp/topo2.css
@@ -30,9 +30,15 @@
     fill: transparent;
 }
 
+/* TODO: move glyphs into framework */
 
-#topo svg .glyph {
-    fill: white;
+#topo svg .glyphIcon {
+    fill: black;
+    stroke: none;
+    fill-rule: evenodd;
+}
+#topo svg .glyphIcon rect {
+    fill: #ddd;
     stroke: none;
 }
 
diff --git a/web/gui/src/main/webapp/topo2.js b/web/gui/src/main/webapp/topo2.js
index 82f7194..0501061 100644
--- a/web/gui/src/main/webapp/topo2.js
+++ b/web/gui/src/main/webapp/topo2.js
@@ -80,7 +80,12 @@
             w: 30,
             h: 30,
             xoff: -16,
-            yoff: -14
+            yoff: -14,
+
+            device: {
+                dim: 30,
+                rx: 4
+            }
         },
         iconUrl: {
             device: 'img/device.png',
@@ -1214,7 +1219,10 @@
         // start with the object as is
         var node = device,
             type = device.type,
-            svgCls = type ? 'node device ' + type : 'node device';
+            svgCls = type ? 'node device ' + type : 'node device',
+            labels = device.labels || [];
+
+        labels.unshift(''); // add 'no-label' to front of cycle
 
         // Augment as needed...
         node.class = 'device';
@@ -1222,6 +1230,9 @@
         positionNode(node);
 
         // cache label array length
+        // TODO: need a uiConfig event from the server to set things
+        // like device labels count, host labels count, etc.
+        // The current method (here) is a little fragile
         network.deviceLabelCount = device.labels.length;
         return node;
     }
@@ -1311,6 +1322,11 @@
         return 'img/' + d.type + '.png';
     }
 
+    function iconGlyphUrl(d) {
+        var which = d.type || 'unknown';
+        return '#' + which;
+    }
+
     // returns the newly computed bounding box of the rectangle
     function adjustRectToFitText(n) {
         var text = n.select('text'),
@@ -1346,14 +1362,26 @@
         var idx = (deviceLabelIndex < d.labels.length) ? deviceLabelIndex : 0;
         return d.labels[idx];
     }
-    function niceLabel(label) {
-        return (label && label.trim()) ? label : '.';
+    function trimLabel(label) {
+        return (label && label.trim()) || '';
+    }
+
+    function emptyBox() {
+        return {
+            x: -2,
+            y: -2,
+            width: 4,
+            height: 4
+        };
     }
 
     function updateDeviceLabel(d) {
-        var label = niceLabel(deviceLabel(d)),
+        var label = trimLabel(deviceLabel(d)),
+            noLabel = !label,
             node = d.el,
-            box;
+            box,
+            dx,
+            dy;
 
         node.select('text')
             .text(label)
@@ -1361,21 +1389,23 @@
             .transition()
             .style('opacity', 1);
 
-        box = adjustRectToFitText(node);
+        if (noLabel) {
+            box = emptyBox();
+            dx = -config.icons.device.dim/2;
+            dy = -config.icons.device.dim/2;
+        } else {
+            box = adjustRectToFitText(node);
+            dx = box.x + config.icons.xoff;
+            dy = box.y + config.icons.yoff;
+        }
 
         node.select('rect')
             .transition()
             .attr(box);
 
-        node.select('rect.iconUnderlay')
+        node.select('g.deviceIcon')
             .transition()
-            .attr('x', box.x + config.icons.xoff)
-            .attr('y', box.y + config.icons.yoff);
-
-        node.select('image')
-            .transition()
-            .attr('x', box.x + config.icons.xoff + 2)
-            .attr('y', box.y + config.icons.yoff + 2);
+            .attr('transform', translate(dx, dy));
     }
 
     function updateHostLabel(d) {
@@ -1436,7 +1466,7 @@
         node = nodeG.selectAll('.node')
             .data(network.nodes, function (d) { return d.id; });
 
-        // operate on existing nodes, if necessary
+        // TODO: operate on existing nodes
         //  update host labels
         //node .foo() .bar() ...
 
@@ -1458,8 +1488,8 @@
         // augment device nodes...
         entering.filter('.device').each(function (d) {
             var node = d3.select(this),
-                icon = iconUrl(d),
-                label = niceLabel(deviceLabel(d)),
+                label = trimLabel(deviceLabel(d)),
+                noLabel = !label,
                 box;
 
             // provide ref to element from backing data....
@@ -1480,41 +1510,8 @@
             node.select('rect')
                 .attr(box);
 
-            if (icon) {
-                var cfg = config.icons;
-                node.append('rect')
-                    .attr({
-                        class: 'iconUnderlay',
-                        x: box.x + config.icons.xoff,
-                        y: box.y + config.icons.yoff,
-                        width: cfg.w,
-                        height: cfg.h,
-                        rx: 4
-                    }).style({
-                        stroke: '#000',
-                        fill: '#ddd'
-                    });
-                node.append('svg:image')
-                    .attr({
-                        x: box.x + config.icons.xoff + 2,
-                        y: box.y + config.icons.yoff + 2,
-                        width: cfg.w - 4,
-                        height: cfg.h - 4,
-                        'xlink:href': icon
-                    });
-            }
+            addDeviceIcon(node, box, noLabel, iconGlyphUrl(d));
 
-            // debug function to show the modelled x,y coordinates of nodes...
-            if (debug('showNodeXY')) {
-                node.select('rect').attr('fill-opacity', 0.5);
-                node.append('circle')
-                    .attr({
-                        class: 'debug',
-                        cx: 0,
-                        cy: 0,
-                        r: '3px'
-                    });
-            }
         });
 
         // TODO: better place for this configuration state
@@ -1604,6 +1601,67 @@
         // TODO: device node exits
     }
 
+    function addDeviceIcon(node, box, noLabel, iid) {
+        var cfg = config.icons.device,
+            dx,
+            dy,
+            g;
+
+        if (noLabel) {
+            box = emptyBox();
+            dx = -cfg.dim/2;
+            dy = -cfg.dim/2;
+        } else {
+            box = adjustRectToFitText(node);
+            dx = box.x + config.icons.xoff;
+            dy = box.y + config.icons.yoff;
+        }
+
+        g = node.append('g').attr('class', 'glyphIcon deviceIcon')
+                .attr('transform', translate(dx, dy));
+
+        g.append('rect').attr({
+            x: 0,
+            y: 0,
+            rx: cfg.rx,
+            width: cfg.dim,
+            height: cfg.dim
+        });
+
+        g.append('use').attr({
+            'xlink:href': iid,
+            width: cfg.dim,
+            height: cfg.dim
+        });
+
+/*
+        if (icon) {
+            node.append('rect')
+                .attr({
+                    class: 'iconUnderlay',
+                    x: box.x + config.icons.xoff,
+                    y: box.y + config.icons.yoff,
+                    width: cfg.w,
+                    height: cfg.h,
+                    rx: 4
+                }).style({
+                    stroke: '#000',
+                    fill: '#ddd'
+                });
+            node.append('svg:image')
+                .attr({
+                    x: box.x + config.icons.xoff + 2,
+                    y: box.y + config.icons.yoff + 2,
+                    width: cfg.w - 4,
+                    height: cfg.h - 4,
+                    'xlink:href': icon
+                });
+        }
+*/
+    }
+
+
+
     function find(key, array) {
         for (var idx = 0, n = array.length; idx < n; idx++) {
             if (array[idx].key === key) {
@@ -2070,6 +2128,7 @@
         var defs = svg.append('defs');
         gly.defBird(defs);
         gly.defBullhorn(defs);
+        gly.defGlyphs(defs);
     }
 
     // ==============================