GUI -- TopoView - Fixed dynamic repositioning of Details Panel.
- also implemented toggleDetails keystroke 'D'.

Change-Id: I99a9ee1235c8cc1174d8c2d542e6e40b7fb6b8dc
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 08b99e1..18b4fe1 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, sus, tes, tfs, tps, tis;
+    var $log, fs, ks, zs, gs, ms, sus, tes, tfs, tps, tis, tss;
 
     // DOM elements
     var ovtopo, svg, defs, zoomLayer, mapG, forceG, noDevsLayer;
@@ -42,9 +42,9 @@
         // key bindings need to be made after the services have been injected
         // thus, deferred to here...
         ks.keyBindings({
-            O: [toggleSummary, 'Toggle ONOS summary pane'],
+            O: [tps.toggleSummary, 'Toggle ONOS summary pane'],
             I: [toggleInstances, 'Toggle ONOS instances pane'],
-            //D: [toggleDetails, 'Disable / enable details pane'],
+            D: [tss.toggleDetails, 'Disable / enable details pane'],
 
             H: [tfs.toggleHosts, 'Toggle host visibility'],
             M: [tfs.toggleOffline, 'Toggle offline visibility'],
@@ -87,15 +87,8 @@
 
     // --- Keystroke functions -------------------------------------------
 
-    function toggleSummary() {
-        if (tps.summaryVisible()) {
-            tes.sendEvent("cancelSummary");
-            tps.hideSummaryPanel();
-        } else {
-            tes.sendEvent('requestSummary');
-        }
-    }
-
+    // NOTE: this really belongs in the TopoPanelService -- but how to
+    //       cleanly link in the updateDeviceColors() call? To be fixed later.
     function toggleInstances() {
         tis.toggle();
         tfs.updateDeviceColors();
@@ -219,10 +212,11 @@
             'FnService', 'MastService', 'KeyService', 'ZoomService',
             'GlyphService', 'MapService', 'SvgUtilService',
             'TopoEventService', 'TopoForceService', 'TopoPanelService',
-            'TopoInstService',
+            'TopoInstService', 'TopoSelectService',
 
         function ($scope, _$log_, $loc, $timeout, _fs_, mast,
-                  _ks_, _zs_, _gs_, _ms_, _sus_, _tes_, _tfs_, _tps_, _tis_) {
+                  _ks_, _zs_, _gs_, _ms_, _sus_,
+                  _tes_, _tfs_, _tps_, _tis_, _tss_) {
             var self = this,
                 projection,
                 dim,
@@ -244,6 +238,7 @@
             tfs = _tfs_;
             tps = _tps_;
             tis = _tis_;
+            tss = _tss_;
 
             self.notifyResize = function () {
                 svgResized(fs.windowSize(mast.mastHeight()));
@@ -279,7 +274,7 @@
             forceG = zoomLayer.append('g').attr('id', 'topo-force');
             tfs.initForce(forceG, uplink, dim);
             tis.initInst();
-            tps.initPanels();
+            tps.initPanels({ sendEvent: tes.sendEvent });
             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 031ab53..d3b50bd 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoPanel.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoPanel.js
@@ -23,7 +23,12 @@
     'use strict';
 
     // injected refs
-    var $log, ps, gs;
+    var $log, fs, ps, gs;
+
+    var api;
+    /*
+      sendEvent( event, {payload} )
+     */
 
     // constants
     var pCls = 'topo-p',
@@ -137,39 +142,83 @@
         showSummaryPanel();
     }
 
+    function toggleSummary() {
+        if (summaryPanel.isVisible()) {
+            api.sendEvent("cancelSummary");
+            hideSummaryPanel();
+        } else {
+            api.sendEvent('requestSummary');
+        }
+    }
 
     // === -----------------------------------------------------
     // === LOGIC For showing/hiding summary and detail panels...
 
     function showSummaryPanel() {
-        summaryPanel.show();
-        // TODO: augment, for details panel move
+        if (detailPanel.isVisible()) {
+            detailPanel.down(summaryPanel.show);
+        } else {
+            summaryPanel.show();
+        }
     }
 
     function hideSummaryPanel() {
-        summaryPanel.hide();
-        // TODO: augment, for details panel move
+        summaryPanel.hide(function () {
+            if (detailPanel.isVisible()) {
+                detailPanel.up();
+            }
+        });
     }
 
     function showDetailPanel() {
-        // TODO: augment with summary-accomodation-logic
-        detailPanel.show();
+        if (summaryPanel.isVisible()) {
+            detailPanel.down(detailPanel.show);
+        } else {
+            detailPanel.up(detailPanel.show);
+        }
     }
 
     function hideDetailPanel() {
         detailPanel.hide();
     }
 
+    // ==========================
 
+    function noop () {}
+
+    function augmentDetailPanel() {
+        var dp = detailPanel;
+        dp.ypos = { up: 64, down: 320, current: 320};
+
+        dp._move = function (y, cb) {
+            var endCb = fs.isF(cb) || noop,
+                yp = dp.ypos;
+            if (yp.current !== y) {
+                yp.current = y;
+                dp.el().transition().duration(300)
+                    .each('end', endCb)
+                    .style('top', yp.current + 'px');
+            } else {
+                endCb();
+            }
+        };
+
+        dp.down = function (cb) { dp._move(dp.ypos.down, cb); };
+        dp.up = function (cb) { dp._move(dp.ypos.up, cb); };
+    }
 
     // ==========================
 
-    function initPanels() {
+    function initPanels(_api_) {
+        api = _api_;
+
         summaryPanel = ps.createPanel(idSum, panelOpts);
         detailPanel = ps.createPanel(idDet, panelOpts);
 
         summaryPanel.classed(pCls, true);
         detailPanel.classed(pCls, true);
+
+        augmentDetailPanel();
     }
 
     function destroyPanels() {
@@ -182,10 +231,11 @@
 
     angular.module('ovTopo')
     .factory('TopoPanelService',
-        ['$log', 'PanelService', 'GlyphService',
+        ['$log', 'FnService', 'PanelService', 'GlyphService',
 
-        function (_$log_, _ps_, _gs_) {
+        function (_$log_, _fs_, _ps_, _gs_) {
             $log = _$log_;
+            fs = _fs_;
             ps = _ps_;
             gs = _gs_;
 
@@ -194,6 +244,7 @@
                 destroyPanels: destroyPanels,
 
                 showSummary: showSummary,
+                toggleSummary: toggleSummary,
 
                 displaySingle: displaySingle,
                 displayMulti: displayMulti,
diff --git a/web/gui/src/main/webapp/app/view/topo/topoSelect.js b/web/gui/src/main/webapp/app/view/topo/topoSelect.js
index b7790f2..fb6c2f8 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoSelect.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoSelect.js
@@ -23,7 +23,7 @@
     'use strict';
 
     // injected refs
-    var $log, fs, tps;
+    var $log, fs, flash, tps;
 
     // api to topoForce
     var api;
@@ -229,6 +229,19 @@
         }
     }
 
+    function toggleDetails() {
+        useDetails = !useDetails;
+        if (useDetails) {
+            flash.flash('Enable details panel');
+            if (haveDetails) {
+                tps.showDetailPanel();
+            }
+        } else {
+            flash.flash('Disable details panel');
+            tps.hideDetailPanel();
+        }
+    }
+
     // === -----------------------------------------------------
     //  TODO: migrate these to topoTraffic.js
 
@@ -263,31 +276,33 @@
 
     angular.module('ovTopo')
         .factory('TopoSelectService',
-        ['$log', 'FnService', 'TopoPanelService',
+        ['$log', 'FnService', 'FlashService', 'TopoPanelService',
 
-            function (_$log_, _fs_, _tps_) {
-                $log = _$log_;
-                fs = _fs_;
-                tps = _tps_;
+        function (_$log_, _fs_, _flash_, _tps_) {
+            $log = _$log_;
+            fs = _fs_;
+            flash = _flash_;
+            tps = _tps_;
 
-                function initSelect(_api_) {
-                    api = _api_;
-                }
+            function initSelect(_api_) {
+                api = _api_;
+            }
 
-                function destroySelect() { }
+            function destroySelect() { }
 
-                return {
-                    initSelect: initSelect,
-                    destroySelect: destroySelect,
+            return {
+                initSelect: initSelect,
+                destroySelect: destroySelect,
 
-                    showDetails: showDetails,
+                showDetails: showDetails,
+                toggleDetails: toggleDetails,
 
-                    nodeMouseOver: nodeMouseOver,
-                    nodeMouseOut: nodeMouseOut,
-                    selectObject: selectObject,
-                    deselectObject: deselectObject,
-                    deselectAll: deselectAll,
-                    hovered: function () { return hovered; }
-                };
-            }]);
+                nodeMouseOver: nodeMouseOver,
+                nodeMouseOut: nodeMouseOut,
+                selectObject: selectObject,
+                deselectObject: deselectObject,
+                deselectAll: deselectAll,
+                hovered: function () { return hovered; }
+            };
+        }]);
 }());
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 7f93eb7..f51d029 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
@@ -37,6 +37,7 @@
             'initPanels',
             'destroyPanels',
             'showSummary',
+            'toggleSummary',
             'displaySingle',
             'displayMulti',
             'addAction',
diff --git a/web/gui/src/main/webapp/tests/app/view/topo/topoSelect-spec.js b/web/gui/src/main/webapp/tests/app/view/topo/topoSelect-spec.js
index f8bc0e7..9e6c2fb 100644
--- a/web/gui/src/main/webapp/tests/app/view/topo/topoSelect-spec.js
+++ b/web/gui/src/main/webapp/tests/app/view/topo/topoSelect-spec.js
@@ -34,7 +34,7 @@
 
     it('should define api functions', function () {
         expect(fs.areFunctions(tss, [
-            'initSelect', 'destroySelect', 'showDetails',
+            'initSelect', 'destroySelect', 'showDetails', 'toggleDetails',
             'nodeMouseOver', 'nodeMouseOut', 'selectObject', 'deselectObject',
             'deselectAll', 'hovered'
         ])).toBeTruthy();