ONOS-1479 - GUI Topology Overlay Work - (WIP)
- Implemented initial ability to have overlay modify the summary panel data.

Change-Id: I0d6bd6d62f0e0d5ba9d901a47271044e0c8d0c89
diff --git a/core/api/src/main/java/org/onosproject/ui/UiTopoOverlay.java b/core/api/src/main/java/org/onosproject/ui/UiTopoOverlay.java
index 999067a..a36d510 100644
--- a/core/api/src/main/java/org/onosproject/ui/UiTopoOverlay.java
+++ b/core/api/src/main/java/org/onosproject/ui/UiTopoOverlay.java
@@ -17,6 +17,7 @@
 
 package org.onosproject.ui;
 
+import org.onosproject.ui.topo.PropertyPanel;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -75,4 +76,13 @@
      */
     public void destroy() {
     }
+
+    /**
+     * Callback to modify the contents of the summary panel.
+     * This default implementation does nothing.
+     *
+     * @param pp property panel model of summary data
+     */
+    public void modifySummary(PropertyPanel pp) {
+    }
 }
diff --git a/core/api/src/main/java/org/onosproject/ui/topo/PropertyPanel.java b/core/api/src/main/java/org/onosproject/ui/topo/PropertyPanel.java
new file mode 100644
index 0000000..33745c3
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/ui/topo/PropertyPanel.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.onosproject.ui.topo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Models a panel displayed on the Topology View.
+ */
+public class PropertyPanel {
+
+    private String title;
+    private String typeId;
+    private List<Prop> properties = new ArrayList<>();
+
+
+    public PropertyPanel(String title, String typeId) {
+        this.title = title;
+        this.typeId = typeId;
+    }
+
+    public PropertyPanel add(Prop p) {
+        properties.add(p);
+        return this;
+    }
+
+    public String title() {
+        return title;
+    }
+
+    public String typeId() {
+        return typeId;
+    }
+
+    // TODO: consider protecting this?
+    public List<Prop> properties() {
+        return properties;
+    }
+
+    public PropertyPanel title(String title) {
+        this.title = title;
+        return this;
+    }
+
+    // TODO: add other builder-like setters here
+
+
+    // ====================
+
+    public static class Prop {
+        public final String key;
+        public final String value;
+
+        public Prop(String key, String value) {
+            this.key = key;
+            this.value = value;
+        }
+
+        public String key() {
+            return key;
+        }
+
+        public String value() {
+            return value;
+        }
+    }
+
+    // Auxiliary properties separator
+    public static class Separator extends Prop {
+        public Separator() {
+            super("-", "");
+        }
+    }
+
+}
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/TopoOverlayCache.java b/web/gui/src/main/java/org/onosproject/ui/impl/TopoOverlayCache.java
index 2490041..3d6d900 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/TopoOverlayCache.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/TopoOverlayCache.java
@@ -22,13 +22,22 @@
 import java.util.HashMap;
 import java.util.Map;
 
+import static com.google.common.base.Strings.isNullOrEmpty;
+
 /**
  * A cache of {@link org.onosproject.ui.UiTopoOverlay}'s that were registered
  * at the time the UI connection was established.
  */
 public class TopoOverlayCache {
 
+    private static final UiTopoOverlay NONE = new NullOverlay();
+
     private final Map<String, UiTopoOverlay> overlays = new HashMap<>();
+    private UiTopoOverlay current = NONE;
+
+    public TopoOverlayCache() {
+        overlays.put(null, NONE);
+    }
 
     /**
      * Adds a topology overlay to the cache.
@@ -55,16 +64,18 @@
     public void switchOverlay(String deact, String act) {
         UiTopoOverlay toDeactivate = getOverlay(deact);
         UiTopoOverlay toActivate = getOverlay(act);
-        if (toDeactivate != null) {
-            toDeactivate.deactivate();
-        }
-        if (toActivate != null) {
-            toActivate.activate();
-        }
+
+        toDeactivate.deactivate();
+        current = toActivate;
+        current.activate();
     }
 
     private UiTopoOverlay getOverlay(String id) {
-        return id == null ? null : overlays.get(id);
+        return isNullOrEmpty(id) ? NONE : overlays.get(id);
+    }
+
+    public UiTopoOverlay currentOverlay() {
+        return current;
     }
 
     /**
@@ -75,4 +86,28 @@
     public int size() {
         return overlays.size();
     }
+
+
+
+    private static class NullOverlay extends UiTopoOverlay {
+        public NullOverlay() {
+            super(null);
+        }
+
+        @Override
+        public void init() {
+        }
+
+        @Override
+        public void activate() {
+        }
+
+        @Override
+        public void deactivate() {
+        }
+
+        @Override
+        public void destroy() {
+        }
+    }
 }
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 6d2295a..11839df 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
@@ -57,6 +57,7 @@
 import org.onosproject.ui.JsonUtils;
 import org.onosproject.ui.RequestHandler;
 import org.onosproject.ui.UiConnection;
+import org.onosproject.ui.topo.PropertyPanel;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -561,7 +562,10 @@
 
     // Subscribes for summary messages.
     private synchronized void requestSummary(long sid) {
-        sendMessage(summmaryMessage(sid));
+        PropertyPanel pp = summmaryMessage(sid);
+        overlayCache.currentOverlay().modifySummary(pp);
+        ObjectNode json = JsonUtils.envelope("showSummary", sid, json(pp));
+        sendMessage(json);
     }
 
 
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java
index 336d6f2..42dcd9f 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java
@@ -72,6 +72,7 @@
 import org.onosproject.ui.JsonUtils;
 import org.onosproject.ui.UiConnection;
 import org.onosproject.ui.UiMessageHandler;
+import org.onosproject.ui.topo.PropertyPanel;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -443,19 +444,20 @@
     }
 
     // Returns summary response.
-    protected ObjectNode summmaryMessage(long sid) {
+    protected PropertyPanel summmaryMessage(long sid) {
         Topology topology = topologyService.currentTopology();
-        return JsonUtils.envelope("showSummary", sid,
-                                  json("ONOS Summary", "node",
-                                       new Prop("Devices", format(topology.deviceCount())),
-                                       new Prop("Links", format(topology.linkCount())),
-                                       new Prop("Hosts", format(hostService.getHostCount())),
-                                       new Prop("Topology SCCs", format(topology.clusterCount())),
-                                       new Separator(),
-                                       new Prop("Intents", format(intentService.getIntentCount())),
-                                       new Prop("Tunnels", format(tunnelService.tunnelCount())),
-                                       new Prop("Flows", format(flowService.getFlowRuleCount())),
-                                       new Prop("Version", version)));
+        PropertyPanel pp = new PropertyPanel("ONOS Summary", "node")
+            .add(new PropertyPanel.Prop("Devices", format(topology.deviceCount())))
+            .add(new PropertyPanel.Prop("Links", format(topology.linkCount())))
+            .add(new PropertyPanel.Prop("Hosts", format(hostService.getHostCount())))
+            .add(new PropertyPanel.Prop("Topology SCCs", format(topology.clusterCount())))
+            .add(new PropertyPanel.Separator())
+            .add(new PropertyPanel.Prop("Intents", format(intentService.getIntentCount())))
+            .add(new PropertyPanel.Prop("Tunnels", format(tunnelService.tunnelCount())))
+            .add(new PropertyPanel.Prop("Flows", format(flowService.getFlowRuleCount())))
+            .add(new PropertyPanel.Prop("Version", version));
+
+        return pp;
     }
 
     // Returns device details response.
@@ -840,6 +842,20 @@
                              link.dst().elementId(), link.dst().port());
     }
 
+    protected ObjectNode json(PropertyPanel pp) {
+        ObjectNode result = objectNode()
+                .put("title", pp.title()).put("type", pp.typeId());
+        ObjectNode pnode = objectNode();
+        ArrayNode porder = arrayNode();
+        for (PropertyPanel.Prop p : pp.properties()) {
+            porder.add(p.key());
+            pnode.put(p.key(), p.value());
+        }
+        result.set("propOrder", porder);
+        result.set("props", pnode);
+        return result;
+    }
+
     // Produces JSON property details.
     private ObjectNode json(String id, String type, Prop... props) {
         ObjectNode result = objectNode()
diff --git a/web/gui/src/main/webapp/app/view/topo/topoOverlay.js b/web/gui/src/main/webapp/app/view/topo/topoOverlay.js
index fd704a6..e2b3125 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoOverlay.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoOverlay.js
@@ -126,6 +126,9 @@
             current = overlay(id);
             current && doop('activate');
             wss.sendEvent('topoSelectOverlay', payload);
+
+            // TODO: refactor to emit "flush on overlay change" messages
+            wss.sendEvent('requestSummary');
         }
     }
 
diff --git a/web/gui/src/main/webapp/app/view/topo/topoPanel.js b/web/gui/src/main/webapp/app/view/topo/topoPanel.js
index b55f084..87dd1bd 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoPanel.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoPanel.js
@@ -208,7 +208,7 @@
         gs.addGlyph(svg, 'node', 40);
         gs.addGlyph(svg, 'bird', 24, true, [8,12]);
 
-        title.text(data.id);
+        title.text(data.title);
         listProps(tbody, data);
     }