ONOS-2186 - GUI Topo Overlay - (WIP)
- Cleaned up intent highlighting in TrafficMonitor (deleted deprecated TrafficClass).
- update traffic ESC handler to force cancel traffic.

Change-Id: I9cab752152718c367ff0cbf4dcacc1dff299164b
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/TrafficMonitor.java b/web/gui/src/main/java/org/onosproject/ui/impl/TrafficMonitor.java
index 31f07f8..2dc8e44 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/TrafficMonitor.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/TrafficMonitor.java
@@ -37,10 +37,11 @@
 import org.onosproject.ui.impl.topo.IntentSelection;
 import org.onosproject.ui.impl.topo.ServicesBundle;
 import org.onosproject.ui.impl.topo.TopoIntentFilter;
-import org.onosproject.ui.impl.topo.TrafficClass;
 import org.onosproject.ui.impl.topo.TrafficLink;
+import org.onosproject.ui.impl.topo.TrafficLink.StatsType;
 import org.onosproject.ui.impl.topo.TrafficLinkMap;
 import org.onosproject.ui.topo.Highlights;
+import org.onosproject.ui.topo.LinkHighlight.Flavor;
 import org.onosproject.ui.topo.NodeSelection;
 import org.onosproject.ui.topo.TopoUtils;
 import org.slf4j.Logger;
@@ -59,9 +60,8 @@
 
 import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
 import static org.onosproject.ui.impl.TrafficMonitor.Mode.IDLE;
+import static org.onosproject.ui.impl.TrafficMonitor.Mode.RELATED_INTENTS;
 import static org.onosproject.ui.impl.TrafficMonitor.Mode.SELECTED_INTENT;
-import static org.onosproject.ui.topo.LinkHighlight.Flavor.PRIMARY_HIGHLIGHT;
-import static org.onosproject.ui.topo.LinkHighlight.Flavor.SECONDARY_HIGHLIGHT;
 
 /**
  * Encapsulates the behavior of monitoring specific traffic patterns.
@@ -239,6 +239,9 @@
         if (selectedIntents != null) {
             selectedIntents.next();
             sendSelectedIntents();
+            if (mode == SELECTED_INTENT) {
+                mode = RELATED_INTENTS;
+            }
         }
     }
 
@@ -251,6 +254,9 @@
         if (selectedIntents != null) {
             selectedIntents.prev();
             sendSelectedIntents();
+            if (mode == SELECTED_INTENT) {
+                mode = RELATED_INTENTS;
+            }
         }
     }
 
@@ -300,7 +306,6 @@
             trafficTask = new TrafficUpdateTask();
             timer.schedule(trafficTask, trafficPeriod, trafficPeriod);
         } else {
-            // TEMPORARY until we are sure this is working correctly
             log.debug("(traffic task already running)");
         }
     }
@@ -314,12 +319,12 @@
 
     private void sendAllFlowTraffic() {
         log.debug("sendAllFlowTraffic");
-        msgHandler.sendHighlights(trafficSummary(TrafficLink.StatsType.FLOW_STATS));
+        msgHandler.sendHighlights(trafficSummary(StatsType.FLOW_STATS));
     }
 
     private void sendAllPortTraffic() {
         log.debug("sendAllPortTraffic");
-        msgHandler.sendHighlights(trafficSummary(TrafficLink.StatsType.PORT_STATS));
+        msgHandler.sendHighlights(trafficSummary(StatsType.PORT_STATS));
     }
 
     private void sendDeviceLinkFlows() {
@@ -345,7 +350,7 @@
     // =======================================================================
     // === Generate messages in JSON object node format
 
-    private Highlights trafficSummary(TrafficLink.StatsType type) {
+    private Highlights trafficSummary(StatsType type) {
         Highlights highlights = new Highlights();
 
         TrafficLinkMap linkMap = new TrafficLinkMap();
@@ -353,9 +358,9 @@
         addEdgeLinks(linkMap);
 
         for (TrafficLink tlink : linkMap.biLinks()) {
-            if (type == TrafficLink.StatsType.FLOW_STATS) {
+            if (type == StatsType.FLOW_STATS) {
                 attachFlowLoad(tlink);
-            } else if (type == TrafficLink.StatsType.PORT_STATS) {
+            } else if (type == StatsType.PORT_STATS) {
                 attachPortLoad(tlink);
             }
 
@@ -385,7 +390,7 @@
 
             // now report on our collated links
             for (TrafficLink tlink : linkMap.biLinks()) {
-                highlights.add(tlink.highlight(TrafficLink.StatsType.FLOW_COUNT));
+                highlights.add(tlink.highlight(StatsType.FLOW_COUNT));
             }
 
         }
@@ -420,10 +425,8 @@
                 log.debug("Highlight intent: {} ([{}] of {})",
                           current.id(), selectedIntents.index(), count);
             }
-            TrafficClass tc1 = new TrafficClass(PRIMARY_HIGHLIGHT, primary);
-            TrafficClass tc2 = new TrafficClass(SECONDARY_HIGHLIGHT, secondary);
-            // classify primary links after secondary (last man wins)
-            highlightIntents(highlights, tc2, tc1);
+
+            highlightIntentLinks(highlights, primary, secondary);
         }
         return highlights;
     }
@@ -437,8 +440,8 @@
             primary.add(current);
             log.debug("Highlight traffic for intent: {} ([{}] of {})",
                       current.id(), selectedIntents.index(), selectedIntents.size());
-            TrafficClass tc1 = new TrafficClass(PRIMARY_HIGHLIGHT, primary, true);
-            highlightIntents(highlights, tc1);
+
+            highlightIntentLinksWithTraffic(highlights, primary);
         }
         return highlights;
     }
@@ -532,27 +535,29 @@
         return count;
     }
 
-    private void highlightIntents(Highlights highlights,
-                                  TrafficClass... trafficClasses) {
+    private void highlightIntentLinks(Highlights highlights,
+                                      Set<Intent> primary, Set<Intent> secondary) {
         TrafficLinkMap linkMap = new TrafficLinkMap();
-
-        for (TrafficClass trafficClass : trafficClasses) {
-            classifyLinkTraffic(linkMap, trafficClass);
-        }
-
-        for (TrafficLink tlink : linkMap.biLinks()) {
-            highlights.add(tlink.highlight(TrafficLink.StatsType.TAGGED));
-        }
+        // NOTE: highlight secondary first, then primary, so that links shared
+        //       by intents are colored correctly ("last man wins")
+        createTrafficLinks(linkMap, secondary, Flavor.SECONDARY_HIGHLIGHT, false);
+        createTrafficLinks(linkMap, primary, Flavor.PRIMARY_HIGHLIGHT, false);
+        colorLinks(highlights, linkMap);
     }
 
-    private void classifyLinkTraffic(TrafficLinkMap linkMap,
-                                     TrafficClass trafficClass) {
-        for (Intent intent : trafficClass.intents()) {
-            boolean isOptical = intent instanceof OpticalConnectivityIntent;
+    private void highlightIntentLinksWithTraffic(Highlights highlights,
+                                                 Set<Intent> primary) {
+        TrafficLinkMap linkMap = new TrafficLinkMap();
+        createTrafficLinks(linkMap, primary, Flavor.PRIMARY_HIGHLIGHT, true);
+        colorLinks(highlights, linkMap);
+    }
+
+    private void createTrafficLinks(TrafficLinkMap linkMap, Set<Intent> intents,
+                                    Flavor flavor, boolean showTraffic) {
+        for (Intent intent : intents) {
             List<Intent> installables = servicesBundle.intentService()
                     .getInstallableIntents(intent.key());
             Iterable<Link> links = null;
-
             if (installables != null) {
                 for (Intent installable : installables) {
 
@@ -566,28 +571,13 @@
                         links = ((OpticalPathIntent) installable).path().links();
                     }
 
-                    classifyLinks(trafficClass, isOptical, linkMap, links);
+                    boolean isOptical = intent instanceof OpticalConnectivityIntent;
+                    processLinks(linkMap, links, flavor, isOptical, showTraffic);
                 }
             }
         }
     }
 
-    private void classifyLinks(TrafficClass trafficClass, boolean isOptical,
-                               TrafficLinkMap linkMap,
-                               Iterable<Link> links) {
-        if (links != null) {
-            for (Link link : links) {
-                TrafficLink tlink = linkMap.add(link);
-                if (trafficClass.showTraffic()) {
-                    tlink.addLoad(getLinkFlowLoad(link));
-                    tlink.antMarch(true);
-                }
-                tlink.optical(isOptical);
-                tlink.tagFlavor(trafficClass.flavor());
-            }
-        }
-    }
-
     // Extracts links from the specified flow rule intent resources
     private Collection<Link> linkResources(Intent installable) {
         ImmutableList.Builder<Link> builder = ImmutableList.builder();
@@ -596,6 +586,28 @@
         return builder.build();
     }
 
+    private void processLinks(TrafficLinkMap linkMap, Iterable<Link> links,
+                              Flavor flavor, boolean isOptical,
+                              boolean showTraffic) {
+        if (links != null) {
+            for (Link link : links) {
+                TrafficLink tlink = linkMap.add(link);
+                tlink.tagFlavor(flavor);
+                tlink.optical(isOptical);
+                if (showTraffic) {
+                    tlink.addLoad(getLinkFlowLoad(link));
+                    tlink.antMarch(true);
+                }
+            }
+        }
+    }
+
+    private void colorLinks(Highlights highlights, TrafficLinkMap linkMap) {
+        for (TrafficLink tlink : linkMap.biLinks()) {
+            highlights.add(tlink.highlight(StatsType.TAGGED));
+        }
+    }
+
     // =======================================================================
     // === Background Task
 
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/TrafficClass.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/TrafficClass.java
deleted file mode 100644
index 0fa1581..0000000
--- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/TrafficClass.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.impl.topo;
-
-import org.onosproject.net.intent.Intent;
-import org.onosproject.ui.topo.LinkHighlight;
-
-/**
- * Auxiliary data carrier for assigning a highlight class to a set of
- * intents, for visualization in the topology view.
- */
-@Deprecated
-public class TrafficClass {
-
-    private final LinkHighlight.Flavor flavor;
-    private final Iterable<Intent> intents;
-    private final boolean showTraffic;
-
-    public TrafficClass(LinkHighlight.Flavor flavor, Iterable<Intent> intents) {
-        this(flavor, intents, false);
-    }
-
-    public TrafficClass(LinkHighlight.Flavor flavor, Iterable<Intent> intents,
-                        boolean showTraffic) {
-        this.flavor = flavor;
-        this.intents = intents;
-        this.showTraffic = showTraffic;
-    }
-
-    public LinkHighlight.Flavor flavor() {
-        return flavor;
-    }
-
-    public Iterable<Intent> intents() {
-        return intents;
-    }
-
-    public boolean showTraffic() {
-        return showTraffic;
-    }
-}
diff --git a/web/gui/src/main/webapp/app/view/topo/topoTrafficNew.js b/web/gui/src/main/webapp/app/view/topo/topoTrafficNew.js
index ea5e24a..cb4bc49 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoTrafficNew.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoTrafficNew.js
@@ -119,7 +119,7 @@
             // hook for handling escape key
             escape: function () {
                 // Must return true to consume ESC, false otherwise.
-                return tts.cancelTraffic();
+                return tts.cancelTraffic(true);
             },
 
             // hooks for when the selection changes...