Pushing changes for [ONOS-5469] : Add detail panel infrastructure

Change-Id: If402282cf70b37b7ee4cee14c57e9a9311f57842
diff --git a/web/gui/src/main/webapp/app/view/cluster/cluster.css b/web/gui/src/main/webapp/app/view/cluster/cluster.css
index fab5069..2ed0f63 100644
--- a/web/gui/src/main/webapp/app/view/cluster/cluster.css
+++ b/web/gui/src/main/webapp/app/view/cluster/cluster.css
@@ -24,4 +24,34 @@
 
 #ov-cluster div.ctrl-btns {
     width: 45px;
-}
\ No newline at end of file
+}
+
+
+/* More in generic panel.css */
+
+#node-details-panel.floatpanel {
+    z-index: 0;
+}
+
+
+#node-details-panel .container {
+    padding: 8px 12px;
+}
+
+#node-details-panel .close-btn {
+    position: absolute;
+    right: 12px;
+    top: 12px;
+    cursor: pointer;
+}
+
+#node-details-panel .dev-icon {
+    display: inline-block;
+    padding: 0 6px 0 0;
+    vertical-align: middle;
+}
+
+#flow-details-panel h2 {
+    display: inline-block;
+    margin: 8px 0;
+}
diff --git a/web/gui/src/main/webapp/app/view/cluster/cluster.html b/web/gui/src/main/webapp/app/view/cluster/cluster.html
index 058975b..3b4481d 100644
--- a/web/gui/src/main/webapp/app/view/cluster/cluster.html
+++ b/web/gui/src/main/webapp/app/view/cluster/cluster.html
@@ -35,6 +35,8 @@
                 </tr>
 
                 <tr ng-repeat="node in tableData track by $index"
+                    ng-click="selectCallback($event, node)"
+                    ng-class="{selected: node.id === selId}"
                     ng-repeat-complete row-id="{{node.id}}">
                     <td class="table-icon">
                         <div icon icon-id="{{node._iconid_state}}"></div>
@@ -51,5 +53,5 @@
         </div>
 
     </div>
-
+    <node-details-panel></node-details-panel>
 </div>
diff --git a/web/gui/src/main/webapp/app/view/cluster/cluster.js b/web/gui/src/main/webapp/app/view/cluster/cluster.js
index f674766..270ed59 100644
--- a/web/gui/src/main/webapp/app/view/cluster/cluster.js
+++ b/web/gui/src/main/webapp/app/view/cluster/cluster.js
@@ -21,16 +21,203 @@
 (function () {
     'use strict';
 
+        // injected references
+        var $log, $scope, $location, fs, tbs, ns, mast, ps, wss, is, ks;
+
+        // internal state
+        var detailsPanel,
+            pStartY,
+            pHeight,
+            top,
+            topContent,
+            bottom,
+            iconDiv,
+            nameDiv,
+            wSize;
+
+
+        // constants
+        var topPdg = 28,
+            ctnrPdg = 24,
+            scrollSize = 17,
+            portsTblPdg = 50,
+            htPdg = 479,
+            wtPdg = 532,
+
+            pName = 'node-details-panel',
+            detailsReq = 'nodeDetailsRequest',
+            detailsResp = 'nodeDetailsResponse';
+
+        function closePanel() {
+            if (detailsPanel.isVisible()) {
+                $scope.selId = null;
+                detailsPanel.hide();
+                return true;
+            }
+            return false;
+        }
+
+        function addCloseBtn(div) {
+            is.loadEmbeddedIcon(div, 'close', 20);
+            div.on('click', closePanel);
+        }
+
+        function setUpPanel() {
+            var container, closeBtn, tblDiv;
+            detailsPanel.empty();
+
+            container = detailsPanel.append('div').classed('container', true);
+
+            top = container.append('div').classed('top', true);
+            closeBtn = top.append('div').classed('close-btn', true);
+            addCloseBtn(closeBtn);
+            iconDiv = top.append('div').classed('dev-icon', true);
+            top.append('h2');
+            topContent = top.append('div').classed('top-content', true);
+            top.append('hr');
+
+            //ToDo add more details
+        }
+
+        function populateTop(details) {
+            is.loadEmbeddedIcon(iconDiv, 'm_node', 40);
+            top.select('h2').html(details.id);
+
+            //ToDo : Add more details
+        }
+
+        function createDetailsPane() {
+            detailsPanel = ps.createPanel(pName, {
+                width: wSize.width,
+                margin: 0,
+                hideMargin: 0
+            });
+            detailsPanel.el().style({
+                position: 'absolute',
+                top: pStartY + 'px'
+            });
+            $scope.hidePanel = function () { detailsPanel.hide(); };
+            detailsPanel.hide();
+        }
+
+        function populateDetails(details) {
+
+            setUpPanel();
+            populateTop(details);
+
+            //ToDo add more details
+            detailsPanel.height(pHeight);
+            detailsPanel.width(wtPdg);
+
+            //Todo : remove this when server implementation is done
+            detailsPanel.show();
+        }
+
+        function respDetailsCb(data) {
+            $scope.panelData = data.details;
+            $scope.$apply();
+            //TODO Use populateDetails() when merging server code
+            $log.debug('Get the details:', $scope.panelData.id);
+        }
+
+
     angular.module('ovCluster', [])
         .controller('OvClusterCtrl',
-        ['$log', '$scope', 'TableBuilderService',
+        ['$log', '$scope', 'TableBuilderService', 'NavService', 'MastService',
+        'PanelService', 'KeyService', 'IconService','WebSocketService',
+        'FnService',
 
-            function ($log, $scope, tbs) {
+            function (_$log_, _$scope_, tbs, _ns_, _mast_, _ps_, _ks_, _is_,
+                    _wss_, _fs_) {
+                var params,
+                    handlers = {};
+
+                $log = _$log_;
+                $scope = _$scope_;
+                fs = _fs_;
+                ns = _ns_;
+                is = _is_;
+                wss = _wss_;
+                mast = _mast_;
+                ps = _ps_;
+
+                $scope.panelData = {};
+
                 tbs.buildTable({
                     scope: $scope,
+                    selCb: selCb,
                     tag: 'cluster'
                 });
 
+            // details panel handlers
+            handlers[detailsResp] = respDetailsCb;
+            wss.bindHandlers(handlers);
+
+            function selCb($event, row) {
+                if ($scope.selId) {
+                    wss.sendEvent(detailsReq, {id: row.id});
+
+                    //ToDo : Remove this line when server implmentation is complete
+                    populateDetails($scope.selId);
+                } else {
+                    $scope.hidePanel();
+                }
+                $log.debug('Got a click on:', row);
+            }
+
+            $scope.$on('$destroy', function () {
+                wss.unbindHandlers(handlers);
+            });
+
                 $log.log('OvClusterCtrl has been created');
-            }]);
+            }])
+
+
+    .directive('nodeDetailsPanel',
+    ['$rootScope', '$window', '$timeout', 'KeyService',
+    function ($rootScope, $window, $timeout, ks) {
+        return function (scope) {
+            var unbindWatch;
+
+            function heightCalc() {
+                pStartY = fs.noPxStyle(d3.select('.tabular-header'), 'height')
+                                        + mast.mastHeight() + topPdg;
+                wSize = fs.windowSize(pStartY);
+                pHeight = wSize.height;
+            }
+
+            function initPanel() {
+                heightCalc();
+                createDetailsPane();
+            }
+
+            // Safari has a bug where it renders the fixed-layout table wrong
+            // if you ask for the window's size too early
+            if (scope.onos.browser === 'safari') {
+                $timeout(initPanel);
+            } else {
+                initPanel();
+            }
+
+            // if the window size changes
+            unbindWatch = $rootScope.$watchCollection(
+                function () {
+                    return {
+                        h: $window.innerHeight,
+                        w: $window.innerWidth
+                    };
+                }, function () {
+                    if (!fs.isEmptyObject(scope.panelData)) {
+                        heightCalc();
+                        populateDetails(scope.panelData);
+                    }
+                }
+            );
+
+            scope.$on('$destroy', function () {
+                unbindWatch();
+                ps.destroyPanel(pName);
+            });
+        };
+    }]);
 }());