Topo2: Initial re-implementation of the toolbar

Change-Id: I8376ba377dda289969500806449380d80452b8f6
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2.css b/web/gui/src/main/webapp/app/view/topo2/topo2.css
index 12be44a..374740e 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2.css
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2.css
@@ -207,3 +207,20 @@
     border: 0;
     margin: 4px -3px;
 }
+
+/* --- Toolbar --- */
+
+#toolbar-topo2-toolbar {
+    padding: 6px;
+}
+
+#toolbar-topo2-toolbar .tbar-row.right {
+    width: 100%;
+}
+
+#toolbar-topo2-toolbar .tbar-row-text {
+    height: 21px;
+    text-align: right;
+    padding: 8px 60px 0 0;
+    font-style: italic;
+}
\ No newline at end of file
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2.js b/web/gui/src/main/webapp/app/view/topo2/topo2.js
index 0022964..77d0e0c3 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2.js
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2.js
@@ -98,7 +98,7 @@
         'Topo2EventService', 'Topo2ForceService', 'Topo2InstanceService',
         'Topo2BreadcrumbService', 'Topo2KeyCommandService', 'Topo2MapService',
         'Topo2MapConfigService', 'Topo2ZoomService', 'Topo2SpriteLayerService',
-        'Topo2SummaryPanelService', 'Topo2DeviceDetailsPanel',
+        'Topo2SummaryPanelService', 'Topo2DeviceDetailsPanel', 'Topo2ToolbarService',
 
         function (
             _$scope_, _$log_, _$loc_,
@@ -108,7 +108,7 @@
             _t2es_, _t2fs_, _t2is_,
             _t2bcs_, _t2kcs_, _t2ms_,
             _t2mcs_, _t2zs_, t2sls,
-            summaryPanel, detailsPanel
+            summaryPanel, detailsPanel, t2tbs
         ) {
             var params = _$loc_.search(),
                 dim,
@@ -188,10 +188,10 @@
             // make sure we can respond to topology events from the server
             t2es.bindHandlers();
 
-            t2fs.init(svg, forceG, uplink, dim, zoomer);
             t2bcs.init();
-            t2kcs.init(t2fs);
+            t2kcs.init(t2fs, t2tbs);
             t2is.initInst({ showMastership: t2fs.showMastership });
+            t2fs.init(svg, forceG, uplink, dim, zoomer);
 
             // === ORIGINAL CODE ===
 
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Force.js b/web/gui/src/main/webapp/app/view/topo2/topo2Force.js
index fc3e5b739..89fbae4 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2Force.js
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Force.js
@@ -25,7 +25,7 @@
     // injected refs
     var $log, $loc, wss;
 
-    var t2is, t2rs, t2ls, t2vs, t2bcs, t2ss, t2bgs;
+    var t2is, t2rs, t2ls, t2vs, t2bcs, t2ss, t2bgs, t2tbs;
     var svg, forceG, uplink, dim, opts, zoomer;
 
     // D3 Selections
@@ -49,11 +49,12 @@
         t2ss.init(svg, zoomer);
         t2ss.region = t2rs;
         t2rs.layout = t2ls;
-
+        t2tbs.init();
         navToBookmarkedRegion($loc.search().regionId);
     }
 
     function destroy() {
+        t2tbs.destroy();
         $log.debug('Destroy topo force layout');
     }
 
@@ -188,9 +189,9 @@
         '$log', '$location', 'WebSocketService', 'Topo2InstanceService',
         'Topo2RegionService', 'Topo2LayoutService', 'Topo2ViewService',
         'Topo2BreadcrumbService', 'Topo2ZoomService', 'Topo2SelectService',
-        'Topo2BackgroundService',
+        'Topo2BackgroundService', 'Topo2ToolbarService',
         function (_$log_, _$loc_, _wss_, _t2is_, _t2rs_, _t2ls_,
-            _t2vs_, _t2bcs_, zoomService, _t2ss_, _t2bgs_) {
+            _t2vs_, _t2bcs_, zoomService, _t2ss_, _t2bgs_, _t2tbs_) {
 
             $log = _$log_;
             $loc = _$loc_;
@@ -202,6 +203,7 @@
             t2bcs = _t2bcs_;
             t2ss = _t2ss_;
             t2bgs = _t2bgs_;
+            t2tbs = _t2tbs_;
 
             var onZoom = function () {
                 var nodes = [].concat(
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2KeyCommands.js b/web/gui/src/main/webapp/app/view/topo2/topo2KeyCommands.js
index b89ea09..fda74c7 100644
--- a/web/gui/src/main/webapp/app/view/topo2/topo2KeyCommands.js
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2KeyCommands.js
@@ -17,31 +17,36 @@
 (function () {
 
     // Injected Services
-    var ks, flash, wss, t2ps, t2bgs, ps, t2is, t2sp, t2vs, t2rs, t2fs, t2sls;
+    var $log, fs, ks, flash, wss, t2ps, t2bgs, ps, t2is, t2sp, t2vs, t2rs, t2fs, t2sls, t2tbs;
 
     // Commmands
-    var actionMap = {
-        L: [cycleDeviceLabels, 'Cycle device labels'],
-        B: [toggleBackground, 'Toggle background'],
-        I: [toggleInstancePanel, 'Toggle ONOS Instance Panel'],
-        O: [toggleSummary, 'Toggle the Summary Panel'],
-        R: [resetZoom, 'Reset pan / zoom'],
-        P: [togglePorts, 'Toggle Port Highlighting'],
-        E: [equalizeMasters, 'Equalize mastership roles'],
-        X: [resetNodeLocation, 'Reset Node Location'],
-        U: [unpinNode, 'Unpin node (mouse over)'],
+    function actionMap() {
+        return {
+            L: [cycleDeviceLabels, 'Cycle device labels'],
+            B: [toggleBackground, 'Toggle background'],
+            I: [toggleInstancePanel, 'Toggle ONOS Instance Panel'],
+            O: [toggleSummary, 'Toggle the Summary Panel'],
+            R: [resetZoom, 'Reset pan / zoom'],
+            P: [togglePorts, 'Toggle Port Highlighting'],
+            E: [equalizeMasters, 'Equalize mastership roles'],
+            X: [resetNodeLocation, 'Reset Node Location'],
+            U: [unpinNode, 'Unpin node (mouse over)'],
 
-        esc: handleEscape
+            esc: handleEscape,
+
+            _keyListener: t2tbs.keyListener.bind(t2tbs)
+        }
     };
 
-    function init(_t2fs_) {
+    function init(_t2fs_, _t2tbs_) {
         t2fs = _t2fs_;
+        t2tbs = _t2tbs_;
         bindCommands();
     }
 
     function bindCommands() {
 
-        ks.keyBindings(actionMap);
+        ks.keyBindings(actionMap());
 
         ks.gestureNotes([
             ['click', 'Select the item and show details'],
@@ -134,15 +139,38 @@
         flash.flash('Unpin node');
     }
 
+    function notValid(what) {
+        $log.warn('topo.js getActionEntry(): Not a valid ' + what);
+    }
+
+    function getActionEntry(key) {
+        var entry;
+
+        if (!key) {
+            notValid('key');
+            return null;
+        }
+
+        entry = actionMap()[key];
+
+        if (!entry) {
+            notValid('actionMap (' + key + ') entry');
+            return null;
+        }
+        return fs.isA(entry) || [entry, ''];
+    }
+
     angular.module('ovTopo2')
     .factory('Topo2KeyCommandService', [
-        'KeyService', 'FlashService', 'WebSocketService', 'Topo2PrefsService',
+        '$log', 'FnService', 'KeyService', 'FlashService', 'WebSocketService', 'Topo2PrefsService',
         'Topo2BackgroundService', 'PrefsService', 'Topo2InstanceService',
         'Topo2SummaryPanelService', 'Topo2ViewService', 'Topo2RegionService',
         'Topo2SpriteLayerService',
-        function (_ks_, _flash_, _wss_, _t2ps_, _t2bgs_, _ps_, _t2is_, _t2sp_,
+        function (_$log_, _fs_, _ks_, _flash_, _wss_, _t2ps_, _t2bgs_, _ps_, _t2is_, _t2sp_,
                   _t2vs_, _t2rs_, _t2sls_) {
 
+            $log = _$log_;
+            fs = _fs_;
             ks = _ks_;
             flash = _flash_;
             wss = _wss_;
@@ -157,7 +185,8 @@
 
             return {
                 init: init,
-                bindCommands: bindCommands
+                bindCommands: bindCommands,
+                getActionEntry: getActionEntry
             };
         }
     ]);
diff --git a/web/gui/src/main/webapp/app/view/topo2/topo2Toolbar.js b/web/gui/src/main/webapp/app/view/topo2/topo2Toolbar.js
new file mode 100644
index 0000000..1324029
--- /dev/null
+++ b/web/gui/src/main/webapp/app/view/topo2/topo2Toolbar.js
@@ -0,0 +1,108 @@
+(function () {
+    'use-strict';
+
+    var instance;
+
+    // TODO: Commented k2b map and addToggles are not implement in Topo2 yet.
+
+    // key to button mapping data
+    var k2b = {
+        O: { id: 'topo2-summary-tog', gid: 'm_summary', isel: true},
+        I: { id: 'topo2-instance-tog', gid: 'm_uiAttached', isel: true },
+        // D: { id: 'details-tog', gid: 'm_details', isel: true },
+        // H: { id: 'hosts-tog', gid: 'm_endstation', isel: false },
+        // M: { id: 'offline-tog', gid: 'm_switch', isel: true },
+        P: { id: 'topo2-ports-tog', gid: 'm_ports', isel: true },
+        B: { id: 'topo2-bkgrnd-tog', gid: 'm_map', isel: false },
+
+        // Z: { id: 'oblique-tog', gid: 'm_oblique', isel: false },
+        // N: { id: 'filters-btn', gid: 'm_filters' },
+        L: { id: 'topo2-cycleLabels-btn', gid: 'm_cycleLabels' },
+        R: { id: 'topo2-resetZoom-btn', gid: 'm_resetZoom' },
+
+        E: { id: 'topo2-eqMaster-btn', gid: 'm_eqMaster' }
+    };
+
+    angular.module('ovTopo2')
+        .factory('Topo2ToolbarService', [
+            'FnService', 'ToolbarService', 'Topo2KeyCommandService',
+            function (fs, tbs, t2kcs) {
+
+                var Toolbar = function () {
+                    instance = this;
+                    this.el = tbs.createToolbar(this.className);
+                };
+
+                Toolbar.prototype = {
+
+                    className: 'topo2-toolbar',
+
+                    init: function () {
+                        this.initKeyData();
+                        this.addFirstRow();
+                        this.el.addRow();
+                        this.addSecondRow();
+
+                        this.el.show();
+                    },
+                    initKeyData: function () {
+                        _.each(k2b, function(value, key) {
+                            var data = t2kcs.getActionEntry(key);
+                            if (data) {
+                                value.cb = data[0];                     // on-click callback
+                                value.tt = data[1] + ' (' + key + ')';  // tooltip
+                            }
+                        });
+                    },
+                    getKey: function (key) {
+                        return k2b[key];
+                    },
+                    keyListener: function (key) {
+                        var v = this.getKey(key);
+
+                        if (v && v.tog) {
+                            v.tog.toggleNoCb();
+                        }
+                    },
+                    addButton: function (key) {
+                        var v =  this.getKey(key);
+                        v.btn = this.el.addButton(v.id, v.gid, v.cb, v.tt);
+                    },
+                    addToggle: function (key, suppressIfMobile) {
+                        var v =  this.getKey(key);
+                        if (suppressIfMobile && fs.isMobile()) { return; }
+                        v.tog = this.el.addToggle(v.id, v.gid, v.isel, v.cb, v.tt);
+                    },
+
+                    addFirstRow: function () {
+                        this.addToggle('I');
+                        this.addToggle('O');
+                        // this.addToggle('D');
+                        this.el.addSeparator();
+
+                        // this.addToggle('H');
+                        // this.addToggle('M');
+                        this.addToggle('P', true);
+                        this.addToggle('B');
+                    },
+                    addSecondRow: function () {
+                        //addToggle('X');
+                        // this.addToggle('Z');
+                        // this.addButton('N');
+                        this.addButton('L');
+                        this.addButton('R');
+                        this.el.addSeparator();
+                        this.addButton('E');
+                    },
+
+                    destroy: function () {
+                        // TODO: Should the tbs remove button id's in the destroyToolbar method?
+                        // If you go topo2 -> topo -> topo2 there's a button id conflict
+                        tbs.destroyToolbar(this.className);
+                    }
+                };
+
+                return instance || new Toolbar();
+            }
+        ]);
+})();
\ No newline at end of file
diff --git a/web/gui/src/main/webapp/index.html b/web/gui/src/main/webapp/index.html
index 3930779..4170c76 100644
--- a/web/gui/src/main/webapp/index.html
+++ b/web/gui/src/main/webapp/index.html
@@ -158,6 +158,7 @@
     <script src="app/view/topo2/topo2NodeModel.js"></script>
     <script src="app/view/topo2/topo2NodePosition.js"></script>
     <script src="app/view/topo2/topo2Panel.js"></script>
+    <script src="app/view/topo2/topo2PeerRegion.js"></script>
     <script src="app/view/topo2/topo2Prefs.js"></script>
     <script src="app/view/topo2/topo2Region.js"></script>
     <script src="app/view/topo2/topo2Select.js"></script>
@@ -166,6 +167,7 @@
     <script src="app/view/topo2/topo2SubRegion.js"></script>
     <script src="app/view/topo2/topo2SubRegionPanel.js"></script>
     <script src="app/view/topo2/topo2Theme.js"></script>
+    <script src="app/view/topo2/topo2Toolbar.js"></script>
     <script src="app/view/topo2/topo2View.js"></script>
     <script src="app/view/topo2/topo2ViewController.js"></script>
     <script src="app/view/topo2/topo2Zoom.js"></script>