ONOS-1479 -- GUI - augmenting topology view for extensibility: WIP.
- Major refactoring of TopologyViewMessageHandler and related classes.

Change-Id: I920f7f9f7317f3987a9a8da35ac086e9f8cab8d3
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 9265e5f..130f88f 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
@@ -18,7 +18,6 @@
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.google.common.collect.ImmutableList;
 import org.onlab.osgi.ServiceDirectory;
 import org.onlab.packet.IpAddress;
 import org.onosproject.cluster.ClusterEvent;
@@ -43,8 +42,6 @@
 import org.onosproject.net.HostId;
 import org.onosproject.net.HostLocation;
 import org.onosproject.net.Link;
-import org.onosproject.net.LinkKey;
-import org.onosproject.net.NetworkResource;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.device.DeviceEvent;
 import org.onosproject.net.device.DeviceService;
@@ -55,29 +52,26 @@
 import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
 import org.onosproject.net.host.HostEvent;
 import org.onosproject.net.host.HostService;
-import org.onosproject.net.intent.FlowRuleIntent;
-import org.onosproject.net.intent.Intent;
 import org.onosproject.net.intent.IntentService;
-import org.onosproject.net.intent.LinkCollectionIntent;
-import org.onosproject.net.intent.OpticalConnectivityIntent;
-import org.onosproject.net.intent.OpticalPathIntent;
-import org.onosproject.net.intent.PathIntent;
 import org.onosproject.net.link.LinkEvent;
 import org.onosproject.net.link.LinkService;
 import org.onosproject.net.provider.ProviderId;
-import org.onosproject.net.statistic.Load;
 import org.onosproject.net.statistic.StatisticService;
 import org.onosproject.net.topology.Topology;
 import org.onosproject.net.topology.TopologyService;
 import org.onosproject.ui.JsonUtils;
 import org.onosproject.ui.UiConnection;
 import org.onosproject.ui.UiMessageHandler;
+import org.onosproject.ui.impl.topo.ServicesBundle;
 import org.onosproject.ui.topo.ButtonId;
+import org.onosproject.ui.topo.DeviceHighlight;
+import org.onosproject.ui.topo.Highlights;
+import org.onosproject.ui.topo.HostHighlight;
+import org.onosproject.ui.topo.LinkHighlight;
 import org.onosproject.ui.topo.PropertyPanel;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.text.DecimalFormat;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -95,10 +89,6 @@
 import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_REMOVED;
 import static org.onosproject.cluster.ControllerNode.State.ACTIVE;
 import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
-import static org.onosproject.net.DeviceId.deviceId;
-import static org.onosproject.net.HostId.hostId;
-import static org.onosproject.net.LinkKey.linkKey;
-import static org.onosproject.net.PortNumber.P0;
 import static org.onosproject.net.PortNumber.portNumber;
 import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
 import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_REMOVED;
@@ -106,8 +96,7 @@
 import static org.onosproject.net.host.HostEvent.Type.HOST_REMOVED;
 import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED;
 import static org.onosproject.net.link.LinkEvent.Type.LINK_REMOVED;
-import static org.onosproject.ui.impl.TopologyViewMessageHandlerBase.StatsType.FLOW;
-import static org.onosproject.ui.impl.TopologyViewMessageHandlerBase.StatsType.PORT;
+import static org.onosproject.ui.impl.topo.TopoUtils.compactLinkString;
 import static org.onosproject.ui.topo.TopoConstants.CoreButtons;
 import static org.onosproject.ui.topo.TopoConstants.Properties;
 
@@ -121,24 +110,8 @@
 
     private static final ProviderId PID =
             new ProviderId("core", "org.onosproject.core", true);
-    private static final String COMPACT = "%s/%s-%s/%s";
 
-    private static final String SHOW_HIGHLIGHTS = "showHighlights";
-
-    private static final double KILO = 1024;
-    private static final double MEGA = 1024 * KILO;
-    private static final double GIGA = 1024 * MEGA;
-
-    private static final String GBITS_UNIT = "Gb";
-    private static final String MBITS_UNIT = "Mb";
-    private static final String KBITS_UNIT = "Kb";
-    private static final String BITS_UNIT = "b";
-    private static final String GBYTES_UNIT = "GB";
-    private static final String MBYTES_UNIT = "MB";
-    private static final String KBYTES_UNIT = "KB";
-    private static final String BYTES_UNIT = "B";
-    //4 Kilo Bytes as threshold
-    private static final double BPS_THRESHOLD = 4 * KILO;
+    protected static final String SHOW_HIGHLIGHTS = "showHighlights";
 
     protected ServiceDirectory directory;
     protected ClusterService clusterService;
@@ -153,9 +126,7 @@
     protected TopologyService topologyService;
     protected TunnelService tunnelService;
 
-    protected enum StatsType {
-        FLOW, PORT
-    }
+    protected ServicesBundle servicesBundle;
 
     private String version;
 
@@ -187,6 +158,11 @@
         topologyService = directory.get(TopologyService.class);
         tunnelService = directory.get(TunnelService.class);
 
+        servicesBundle = new ServicesBundle(intentService, deviceService,
+                                            hostService, linkService,
+                                            flowService,
+                                            flowStatsService, portStatsService);
+
         String ver = directory.get(CoreService.class).version().toString();
         version = ver.replace(".SNAPSHOT", "*").replaceFirst("~.*$", "");
     }
@@ -232,64 +208,6 @@
         return JsonUtils.envelope("message", id, payload);
     }
 
-    // Produces a set of all hosts listed in the specified JSON array.
-    protected Set<Host> getHosts(ArrayNode array) {
-        Set<Host> hosts = new HashSet<>();
-        if (array != null) {
-            for (JsonNode node : array) {
-                try {
-                    addHost(hosts, hostId(node.asText()));
-                } catch (IllegalArgumentException e) {
-                    log.debug("Skipping ID {}", node.asText());
-                }
-            }
-        }
-        return hosts;
-    }
-
-    // Adds the specified host to the set of hosts.
-    private void addHost(Set<Host> hosts, HostId hostId) {
-        Host host = hostService.getHost(hostId);
-        if (host != null) {
-            hosts.add(host);
-        }
-    }
-
-
-    // Produces a set of all devices listed in the specified JSON array.
-    protected Set<Device> getDevices(ArrayNode array) {
-        Set<Device> devices = new HashSet<>();
-        if (array != null) {
-            for (JsonNode node : array) {
-                try {
-                    addDevice(devices, deviceId(node.asText()));
-                } catch (IllegalArgumentException e) {
-                    log.debug("Skipping ID {}", node.asText());
-                }
-            }
-        }
-        return devices;
-    }
-
-    private void addDevice(Set<Device> devices, DeviceId deviceId) {
-        Device device = deviceService.getDevice(deviceId);
-        if (device != null) {
-            devices.add(device);
-        }
-    }
-
-    protected void addHover(Set<Host> hosts, Set<Device> devices, String hover) {
-        try {
-            addHost(hosts, hostId(hover));
-        } catch (IllegalArgumentException e) {
-            try {
-                addDevice(devices, deviceId(hover));
-            } catch (IllegalArgumentException ne) {
-                log.debug("Skipping ID {}", hover);
-            }
-        }
-    }
-
     // Produces a cluster instance message to the client.
     protected ObjectNode instanceMessage(ClusterEvent event, String messageType) {
         ControllerNode node = event.subject();
@@ -445,6 +363,7 @@
                    JsonUtils.node(payload, "memento"));
     }
 
+
     // -----------------------------------------------------------------------
     // Create models of the data to return, that overlays can adjust / augment
 
@@ -527,24 +446,24 @@
         return count;
     }
 
-    // Counts all entries that egress on the given device links.
-    protected Map<Link, Integer> getFlowCounts(DeviceId deviceId) {
+    // Counts all flow entries that egress on the links of the given device.
+    private Map<Link, Integer> getLinkFlowCounts(DeviceId deviceId) {
+        // get the flows for the device
         List<FlowEntry> entries = new ArrayList<>();
-        Set<Link> links = new HashSet<>(linkService.getDeviceEgressLinks(deviceId));
-        Set<Host> hosts = hostService.getConnectedHosts(deviceId);
         for (FlowEntry flowEntry : flowService.getFlowEntries(deviceId)) {
             entries.add(flowEntry);
         }
 
-        // Add all edge links to the set
+        // get egress links from device, and include edge links
+        Set<Link> links = new HashSet<>(linkService.getDeviceEgressLinks(deviceId));
+        Set<Host> hosts = hostService.getConnectedHosts(deviceId);
         if (hosts != null) {
             for (Host host : hosts) {
-                links.add(new DefaultEdgeLink(host.providerId(),
-                                              new ConnectPoint(host.id(), P0),
-                                              host.location(), false));
+                links.add(createEdgeLink(host, false));
             }
         }
 
+        // compile flow counts per link
         Map<Link, Integer> counts = new HashMap<>();
         for (Link link : links) {
             counts.put(link, getEgressFlows(link, entries));
@@ -553,7 +472,7 @@
     }
 
     // Counts all entries that egress on the link source port.
-    private Integer getEgressFlows(Link link, List<FlowEntry> entries) {
+    private int getEgressFlows(Link link, List<FlowEntry> entries) {
         int count = 0;
         PortNumber out = link.src().port();
         for (FlowEntry entry : entries) {
@@ -568,7 +487,6 @@
         return count;
     }
 
-
     // Returns host details response.
     protected PropertyPanel hostDetails(HostId hostId, long sid) {
         Host host = hostService.getHost(hostId);
@@ -589,270 +507,98 @@
             .addProp(Properties.LATITUDE, annot.value(AnnotationKeys.LATITUDE))
             .addProp(Properties.LONGITUDE, annot.value(AnnotationKeys.LONGITUDE));
 
-        // TODO: add button descriptors
+        // Potentially add button descriptors here
         return pp;
     }
 
 
-    // TODO: migrate to Traffic overlay
-    // Produces JSON message to trigger flow traffic overview visualization
-    protected ObjectNode trafficSummaryMessage(StatsType type) {
+    // ----------------------------------------------------------------------
+
+    /**
+     * Transforms the given highlights model into a JSON message payload.
+     *
+     * @param highlights the model to transform
+     * @return JSON payload
+     */
+    protected ObjectNode json(Highlights highlights) {
         ObjectNode payload = objectNode();
-        ArrayNode paths = arrayNode();
-        payload.set("paths", paths);
 
-        ObjectNode pathNodeN = objectNode();
-        ArrayNode linksNodeN = arrayNode();
-        ArrayNode labelsN = arrayNode();
+        ArrayNode devices = arrayNode();
+        ArrayNode hosts = arrayNode();
+        ArrayNode links = arrayNode();
 
-        pathNodeN.put("class", "plain").put("traffic", false);
-        pathNodeN.set("links", linksNodeN);
-        pathNodeN.set("labels", labelsN);
-        paths.add(pathNodeN);
+        payload.set("devices", devices);
+        payload.set("hosts", hosts);
+        payload.set("links", links);
 
-        ObjectNode pathNodeT = objectNode();
-        ArrayNode linksNodeT = arrayNode();
-        ArrayNode labelsT = arrayNode();
+        highlights.devices().forEach(dh -> devices.add(json(dh)));
+        highlights.hosts().forEach(hh -> hosts.add(json(hh)));
+        jsonifyLinks(links, highlights.links());
 
-        pathNodeT.put("class", "secondary").put("traffic", true);
-        pathNodeT.set("links", linksNodeT);
-        pathNodeT.set("labels", labelsT);
-        paths.add(pathNodeT);
-
-        Map<LinkKey, BiLink> biLinks = consolidateLinks(linkService.getLinks());
-        addEdgeLinks(biLinks);
-        for (BiLink link : biLinks.values()) {
-            boolean bi = link.two != null;
-            if (type == FLOW) {
-                link.addLoad(getLinkLoad(link.one));
-                link.addLoad(bi ? getLinkLoad(link.two) : null);
-            } else if (type == PORT) {
-                //For a bi-directional traffic links, use
-                //the max link rate of either direction
-                link.addLoad(portStatsService.load(link.one.src()),
-                             BPS_THRESHOLD,
-                             portStatsService.load(link.one.dst()),
-                             BPS_THRESHOLD);
-            }
-            if (link.hasTraffic) {
-                linksNodeT.add(compactLinkString(link.one));
-                labelsT.add(type == PORT ?
-                                    formatBitRate(link.rate) + "ps" :
-                                    formatBytes(link.bytes));
-            } else {
-                linksNodeN.add(compactLinkString(link.one));
-                labelsN.add("");
-            }
-        }
-        return JsonUtils.envelope(SHOW_HIGHLIGHTS, 0, payload);
+        return payload;
     }
 
-    private Load getLinkLoad(Link link) {
-        if (link.src().elementId() instanceof DeviceId) {
-            return flowStatsService.load(link);
-        }
-        return null;
-    }
+    private void jsonifyLinks(ArrayNode links, Set<LinkHighlight> hilites) {
+        // a little more complicated than devices or hosts, since we are
+        //  grouping the link highlights by CSS classes
 
-    private void addEdgeLinks(Map<LinkKey, BiLink> biLinks) {
-        hostService.getHosts().forEach(host -> {
-            addLink(biLinks, createEdgeLink(host, true));
-            addLink(biLinks, createEdgeLink(host, false));
-        });
-    }
-
-    private Map<LinkKey, BiLink> consolidateLinks(Iterable<Link> links) {
-        Map<LinkKey, BiLink> biLinks = new HashMap<>();
-        for (Link link : links) {
-            addLink(biLinks, link);
-        }
-        return biLinks;
-    }
-
-    // Produces JSON message to trigger flow overview visualization
-    protected ObjectNode flowSummaryMessage(Set<Device> devices) {
-        ObjectNode payload = objectNode();
-        ArrayNode paths = arrayNode();
-        payload.set("paths", paths);
-
-        for (Device device : devices) {
-            Map<Link, Integer> counts = getFlowCounts(device.id());
-            for (Link link : counts.keySet()) {
-                addLinkFlows(link, paths, counts.get(link));
-            }
-        }
-        return JsonUtils.envelope(SHOW_HIGHLIGHTS, 0, payload);
-    }
-
-    private void addLinkFlows(Link link, ArrayNode paths, Integer count) {
-        ObjectNode pathNode = objectNode();
-        ArrayNode linksNode = arrayNode();
-        ArrayNode labels = arrayNode();
-        boolean noFlows = count == null || count == 0;
-        pathNode.put("class", noFlows ? "secondary" : "primary");
-        pathNode.put("traffic", false);
-        pathNode.set("links", linksNode.add(compactLinkString(link)));
-        pathNode.set("labels", labels.add(noFlows ? "" : (count.toString() +
-                (count == 1 ? " flow" : " flows"))));
-        paths.add(pathNode);
-    }
+        // TODO: refactor this method (including client side) to use new format
+        //       as a more compact representation of the data...
+        // * links:
+        //   * "primary animated":
+        //     * "link01" -> "label"
+        //     * "link02" -> "label"
+        //   * "secondary":
+        //     * "link04" -> "label"
+        //     * "link05" -> ""
 
 
-    // Produces JSON message to trigger traffic visualization
-    protected ObjectNode trafficMessage(TrafficClass... trafficClasses) {
-        ObjectNode payload = objectNode();
-        ArrayNode paths = arrayNode();
-        payload.set("paths", paths);
+        Map<String, List<String>> linkIdMap = new HashMap<>();
+        Map<String, List<String>> linkLabelMap = new HashMap<>();
+        List<String> ids;
+        List<String> labels;
 
-        // Classify links based on their traffic traffic first...
-        Map<LinkKey, BiLink> biLinks = classifyLinkTraffic(trafficClasses);
+        for (LinkHighlight lh : hilites) {
+            String cls = lh.cssClasses();
+            ids = linkIdMap.get(cls);
+            labels = linkLabelMap.get(cls);
 
-        // Then separate the links into their respective classes and send them out.
-        Map<String, ObjectNode> pathNodes = new HashMap<>();
-        for (BiLink biLink : biLinks.values()) {
-            boolean hasTraffic = biLink.hasTraffic;
-            String tc = (biLink.classes() + (hasTraffic ? " animated" : "")).trim();
-            ObjectNode pathNode = pathNodes.get(tc);
-            if (pathNode == null) {
-                pathNode = objectNode()
-                        .put("class", tc).put("traffic", hasTraffic);
-                pathNode.set("links", arrayNode());
-                pathNode.set("labels", arrayNode());
-                pathNodes.put(tc, pathNode);
-                paths.add(pathNode);
-            }
-            ((ArrayNode) pathNode.path("links")).add(compactLinkString(biLink.one));
-            ((ArrayNode) pathNode.path("labels")).add(hasTraffic ? formatBytes(biLink.bytes) : "");
-        }
-
-        return JsonUtils.envelope(SHOW_HIGHLIGHTS, 0, payload);
-    }
-
-    // Classifies the link traffic according to the specified classes.
-    private Map<LinkKey, BiLink> classifyLinkTraffic(TrafficClass... trafficClasses) {
-        Map<LinkKey, BiLink> biLinks = new HashMap<>();
-        for (TrafficClass trafficClass : trafficClasses) {
-            for (Intent intent : trafficClass.intents) {
-                boolean isOptical = intent instanceof OpticalConnectivityIntent;
-                List<Intent> installables = intentService.getInstallableIntents(intent.key());
-                if (installables != null) {
-                    for (Intent installable : installables) {
-                        String type = isOptical ? trafficClass.type + " optical" : trafficClass.type;
-                        if (installable instanceof PathIntent) {
-                            classifyLinks(type, biLinks, trafficClass.showTraffic,
-                                          ((PathIntent) installable).path().links());
-                        } else if (installable instanceof FlowRuleIntent) {
-                            classifyLinks(type, biLinks, trafficClass.showTraffic,
-                                          linkResources(installable));
-                        } else if (installable instanceof LinkCollectionIntent) {
-                            classifyLinks(type, biLinks, trafficClass.showTraffic,
-                                          ((LinkCollectionIntent) installable).links());
-                        } else if (installable instanceof OpticalPathIntent) {
-                            classifyLinks(type, biLinks, trafficClass.showTraffic,
-                                          ((OpticalPathIntent) installable).path().links());
-                        }
-                    }
-                }
-            }
-        }
-        return biLinks;
-    }
-
-    // Extracts links from the specified flow rule intent resources
-    private Collection<Link> linkResources(Intent installable) {
-        ImmutableList.Builder<Link> builder = ImmutableList.builder();
-        for (NetworkResource r : installable.resources()) {
-            if (r instanceof Link) {
-                builder.add((Link) r);
-            }
-        }
-        return builder.build();
-    }
-
-
-    // Adds the link segments (path or tree) associated with the specified
-    // connectivity intent
-    private void classifyLinks(String type, Map<LinkKey, BiLink> biLinks,
-                               boolean showTraffic, Iterable<Link> links) {
-        if (links != null) {
-            for (Link link : links) {
-                BiLink biLink = addLink(biLinks, link);
-                if (showTraffic) {
-                    biLink.addLoad(getLinkLoad(link));
-                }
-                biLink.addClass(type);
-            }
-        }
-    }
-
-
-    static BiLink addLink(Map<LinkKey, BiLink> biLinks, Link link) {
-        LinkKey key = canonicalLinkKey(link);
-        BiLink biLink = biLinks.get(key);
-        if (biLink != null) {
-            biLink.setOther(link);
-        } else {
-            biLink = new BiLink(key, link);
-            biLinks.put(key, biLink);
-        }
-        return biLink;
-    }
-
-    // Poor-mans formatting to get the labels with byte counts looking nice.
-    private String formatBytes(long bytes) {
-        String unit;
-        double value;
-        if (bytes > GIGA) {
-            value = bytes / GIGA;
-            unit = GBYTES_UNIT;
-        } else if (bytes > MEGA) {
-            value = bytes / MEGA;
-            unit = MBYTES_UNIT;
-        } else if (bytes > KILO) {
-            value = bytes / KILO;
-            unit = KBYTES_UNIT;
-        } else {
-            value = bytes;
-            unit = BYTES_UNIT;
-        }
-        DecimalFormat format = new DecimalFormat("#,###.##");
-        return format.format(value) + " " + unit;
-    }
-
-    // Poor-mans formatting to get the labels with bit rate looking nice.
-    private String formatBitRate(long bytes) {
-        String unit;
-        double value;
-        //Convert to bits
-        long bits = bytes * 8;
-        if (bits > GIGA) {
-            value = bits / GIGA;
-            unit = GBITS_UNIT;
-
-            // NOTE: temporary hack to clip rate at 10.0 Gbps
-            //  Added for the CORD Fabric demo at ONS 2015
-            if (value > 10.0) {
-                value = 10.0;
+            if (ids == null) {  // labels will be null also
+                ids = new ArrayList<>();
+                linkIdMap.put(cls, ids);
+                labels = new ArrayList<>();
+                linkLabelMap.put(cls, labels);
             }
 
-        } else if (bits > MEGA) {
-            value = bits / MEGA;
-            unit = MBITS_UNIT;
-        } else if (bits > KILO) {
-            value = bits / KILO;
-            unit = KBITS_UNIT;
-        } else {
-            value = bits;
-            unit = BITS_UNIT;
+            ids.add(lh.elementId());
+            labels.add(lh.label());
         }
-        DecimalFormat format = new DecimalFormat("#,###.##");
-        return format.format(value) + " " + unit;
+
+        for (String cls : linkIdMap.keySet()) {
+            ObjectNode group = objectNode();
+            links.add(group);
+
+            group.put("class", cls);
+
+            ArrayNode lnks = arrayNode();
+            ArrayNode labs = arrayNode();
+            group.set("links", lnks);
+            group.set("labels", labs);
+
+            linkIdMap.get(cls).forEach(lnks::add);
+            linkLabelMap.get(cls).forEach(labs::add);
+        }
     }
 
-    // Produces compact string representation of a link.
-    private static String compactLinkString(Link link) {
-        return String.format(COMPACT, link.src().elementId(), link.src().port(),
-                             link.dst().elementId(), link.dst().port());
+
+    protected ObjectNode json(DeviceHighlight dh) {
+        // TODO: implement this once we know what a device highlight looks like
+        return objectNode();
+    }
+
+    protected ObjectNode json(HostHighlight hh) {
+        // TODO: implement this once we know what a host highlight looks like
+        return objectNode();
     }
 
     // translates the property panel into JSON, for returning to the client
@@ -879,95 +625,4 @@
         return result;
     }
 
-
-    // Produces canonical link key, i.e. one that will match link and its inverse.
-    static LinkKey canonicalLinkKey(Link link) {
-        String sn = link.src().elementId().toString();
-        String dn = link.dst().elementId().toString();
-        return sn.compareTo(dn) < 0 ?
-                linkKey(link.src(), link.dst()) : linkKey(link.dst(), link.src());
-    }
-
-    // Representation of link and its inverse and any traffic data.
-    static class BiLink {
-        public final LinkKey key;
-        public final Link one;
-        public Link two;
-        public boolean hasTraffic = false;
-        public long bytes = 0;
-
-        private Set<String> classes = new HashSet<>();
-        private long rate;
-
-        BiLink(LinkKey key, Link link) {
-            this.key = key;
-            this.one = link;
-        }
-
-        void setOther(Link link) {
-            this.two = link;
-        }
-
-        void addLoad(Load load) {
-            addLoad(load, 0);
-        }
-
-        void addLoad(Load load, double threshold) {
-            if (load != null) {
-                this.hasTraffic = hasTraffic || load.rate() > threshold;
-                this.bytes += load.latest();
-                this.rate += load.rate();
-            }
-        }
-
-        void addLoad(Load srcLinkLoad,
-                     double srcLinkThreshold,
-                     Load dstLinkLoad,
-                     double dstLinkThreshold) {
-            //use the max of link load at source or destination
-            if (srcLinkLoad != null) {
-                this.hasTraffic = hasTraffic || srcLinkLoad.rate() > srcLinkThreshold;
-                this.bytes = srcLinkLoad.latest();
-                this.rate = srcLinkLoad.rate();
-            }
-
-            if (dstLinkLoad != null) {
-                if (dstLinkLoad.rate() > this.rate) {
-                    this.bytes = dstLinkLoad.latest();
-                    this.rate = dstLinkLoad.rate();
-                    this.hasTraffic = hasTraffic || dstLinkLoad.rate() > dstLinkThreshold;
-                }
-            }
-        }
-
-        void addClass(String trafficClass) {
-            classes.add(trafficClass);
-        }
-
-        String classes() {
-            StringBuilder sb = new StringBuilder();
-            classes.forEach(c -> sb.append(c).append(" "));
-            return sb.toString().trim();
-        }
-    }
-
-
-    // TODO: move this to traffic overlay component
-    // Auxiliary carrier of data for requesting traffic message.
-    static class TrafficClass {
-        public final boolean showTraffic;
-        public final String type;
-        public final Iterable<Intent> intents;
-
-        TrafficClass(String type, Iterable<Intent> intents) {
-            this(type, intents, false);
-        }
-
-        TrafficClass(String type, Iterable<Intent> intents, boolean showTraffic) {
-            this.type = type;
-            this.intents = intents;
-            this.showTraffic = showTraffic;
-        }
-    }
-
 }