GUI -- Reworked sprite definition loading via websocket events.
- includes option to specify sprite definition id: #/topo?sprites=defn_name.

Change-Id: If2ce59384e01bb5f35827a503748e21ab4fb1b31
diff --git a/tools/test/bin/onos-upload-sprites b/tools/test/bin/onos-upload-sprites
index 0bf9bef..982d713 100755
--- a/tools/test/bin/onos-upload-sprites
+++ b/tools/test/bin/onos-upload-sprites
@@ -6,6 +6,12 @@
 node=${1}
 sprites=${2}
 
+if [ -z "$node" -o -z "$sprites" ]
+then
+    echo "Usage: onos-upload-sprites <server-ip> <sprites-defn.json>"
+    exit 1
+fi
+
 export URL=http://$node:8181/onos/ui/rs/topology/sprites
 export HDR="-HContent-Type:application/json"
 
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyResource.java b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyResource.java
index 5bb46f2..b574b77 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyResource.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyResource.java
@@ -86,7 +86,7 @@
     @Consumes("application/json")
     public Response setSprites(InputStream stream) throws IOException {
         JsonNode root = mapper.readTree(stream);
-        String name = root.path("defn_id").asText("sprites");
+        String name = root.path("defn_name").asText("sprites");
         get(SpriteService.class).put(name, root);
         return Response.ok().build();
     }
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java
index cd8c3c2..3cc12b3 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java
@@ -581,8 +581,9 @@
 
     // Sends requested sprite data.
     private void sendSpriteData(ObjectNode event) {
+        String name = event.path("payload").path("name").asText();
         ObjectNode root = mapper.createObjectNode();
-        root.set("defn", get(SpriteService.class).get(event.path("payload").path("name").asText()));
+        root.set("data", get(SpriteService.class).get(name));
         sendMessage(envelope("spriteDataResponse", number(event, "sid"), root));
     }
 
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java b/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java
index 66138e7..408a85a 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java
@@ -130,7 +130,7 @@
 
     @Override
     public void put(String name, JsonNode spriteData) {
-        log.info("Registered sprite definition {}", name);
+        log.info("Registered sprite definition [{}]", name);
         sprites.put(name, spriteData);
     }
 
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 68ecf2c..f4d08f2 100644
--- a/web/gui/src/main/webapp/app/view/topo/topo.js
+++ b/web/gui/src/main/webapp/app/view/topo/topo.js
@@ -366,7 +366,7 @@
                 }
             );
             spriteG = zoomLayer.append ('g').attr('id', 'topo-sprites');
-            tspr.loadSprites(spriteG);
+            tspr.loadSprites(spriteG, $loc.search().sprites);
 
             forceG = zoomLayer.append('g').attr('id', 'topo-force');
             tfs.initForce(svg, forceG, uplink, dim);
diff --git a/web/gui/src/main/webapp/app/view/topo/topoEvent.js b/web/gui/src/main/webapp/app/view/topo/topoEvent.js
index 154cd4c..68f2e10 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoEvent.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoEvent.js
@@ -27,7 +27,7 @@
     'use strict';
 
     // injected refs
-    var $log, wss, tps, tis, tfs, tss, tts;
+    var $log, wss, tps, tis, tfs, tss, tts, tspr;
 
     // internal state
     var handlerMap,
@@ -55,7 +55,10 @@
             removeHost: tfs,
             addLink: tfs,
             updateLink: tfs,
-            removeLink: tfs
+            removeLink: tfs,
+
+            spriteListResponse: tspr,
+            spriteDataResponse: tspr
         };
     }
 
@@ -69,9 +72,9 @@
     .factory('TopoEventService',
         ['$log', '$location', 'WebSocketService',
             'TopoPanelService', 'TopoInstService', 'TopoForceService',
-            'TopoSelectService', 'TopoTrafficService',
+            'TopoSelectService', 'TopoTrafficService', 'TopoSpriteService',
 
-        function (_$log_, $loc, _wss_, _tps_, _tis_, _tfs_, _tss_, _tts_) {
+        function (_$log_, $loc, _wss_, _tps_, _tis_, _tfs_, _tss_, _tts_, _tspr_) {
             $log = _$log_;
             wss = _wss_;
             tps = _tps_;
@@ -79,6 +82,7 @@
             tfs = _tfs_;
             tss = _tss_;
             tts = _tts_;
+            tspr = _tspr_;
 
             createHandlerMap();
 
@@ -86,8 +90,6 @@
                 openListener = wss.addOpenListener(wsOpen);
                 wss.bindHandlers(handlerMap);
                 wss.sendEvent('topoStart');
-                wss.sendEvent('spriteListRequest');
-                wss.sendEvent('spriteDataRequest', {name: 'sample'});
                 $log.debug('topo comms started');
             }
 
diff --git a/web/gui/src/main/webapp/app/view/topo/topoSprite.js b/web/gui/src/main/webapp/app/view/topo/topoSprite.js
index 15e5182..1586a04 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoSprite.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoSprite.js
@@ -23,55 +23,12 @@
     'use strict';
 
     // injected refs
-    var $log, $http, fs, sus;
+    var $log, $http, fs, sus, wss;
+
+    var tssid = 'TopoSpriteService: ';
 
     // internal state
-    var spriteLayer,
-        cache = d3.map();
-
-    // constants
-    var urlPrefix = 'data/ext/';
-
-    function getUrl(id) {
-        return urlPrefix + id + '.json';
-    }
-
-    // =========================
-
-    function clearCache() {
-        cache = d3.map();
-    }
-
-
-    function loadSpriteData(id, cb) {
-        var url = getUrl(id),
-            promise = cache.get(id);
-
-        if (!promise) {
-            // need to fetch data and cache it
-            promise = $http.get(url);
-
-            promise.meta = {
-                id: id,
-                url: url,
-                wasCached: false
-            };
-
-            promise.then(function (response) {
-                // success
-                promise.spriteData = response.data;
-                cb(promise.spriteData);
-            }, function (response) {
-                // error
-                $log.warn('Failed to retrieve sprite data: ' + url,
-                    response.status, response.data);
-            });
-
-        } else {
-            promise.meta.wasCached = true;
-            cb(promise.spriteData);
-        }
-    }
+    var spriteLayer;
 
     function doSprite(def, item) {
         var g;
@@ -100,42 +57,71 @@
         });
     }
 
-    function loadSprites(layer) {
-        spriteLayer = layer;
+    // ==========================
+    // event handlers
 
-        loadSpriteData('sprites', function (data) {
-            var defs = {};
-
-            $log.debug("Loading sprites...", data.file_desc);
-
-            data.defn.forEach(function (d) {
-                defs[d.id] = d;
-            });
-
-            data.load.forEach(function (item) {
-                doSprite(defs[item.id], item);
-            });
-        });
-
+    // Handles response from 'spriteListRequest' which lists all the
+    // registered sprite definitions on the server.
+    // (see onos-upload-sprites)
+    function inList(payload) {
+        $log.debug(tssid + 'Registered sprite definitions:', payload.names);
+        // Some day, we will make this list available to the user in
+        //  a dropdown selection box...
     }
 
+    // Handles response from 'spriteDataRequest' which provides the
+    //  data for the requested sprite definition.
+    function inData(payload) {
+        var data = payload.data,
+            name = data && data.defn_name,
+            desc = data && data.defn_desc,
+            defs = {};
+
+        if (!data) {
+            $log.warn(tssid + 'No sprite data loaded.')
+            return;
+        }
+
+        $log.debug("Loading sprites...[" + name + "]", desc);
+
+        data.defn.forEach(function (d) {
+            defs[d.id] = d;
+        });
+
+        data.load.forEach(function (item) {
+            doSprite(defs[item.id], item);
+        });
+    }
+
+
+    function loadSprites(layer, defname) {
+        var name = defname || 'sprites';
+        spriteLayer = layer;
+
+        $log.info(tssid + 'Requesting sprite definition ['+name+']...');
+
+        wss.sendEvent('spriteListRequest');
+        wss.sendEvent('spriteDataRequest', {name: name});
+    }
 
     // === -----------------------------------------------------
     // === MODULE DEFINITION ===
 
     angular.module('ovTopo')
     .factory('TopoSpriteService',
-        ['$log', '$http', 'FnService', 'SvgUtilService',
+        ['$log', '$http', 'FnService', 'SvgUtilService', 'WebSocketService',
 
-        function (_$log_, _$http_, _fs_, _sus_) {
+        function (_$log_, _$http_, _fs_, _sus_, _wss_) {
             $log = _$log_;
             $http = _$http_;
             fs = _fs_;
             sus = _sus_;
+            wss = _wss_;
 
             return {
-                clearCache: clearCache,
-                loadSprites: loadSprites
+                loadSprites: loadSprites,
+                spriteListResponse: inList,
+                spriteDataResponse: inData
             };
         }]);
 
diff --git a/web/gui/src/main/webapp/data/ext/sprites.json b/web/gui/src/main/webapp/data/sprites/sprites.json
similarity index 93%
rename from web/gui/src/main/webapp/data/ext/sprites.json
rename to web/gui/src/main/webapp/data/sprites/sprites.json
index ca8c2fe..f92e705 100644
--- a/web/gui/src/main/webapp/data/ext/sprites.json
+++ b/web/gui/src/main/webapp/data/sprites/sprites.json
@@ -1,6 +1,6 @@
 {
-  "defn_id": "sample",
-  "file_desc": "Cloud Sprite Data",
+  "defn_name": "sample",
+  "defn_desc": "Sample Cloud Sprite Data",
 
   "_comment": [
     "configuration file for loading canned and/or custom sprites (and labels)",