GUI -- Implemented showSummary event (Icon still to do..) WIP
- included CSS for light/dark themes.
- Removed height from panel default settings.
- Fixed 'restart' bug in mock server - (renamed to mockserver.js)

Change-Id: I615299e6f8f07843edb074050b7450eea501bfbb
diff --git a/web/gui/src/main/webapp/app/fw/layer/panel.css b/web/gui/src/main/webapp/app/fw/layer/panel.css
index f83d595..1075b74 100644
--- a/web/gui/src/main/webapp/app/fw/layer/panel.css
+++ b/web/gui/src/main/webapp/app/fw/layer/panel.css
@@ -26,21 +26,21 @@
     width: 200px;
     right: -220px;
     opacity: 0;
-    background-color: rgba(255,255,255,0.8);
 
     padding: 10px;
-    color: black;
     font-size: 10pt;
 
     -moz-border-radius: 6px;
     border-radius: 6px;
-    box-shadow: 0px 2px 12px #777;
 }
 
-/* TODO: light/dark themes */
 .light .floatpanel {
-
+    background-color: rgba(255,255,255,0.8);
+    color: black;
+    box-shadow: 0 2px 12px #777;
 }
 .dark .floatpanel {
-
+    background-color: rgba(50,50,50,0.8);
+    color: #ccc;
+    box-shadow: 0 2px 12px #000;
 }
diff --git a/web/gui/src/main/webapp/app/fw/layer/panel.js b/web/gui/src/main/webapp/app/fw/layer/panel.js
index 2209487..1665626 100644
--- a/web/gui/src/main/webapp/app/fw/layer/panel.js
+++ b/web/gui/src/main/webapp/app/fw/layer/panel.js
@@ -25,7 +25,6 @@
     var defaultSettings = {
         edge: 'right',
         width: 200,
-        height: 80,
         margin: 20,
         xtnTime: 750
     };
@@ -87,7 +86,9 @@
         // has to be called after el is set
         p.el.style(p.settings.edge, pxHide(p));
         panelWidth(p.settings.width);
-        panelHeight(p.settings.height);
+        if (p.settings.height) {
+            panelHeight(p.settings.height);
+        }
 
         panels[id] = p;
 
diff --git a/web/gui/src/main/webapp/app/view/topo/topo.css b/web/gui/src/main/webapp/app/view/topo/topo.css
index 626ddf7..785df8c 100644
--- a/web/gui/src/main/webapp/app/view/topo/topo.css
+++ b/web/gui/src/main/webapp/app/view/topo/topo.css
@@ -18,6 +18,8 @@
  ONOS GUI -- Topology View -- CSS file
  */
 
+/* --- Topo Map --- */
+
 .light #ov-topo svg {
     background-color: #fff;
     /* For Debugging the placement of the SVG layer... */
@@ -39,3 +41,80 @@
 .dark #ov-topo svg #topo-map {
     stroke: #444;
 }
+
+
+/* --- Topo Panels --- */
+
+#topo-p-summary {
+    /* Base css from panel.css */
+    
+}
+
+#topo-p-summary svg {
+    display: inline-block;
+    width: 42px;
+    height: 42px;
+}
+
+#topo-p-summary svg .glyphIcon {
+    stroke: none;
+    fill-rule: evenodd;
+}
+.light #topo-p-summary svg .glyphIcon {
+    fill: black;
+}
+.dark #topo-p-summary svg .glyphIcon {
+    fill: #ddd;
+}
+
+#topo-p-summary h2 {
+    position: absolute;
+    margin: 0 4px;
+    top: 20px;
+    left: 50px;
+}
+.light #topo-p-summary h2 {
+    color: black;
+}
+.dark #topo-p-summary h2 {
+    color: #ddd;
+}
+
+#topo-p-summary h3 {
+    margin: 0 4px;
+    top: 20px;
+    left: 50px;
+}
+.light #topo-p-summary h3 {
+    color: black;
+}
+.dark #topo-p-summary h3 {
+    color: #ddd;
+}
+
+#topo-p-summary p, table {
+    margin: 4px 4px;
+}
+
+#topo-p-summary td.label {
+    font-style: italic;
+    padding-right: 12px;
+    /* works for both light and dark themes ... */
+    color: #777;
+}
+
+#topo-p-summary td.value {
+}
+
+#topo-p-summary hr {
+    height: 1px;
+    border: 0;
+}
+.light #topo-p-summary hr {
+    background-color: #ccc;
+    color: #ccc;
+}
+.dark #topo-p-summary hr {
+    background-color: #888;
+    color: #888;
+}
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 05ddb66..2edc13e 100644
--- a/web/gui/src/main/webapp/app/view/topo/topo.js
+++ b/web/gui/src/main/webapp/app/view/topo/topo.js
@@ -28,7 +28,7 @@
     ];
 
     // references to injected services etc.
-    var $log, fs, ks, zs, gs, ms, tes, tfs, tps;
+    var $log, fs, ks, zs, gs, ms, tfs;
 
     // DOM elements
     var ovtopo, svg, defs, zoomLayer, mapG, forceG;
@@ -137,11 +137,6 @@
         tfs.initForce(forceG, svg.attr('width'), svg.attr('height'));
     }
 
-    function setUpPanels() {
-        tps.initPanels();
-    }
-
-
     // --- Controller Definition -----------------------------------------
 
     angular.module('ovTopo', moduleDependencies)
@@ -153,7 +148,7 @@
             'TopoEventService', 'TopoForceService', 'TopoPanelService',
 
         function ($scope, _$log_, $loc, $timeout, _fs_, mast,
-                  _ks_, _zs_, _gs_, _ms_, _tes_, _tfs_, _tps_) {
+                  _ks_, _zs_, _gs_, _ms_, tes, _tfs_, tps) {
             var self = this;
             $log = _$log_;
             fs = _fs_;
@@ -161,9 +156,7 @@
             zs = _zs_;
             gs = _gs_;
             ms = _ms_;
-            tes = _tes_;
             tfs = _tfs_;
-            tps = _tps_;
 
             self.notifyResize = function () {
                 svgResized(fs.windowSize(mast.mastHeight()));
@@ -173,7 +166,7 @@
             $scope.$on('$destroy', function () {
                 $log.log('OvTopoCtrl is saying Buh-Bye!');
                 tes.closeSock();
-                ps.destroyPanel('topo-p-summary');
+                tps.destroyPanels();
             });
 
             // svg layer and initialization of components
@@ -190,9 +183,8 @@
             setUpZoom();
             setUpMap();
             setUpForce();
-            setUpPanels();
 
-            // open up a connection to the server...
+            tps.initPanels();
             tes.openSock();
 
             $log.log('OvTopoCtrl has been created');
diff --git a/web/gui/src/main/webapp/app/view/topo/topoPanel.js b/web/gui/src/main/webapp/app/view/topo/topoPanel.js
index e513b1f..d05dc3e 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoPanel.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoPanel.js
@@ -25,6 +25,14 @@
     // injected refs
     var $log, ps;
 
+    // constants
+    var idSum = 'topo-p-summary',
+        idDet = 'topo-p-detail',
+        idIns = 'topo-p-instance',
+        panelOpts = {
+            width: 260
+        };
+
     // internal state
     var settings;
 
@@ -45,6 +53,54 @@
 
     // ==========================
 
+    function addSep(tbody) {
+        tbody.append('tr').append('td').attr('colspan', 2).append('hr');
+    }
+
+    function addProp(tbody, label, value) {
+        var tr = tbody.append('tr');
+
+        function addCell(cls, txt) {
+            tr.append('td').attr('class', cls).text(txt);
+        }
+        addCell('label', label + ' :');
+        addCell('value', value);
+    }
+
+    function populateSummary(data) {
+        summaryPanel.empty();
+
+        var svg = summaryPanel.append('svg').attr({
+                width: 40,
+                height: 40
+            }).style('background-color', 'goldenrod'),
+            iid = '#' + (data.type || 'unknown');
+
+        var title = summaryPanel.append('h2'),
+            table = summaryPanel.append('table'),
+            tbody = table.append('tbody');
+
+        // append glyph iid to SVG  // black fill
+        // append glyph bird to SVG // white fill
+
+        title.text(data.id);
+
+        data.propOrder.forEach(function(p) {
+            if (p === '-') {
+                addSep(tbody);
+            } else {
+                addProp(tbody, p, data.props[p]);
+            }
+        });
+    }
+
+    function showSummaryPanel() {
+        summaryPanel.show();
+
+    }
+
+    // ==========================
+
     angular.module('ovTopo')
     .factory('TopoPanelService',
         ['$log', 'PanelService',
@@ -54,20 +110,24 @@
             ps = _ps_;
 
             function initPanels() {
-                summaryPanel = ps.createPanel('topo-p-summary');
+                summaryPanel = ps.createPanel(idSum, panelOpts);
                 // TODO: set up detail and instance panels..
             }
 
-            function showSummary(payload) {
-                summaryPanel.empty();
-                summaryPanel.append('h2').text(payload.id);
-                // TODO: complete the formatting...
+            function destroyPanels() {
+                ps.destroyPanel(idSum);
+                summaryPanel = null;
+                // TODO: destroy detail and instance panels..
+            }
 
-                summaryPanel.show();
+            function showSummary(payload) {
+                populateSummary(payload);
+                showSummaryPanel();
             }
 
             return {
                 initPanels: initPanels,
+                destroyPanels: destroyPanels,
                 showSummary: showSummary
             };
         }]);
diff --git a/web/gui/src/main/webapp/tests/app/fw/layer/panel-spec.js b/web/gui/src/main/webapp/tests/app/fw/layer/panel-spec.js
index 1d33e4f..41a9ff9 100644
--- a/web/gui/src/main/webapp/tests/app/fw/layer/panel-spec.js
+++ b/web/gui/src/main/webapp/tests/app/fw/layer/panel-spec.js
@@ -72,7 +72,6 @@
         expect($log.debug).toHaveBeenCalledWith('creating panel:', 'foo', {
             edge: 'right',
             width: 200,
-            height: 80,
             margin: 20,
             xtnTime: 750
         });
@@ -120,7 +119,6 @@
         expect($log.debug).toHaveBeenCalledWith('creating panel:', 'foo', {
             edge: 'left',
             width: 250,
-            height: 80,
             margin: 20,
             xtnTime: 750
         });
diff --git a/web/gui/src/main/webapp/tests/app/view/topo/topoPanel-spec.js b/web/gui/src/main/webapp/tests/app/view/topo/topoPanel-spec.js
index 4564d1e..6018370 100644
--- a/web/gui/src/main/webapp/tests/app/view/topo/topoPanel-spec.js
+++ b/web/gui/src/main/webapp/tests/app/view/topo/topoPanel-spec.js
@@ -34,7 +34,7 @@
 
     it('should define api functions', function () {
         expect(fs.areFunctions(tps, [
-            'initPanels'
+            'initPanels', 'destroyPanels', 'showSummary'
         ])).toBeTruthy();
     });
 
diff --git a/web/gui/src/test/_karma/wssrv.js b/web/gui/src/test/_karma/mockserver.js
similarity index 87%
rename from web/gui/src/test/_karma/wssrv.js
rename to web/gui/src/test/_karma/mockserver.js
index 58eae91..319c4c8 100644
--- a/web/gui/src/test/_karma/wssrv.js
+++ b/web/gui/src/test/_karma/mockserver.js
@@ -12,7 +12,8 @@
     lastargs,       // arguments to last command
     connection,     // ws connection
     origin,         // origin of connection
-    scenario,       // test scenario name
+    scid,           // scenario ID
+    scdata,         // scenario data
     scdone,         // shows when scenario is over
     evno,           // next event number
     evdata;         // event data
@@ -35,6 +36,7 @@
 
 server.on('listening', function () {
     console.log('OK, server is running');
+    console.log('(? for help)');
 });
 
 var wsServer = new WebSocketServer({
@@ -163,10 +165,10 @@
 
 function showScenarioStatus() {
     var msg;
-    if (!scenario) {
+    if (!scid) {
         console.log('No scenario loaded.');
     } else {
-        msg = 'Scenario: "' + scenario + '", ' +
+        msg = 'Scenario: "' + scid + '", ' +
                 (scdone ? 'DONE' : 'next event: ' + evno);
         console.log(msg);
     }
@@ -174,7 +176,19 @@
 
 function scenarioPath(evno) {
     var file = evno ? ('/ev_' + evno + '_onos.json') : '/scenario.json';
-    return 'ev/' + scenario + file;
+    return 'ev/' + scid + file;
+}
+
+
+function initScenario(verb) {
+    console.log(); // get past prompt
+    console.log(verb + ' scenario "' + scid + '"');
+    console.log(scdata.title);
+    scdata.description.forEach(function (d) {
+        console.log('  ' + d);
+    });
+    evno = 1;
+    scdone = false;
 }
 
 function setScenario(id) {
@@ -183,38 +197,24 @@
     }
 
     evdata = null;
-    scenario = id;
+    scid = id;
     fs.readFile(scenarioPath(), 'utf8', function (err, data) {
         if (err) {
             console.warn('No scenario named "' + id + '"', err);
-            scenario = null;
+            scid = null;
         } else {
-            evdata = JSON.parse(data);
-            console.log(); // get past prompt
-            console.log('Loading scenario "' + id + '"');
-            console.log(evdata.title);
-            evdata.description.forEach(function (d) {
-                console.log('  ' + d);
-            });
-            evno = 1;
-            scdone = false;
+            scdata = JSON.parse(data);
+            initScenario('Loading');
         }
         rl.prompt();
     });
 }
 
 function restartScenario() {
-    if (!scenario) {
+    if (!scid) {
         console.log('No scenario loaded.');
     } else {
-        console.log();
-        console.log('Restarting scenario "' + scenario + '"');
-        console.log(evdata.title);
-        evdata.description.forEach(function (d) {
-            console.log('  ' + d);
-        });
-        evno = 1;
-        scdone = false;
+        initScenario('Restarting');
     }
     rl.prompt();
 }
@@ -222,7 +222,7 @@
 function nextEvent() {
     var path;
 
-    if (!scenario) {
+    if (!scid) {
         console.log('No scenario loaded.');
         rl.prompt();
     } else if (!connection) {