Pushing changes for story/subtask onos-5522
Patchset-2 Fixing code based on review comments on patchset-1
Patchset-3 Fixing code based on review comments on patchset-2

Change-Id: Ib3d0773bb6d2769f0590a99161462b2fe57b4304
diff --git a/web/gui/src/main/webapp/app/view/flow/flow.css b/web/gui/src/main/webapp/app/view/flow/flow.css
index 5b59f1b..fefb7a4 100644
--- a/web/gui/src/main/webapp/app/view/flow/flow.css
+++ b/web/gui/src/main/webapp/app/view/flow/flow.css
@@ -36,3 +36,32 @@
     text-align: left;
     padding-left: 36px;
 }
+
+/* More in generic panel.css */
+
+#flow-details-panel.floatpanel {
+    z-index: 0;
+}
+
+
+#flow-details-panel .container {
+    padding: 8px 12px;
+}
+
+#flow-details-panel .close-btn {
+    position: absolute;
+    right: 12px;
+    top: 12px;
+    cursor: pointer;
+}
+
+#flow-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/flow/flow.html b/web/gui/src/main/webapp/app/view/flow/flow.html
index 89036e2..eb1e45a 100644
--- a/web/gui/src/main/webapp/app/view/flow/flow.html
+++ b/web/gui/src/main/webapp/app/view/flow/flow.html
@@ -98,6 +98,8 @@
                 </tr>
 
                 <tr ng-repeat-start="flow in tableData | filter:queryFilter track by $index"
+                    ng-click="selectCallback($event, flow)"
+                    ng-class="{selected: flow.id === selId}"
                     ng-repeat-complete row-id="{{flow.id}}">
                     <td>{{flow.id}}</td>
                     <td>{{flow.appId}}</td>
@@ -120,5 +122,6 @@
         </div>
 
     </div>
+    <flow-details-panel></flow-details-panel>
 
 </div>
diff --git a/web/gui/src/main/webapp/app/view/flow/flow.js b/web/gui/src/main/webapp/app/view/flow/flow.js
index 872a2d1..445288d 100644
--- a/web/gui/src/main/webapp/app/view/flow/flow.js
+++ b/web/gui/src/main/webapp/app/view/flow/flow.js
@@ -22,21 +22,125 @@
     'use strict';
 
     // injected references
-    var $log, $scope, $location, fs, tbs, ns;
+    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 = 'flow-details-panel',
+        detailsReq = 'flowDetailsRequest',
+        detailsResp = 'flowDetailsResponse';
+
+    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_flows', 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) {
+        var details = data.details;
+        //TODO Use populateDetails() when merging server code
+        $log.debug('Get the details:', details.id);
+    }
 
     angular.module('ovFlow', [])
     .controller('OvFlowCtrl',
         ['$log', '$scope', '$location',
             'FnService', 'TableBuilderService', 'NavService',
+            'MastService', 'PanelService', 'KeyService', 'IconService',
+            'WebSocketService',
 
-        function (_$log_, _$scope_, _$location_, _fs_, _tbs_, _ns_) {
-            var params;
+        function (_$log_, _$scope_, _$location_, _fs_, _tbs_, _ns_,
+                    _mast_, _ps_, _ks_, _is_, _wss_) {
+            var params,
+                handlers = {};
+
             $log = _$log_;
             $scope = _$scope_;
             $location = _$location_;
             fs = _fs_;
             tbs = _tbs_;
             ns = _ns_;
+            is = _is_;
+            wss = _wss_;
+            mast = _mast_;
+            ps = _ps_;
             $scope.deviceTip = 'Show device table';
             $scope.portTip = 'Show port view for this device';
             $scope.groupTip = 'Show group view for this device';
@@ -52,6 +156,7 @@
             tbs.buildTable({
                 scope: $scope,
                 tag: 'flow',
+                selCb: selCb,
                 query: params
             });
 
@@ -61,6 +166,22 @@
                 }
             };
 
+            // details panel handlers
+            handlers[detailsResp] = respDetailsCb;
+            wss.bindHandlers(handlers);
+
+            function selCb($event, row) {
+                if ($scope.selId) {
+                    wss.sendEvent(detailsReq, {flowId: row.id, appId: row.appId});
+
+                    //ToDo : Remove this line when server implmentation is complete
+                    populateDetails($scope.selId);
+                } else {
+                    $scope.hidePanel();
+                }
+                $log.debug('Got a click on:', row);
+            }
+
             $scope.briefToggle = function () {
                 $scope.brief = !$scope.brief;
             };
@@ -74,5 +195,54 @@
             });
 
             $log.log('OvFlowCtrl has been created');
-        }]);
+        }])
+
+    .directive('flowDetailsPanel',
+    ['$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);
+            });
+        };
+    }]);
+
 }());