TopoRegions: created skeleton Topo2 UI view for development of the "region-aware" topology.
 - Added initial event generation (layout/region/ etc.) -- WIP

Change-Id: I2f93eea7505ff0400085d7f67491f6b61231cb86
diff --git a/core/api/src/main/java/org/onosproject/ui/RequestHandler.java b/core/api/src/main/java/org/onosproject/ui/RequestHandler.java
index a789a74..76710a2 100644
--- a/core/api/src/main/java/org/onosproject/ui/RequestHandler.java
+++ b/core/api/src/main/java/org/onosproject/ui/RequestHandler.java
@@ -89,6 +89,17 @@
 
     /**
      * Sends a message back to the client.
+     *
+     * @param eventType message event type
+     * @param payload   message payload
+     */
+    protected void sendMessage(String eventType, ObjectNode payload) {
+        // TODO: remove sid
+        parent.connection().sendMessage(eventType, 0, payload);
+    }
+
+    /**
+     * Sends a message back to the client.
      * Here, the message is preformatted; the assumption is it has its
      * eventType, sid and payload attributes already filled in.
      *
diff --git a/core/api/src/main/java/org/onosproject/ui/model/topo/UiDevice.java b/core/api/src/main/java/org/onosproject/ui/model/topo/UiDevice.java
index 3ed9da0..c029c2b 100644
--- a/core/api/src/main/java/org/onosproject/ui/model/topo/UiDevice.java
+++ b/core/api/src/main/java/org/onosproject/ui/model/topo/UiDevice.java
@@ -17,6 +17,7 @@
 package org.onosproject.ui.model.topo;
 
 import com.google.common.base.MoreObjects;
+import org.onosproject.cluster.NodeId;
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.region.RegionId;
@@ -30,6 +31,8 @@
     private final Device device;
 
     private RegionId regionId;
+    private NodeId masterId;
+    private boolean online;
 
     /**
      * Creates a new UI device.
@@ -51,6 +54,24 @@
         this.regionId = regionId;
     }
 
+    /**
+     * Sets the ID of the controller node that holds mastership for this device.
+     *
+     * @param masterId master identifier
+     */
+    public void setMasterId(NodeId masterId) {
+        this.masterId = masterId;
+    }
+
+    /**
+     * Sets a flag indicating whether the backing device is online.
+     *
+     * @param online boolen flag
+     */
+    public void setOnline(boolean online) {
+        this.online = online;
+    }
+
     @Override
     public String toString() {
         return MoreObjects.toStringHelper(this)
@@ -104,4 +125,32 @@
     public UiRegion uiRegion() {
         return topology.findRegion(regionId);
     }
+
+    /**
+     * Returns a string representation of the type of the backing device.
+     *
+     * @return the device type
+     */
+    public String type() {
+        return device.type().toString().toLowerCase();
+    }
+
+    /**
+     * Returns a boolean indicating whether the backing device is online.
+     *
+     * @return true if device is online, false otherwise
+     */
+    public boolean isOnline() {
+        return online;
+    }
+
+    /**
+     * Returns the identifier for the cluster member that has
+     * mastership over this device.
+     *
+     * @return master cluster member identifier
+     */
+    public NodeId master() {
+        return masterId;
+    }
 }
diff --git a/core/api/src/main/java/org/onosproject/ui/model/topo/UiNode.java b/core/api/src/main/java/org/onosproject/ui/model/topo/UiNode.java
index e39a7d2..79fdf5a 100644
--- a/core/api/src/main/java/org/onosproject/ui/model/topo/UiNode.java
+++ b/core/api/src/main/java/org/onosproject/ui/model/topo/UiNode.java
@@ -20,4 +20,41 @@
  * Represents a node drawn on the topology view (region, device, host).
  */
 abstract class UiNode extends UiElement {
+
+    /**
+     * Default "layer" tag.
+     */
+    public static final String LAYER_DEFAULT = "def";
+
+    /**
+     * Packet layer tag.
+     */
+    public static final String LAYER_PACKET = "pkt";
+
+    /**
+     * Optical layer tag.
+     */
+    public static final String LAYER_OPTICAL = "opt";
+
+
+    private String layer = LAYER_DEFAULT;
+
+    /**
+     * Returns the tag for the "layer" that the node should be rendered in
+     * when viewed in the oblique view.
+     *
+     * @return the node's layer
+     */
+    public String layer() {
+        return layer;
+    }
+
+    /**
+     * Sets this node's "layer", for layered rendering.
+     *
+     * @param layerTag the layer tag to set
+     */
+    public void setLayer(String layerTag) {
+        layer = layerTag;
+    }
 }
diff --git a/core/api/src/main/java/org/onosproject/ui/model/topo/UiRegion.java b/core/api/src/main/java/org/onosproject/ui/model/topo/UiRegion.java
index 9776216..023300c 100644
--- a/core/api/src/main/java/org/onosproject/ui/model/topo/UiRegion.java
+++ b/core/api/src/main/java/org/onosproject/ui/model/topo/UiRegion.java
@@ -22,7 +22,10 @@
 import org.onosproject.net.region.Region;
 import org.onosproject.net.region.RegionId;
 
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
@@ -37,6 +40,8 @@
     private final Set<HostId> hostIds = new HashSet<>();
     private final Set<UiLinkId> uiLinkIds = new HashSet<>();
 
+    private final List<String> layerOrder = new ArrayList<>();
+
     private final UiTopology topology;
 
     private final Region region;
@@ -50,6 +55,8 @@
     public UiRegion(UiTopology topology, Region region) {
         this.topology = topology;
         this.region = region;
+        // unless told otherwise, we'll use a single, default layer
+        layerOrder.add(UiNode.LAYER_DEFAULT);
     }
 
     @Override
@@ -60,6 +67,17 @@
     }
 
     /**
+     * Sets the layer order for this region.
+     * Typically, the {@code UiNode.LAYER_*} constants will be used here.
+     *
+     * @param layers the layers
+     */
+    public void setLayerOrder(String... layers) {
+        layerOrder.clear();
+        Collections.addAll(layerOrder, layers);
+    }
+
+    /**
      * Returns the identity of the region.
      *
      * @return region ID
@@ -170,4 +188,19 @@
     public Set<UiLink> links() {
         return topology.linkSet(uiLinkIds);
     }
+
+    /**
+     * Returns the order in which layers should be rendered. Lower layers
+     * come earlier in the list. For example, to indicate that nodes in the
+     * optical layer should be rendered "below" nodes in the packet layer,
+     * this method should return:
+     * <pre>
+     * [UiNode.LAYER_OPTICAL, UiNode.LAYER_PACKET]
+     * </pre>
+     *
+     * @return layer ordering
+     */
+    public List<String> layerOrder() {
+        return Collections.unmodifiableList(layerOrder);
+    }
 }
diff --git a/core/api/src/main/java/org/onosproject/ui/model/topo/UiTopoLayout.java b/core/api/src/main/java/org/onosproject/ui/model/topo/UiTopoLayout.java
index 8b421c0..604cf65 100644
--- a/core/api/src/main/java/org/onosproject/ui/model/topo/UiTopoLayout.java
+++ b/core/api/src/main/java/org/onosproject/ui/model/topo/UiTopoLayout.java
@@ -17,6 +17,7 @@
 package org.onosproject.ui.model.topo;
 
 import org.onosproject.net.region.Region;
+import org.onosproject.net.region.RegionId;
 
 /**
  * Represents a specific "subset" of the UI model of the network topology
@@ -41,6 +42,11 @@
         this.parent = parent;
     }
 
+    @Override
+    public String toString() {
+        return "{UiTopoLayout: " + id + "}";
+    }
+
     /**
      * Returns the UI layout identifier.
      *
@@ -51,7 +57,8 @@
     }
 
     /**
-     * Returns the backing region with which this layout is associated.
+     * Returns the backing region with which this layout is associated. Note
+     * that this may be null (for the root layout).
      *
      * @return backing region
      */
@@ -60,6 +67,16 @@
     }
 
     /**
+     * Returns the identifier of the backing region. Will be null if the
+     * region is null.
+     *
+     * @return backing region identifier
+     */
+    public RegionId regionId() {
+        return region == null ? null : region.id();
+    }
+
+    /**
      * Returns the parent layout identifier.
      *
      * @return parent layout identifier
diff --git a/core/api/src/main/java/org/onosproject/ui/model/topo/UiTopology.java b/core/api/src/main/java/org/onosproject/ui/model/topo/UiTopology.java
index 9555e3a..5ce91da 100644
--- a/core/api/src/main/java/org/onosproject/ui/model/topo/UiTopology.java
+++ b/core/api/src/main/java/org/onosproject/ui/model/topo/UiTopology.java
@@ -23,8 +23,12 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -46,6 +50,9 @@
 
     private static final Logger log = LoggerFactory.getLogger(UiTopology.class);
 
+    private static final Comparator<UiClusterMember> CLUSTER_MEMBER_COMPARATOR =
+            (o1, o2) -> o1.idAsString().compareTo(o2.idAsString());
+
 
     // top level mappings of topology elements by ID
     private final Map<NodeId, UiClusterMember> cnodeLookup = new HashMap<>();
@@ -84,6 +91,18 @@
         linkLookup.clear();
     }
 
+
+    /**
+     * Returns all the cluster members, sorted by their ID.
+     *
+     * @return all cluster members
+     */
+    public List<UiClusterMember> allClusterMembers() {
+        List<UiClusterMember> members = new ArrayList<>(cnodeLookup.values());
+        Collections.sort(members, CLUSTER_MEMBER_COMPARATOR);
+        return members;
+    }
+
     /**
      * Returns the cluster member with the given identifier, or null if no
      * such member exists.