GUI - topo view: enhancements to provide tinting of maps.

Change-Id: Ie369f4eee4c28e70ef86852cfbeea78fea8fae4f
diff --git a/web/gui/src/main/webapp/app/fw/svg/map.js b/web/gui/src/main/webapp/app/fw/svg/map.js
index c24fb28..a74f95d 100644
--- a/web/gui/src/main/webapp/app/fw/svg/map.js
+++ b/web/gui/src/main/webapp/app/fw/svg/map.js
@@ -56,13 +56,13 @@
 
             deferredProjection.resolve(gen.settings.projection);
 
-            var path = mapLayer.selectAll('path')
+            mapLayer.selectAll('path')
                 .data(gen.geodata.features)
                 .enter()
                 .append('path')
                 .attr('d', gen.pathgen);
 
-            opts.fill && path.style('fill', opts.fill);
+            reshade(opts.shading);
         });
         return deferredProjection.promise;
     }
@@ -78,7 +78,7 @@
     //         }
     //     });
 
-    function loadMapRegionInto(mapLayer, filterOpts) {
+    function loadMapRegionInto(mapLayer, opts) {
         var promise = gds.fetchTopoData("*countries"),
             deferredProjection = $q.defer();
 
@@ -94,14 +94,14 @@
                 pathGen = d3.geo.path().projection(proj),
                 data = promise.topodata,
                 features = topojson.feature(data, data.objects.countries).features,
-                country = features.filter(filterOpts.countryFilter),
+                country = features.filter(opts.countryFilter),
                 countryFeature = {
                     type: 'FeatureCollection',
                     features: country
                 },
                 path = d3.geo.path().projection(proj);
 
-            gds.rescaleProjection(proj, 0.95, 1000, path, countryFeature);
+            gds.rescaleProjection(proj, 0.95, 1000, path, countryFeature, opts.adjustScale);
 
             deferredProjection.resolve(proj);
 
@@ -110,10 +110,31 @@
                 .enter()
                 .append('path').classed('country', true)
                 .attr('d', pathGen);
+
+            reshade(opts.shading);
         });
         return deferredProjection.promise;
     }
 
+    function reshade(sh) {
+        var p = sh && sh.palette,
+            svg, paths, stroke, fill, bg;
+        if (sh) {
+            stroke = p.outline;
+            fill = sh.flip ? p.sea : p.land;
+            bg = sh.flip ? p.land : p.sea;
+
+            svg = d3.select('#ov-topo').select('svg');
+            paths = d3.select('#topo-map').selectAll('path');
+
+            svg.style('background-color', bg);
+            paths.attr({
+                stroke: stroke,
+                fill: fill
+            });
+        }
+    }
+
     angular.module('onosSvg')
         .factory('MapService', ['$log', '$q', 'FnService', 'GeoDataService',
         function (_$log_, _$q_, _fs_, _gds_) {
@@ -124,7 +145,8 @@
 
             return {
                 loadMapRegionInto: loadMapRegionInto,
-                loadMapInto: loadMapInto
+                loadMapInto: loadMapInto,
+                reshade: reshade
             };
         }]);
 
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 a78647d..56be9f6 100644
--- a/web/gui/src/main/webapp/app/view/topo/topo.js
+++ b/web/gui/src/main/webapp/app/view/topo/topo.js
@@ -29,14 +29,14 @@
     ];
 
     // references to injected services etc.
-    var $scope, $log, $cookies, fs, ks, zs, gs, ms, sus, flash, wss, ps,
+    var $scope, $log, $cookies, fs, ks, zs, gs, ms, sus, flash, wss, ps, th,
         tds, tes, tfs, tps, tis, tss, tls, tts, tos, fltr, ttbs, ttip, tov;
 
     // DOM elements
     var ovtopo, svg, defs, zoomLayer, mapG, spriteG, forceG, noDevsLayer;
 
     // Internal state
-    var zoomer, actionMap;
+    var zoomer, actionMap, themeListener;
 
     // --- Short Cut Keys ------------------------------------------------
 
@@ -345,6 +345,27 @@
         }
     };
 
+    var tintOn = 0,
+        shadeFlip = 0,
+        shadePalette = {
+        light: {
+            sea: 'aliceblue',
+            land: 'white',
+            outline: '#ddd'
+        },
+        dark: {
+            sea: '#001830',
+            land: '#232331',
+            outline: '#3a3a3a'
+        }
+    };
+
+    function shading() {
+        return tintOn ? {
+            palette: shadePalette[th.theme()],
+            flip: shadeFlip
+        } : '';
+    }
 
     function setUpMap($loc) {
         var qp = $loc.search(),
@@ -355,27 +376,53 @@
             ms1 = qp.mapscale,
             ms2 = pr && pr.scale,
             mapScale = ms1 || ms2 || 1,
+            t1 = qp.tint,
+            t2 = pr && pr.tint,
+            tint = t1 || t2 || 'off',
             promise,
             cfilter;
 
+        tintOn = tint === 'on' ? 1 : 0;
+
         mapG = zoomLayer.append('g').attr('id', 'topo-map');
         if (mapId === 'usa') {
-            promise = ms.loadMapInto(mapG, '*continental_us');
+            shadeFlip = 0;
+            promise = ms.loadMapInto(mapG, '*continental_us', {
+                adjustScale: mapScale,
+                shading: shading()
+            });
         } else if (mapId === 'bayarea') {
-            // TODO: be consistent about propagating options to other cases
+            shadeFlip = 1;
             promise = ms.loadMapInto(mapG, '*bayarea', {
                 objectTag: 'bayareaGEO',
                 adjustScale: mapScale,
-                fill: 'aliceblue'
+                shading: shading()
             });
         } else {
+            shadeFlip = 0;
             cfilter = countryFilters[mapId] || countryFilters.world;
-            promise = ms.loadMapRegionInto(mapG, { countryFilter: cfilter });
+            promise = ms.loadMapRegionInto(mapG, {
+                countryFilter: cfilter,
+                adjustScale: mapScale,
+                shading: shading()
+            });
         }
-        ps.setPrefs('topo_mapid', { id: mapId, scale: mapScale });
+        ps.setPrefs('topo_mapid', { id: mapId, scale: mapScale, tint: tint });
         return promise;
     }
 
+    // set up theme listener to re-shade the map when required.
+    function mapShader(on) {
+        if (on) {
+            themeListener = th.addListener(function () {
+                ms.reshade(shading());
+            });
+        } else {
+            th.removeListener(themeListener);
+            themeListener = null;
+        }
+    }
+
     function opacifyMap(b) {
         mapG.transition()
             .duration(1000)
@@ -448,7 +495,8 @@
         .controller('OvTopoCtrl', ['$scope', '$log', '$location', '$timeout',
             '$cookies', 'FnService', 'MastService', 'KeyService', 'ZoomService',
             'GlyphService', 'MapService', 'SvgUtilService', 'FlashService',
-            'WebSocketService', 'PrefsService', 'TopoDialogService',
+            'WebSocketService', 'PrefsService', 'ThemeService',
+            'TopoDialogService',
             'TopoEventService', 'TopoForceService', 'TopoPanelService',
             'TopoInstService', 'TopoSelectService', 'TopoLinkService',
             'TopoTrafficService', 'TopoObliqueService', 'TopoFilterService',
@@ -456,7 +504,8 @@
             'TopoOverlayService',
 
         function (_$scope_, _$log_, $loc, $timeout, _$cookies_, _fs_, mast, _ks_,
-                  _zs_, _gs_, _ms_, _sus_, _flash_, _wss_, _ps_, _tds_, _tes_,
+                  _zs_, _gs_, _ms_, _sus_, _flash_, _wss_, _ps_, _th_,
+                  _tds_, _tes_,
                   _tfs_, _tps_, _tis_, _tss_, _tls_, _tts_, _tos_, _fltr_,
                   _ttbs_, tspr, _ttip_, _tov_) {
             var params = $loc.search(),
@@ -484,6 +533,7 @@
             flash = _flash_;
             wss = _wss_;
             ps = _ps_;
+            th = _th_;
             tds = _tds_;
             tes = _tes_;
             tfs = _tfs_;
@@ -523,6 +573,7 @@
                 tis.destroyInst();
                 tfs.destroyForce();
                 ttbs.destroyToolbar();
+                mapShader(false);
             });
 
             // svg layer and initialization of components
@@ -548,6 +599,7 @@
                     flash.enable(false);
                     toggleMap(prefsState.bg);
                     flash.enable(true);
+                    mapShader(true);
 
                     // now we have the map projection, we are ready for
                     //  the server to send us device/host data...