ONOS-5894 GUI refactoring of faultmanagement app

Change-Id: I8be596dac8821609f1f4292bc79bc903460009a4
diff --git a/apps/faultmanagement/fmgui/src/main/java/org/onosproject/faultmanagement/alarms/gui/AlarmMonitor.java b/apps/faultmanagement/fmgui/src/main/java/org/onosproject/faultmanagement/alarms/gui/AlarmMonitor.java
new file mode 100644
index 0000000..d65149d
--- /dev/null
+++ b/apps/faultmanagement/fmgui/src/main/java/org/onosproject/faultmanagement/alarms/gui/AlarmMonitor.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2017-present 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.faultmanagement.alarms.gui;
+
+import org.onosproject.incubator.net.faultmanagement.alarm.AlarmEvent;
+import org.onosproject.incubator.net.faultmanagement.alarm.AlarmListener;
+
+/**
+ * Encapsulates the behavior of monitoring when new alarms are stored.
+ */
+public class AlarmMonitor {
+
+    private final AlarmTopovMessageHandler messageHandler;
+    private final AlarmListener alarmListener = new TopoAlarmListener();
+    private volatile boolean isMonitoring;
+
+
+    /**
+     * Constructs a traffic monitor.
+     *
+     * @param msgHandler the alarm message handler
+     */
+    public AlarmMonitor(AlarmTopovMessageHandler msgHandler) {
+        messageHandler = msgHandler;
+        messageHandler.alarmService.addListener(alarmListener);
+    }
+
+    /**
+     * Activates updating the alarms onf the GUI client.
+     */
+    protected void startMonitorig() {
+        isMonitoring = true;
+    }
+
+    /**
+     * De-activates updating the alarms onf the GUI client.
+     */
+    protected void stopMonitoring() {
+        isMonitoring = false;
+    }
+
+    //internal alarm listener
+    private class TopoAlarmListener implements AlarmListener {
+
+        @Override
+        public void event(AlarmEvent event) {
+            if (isMonitoring) {
+                messageHandler.sendAlarmHighlights();
+            }
+        }
+    }
+}
diff --git a/apps/faultmanagement/fmgui/src/main/java/org/onosproject/faultmanagement/alarms/gui/AlarmTopovMessageHandler.java b/apps/faultmanagement/fmgui/src/main/java/org/onosproject/faultmanagement/alarms/gui/AlarmTopovMessageHandler.java
index 10ebad9..9a8184c 100644
--- a/apps/faultmanagement/fmgui/src/main/java/org/onosproject/faultmanagement/alarms/gui/AlarmTopovMessageHandler.java
+++ b/apps/faultmanagement/fmgui/src/main/java/org/onosproject/faultmanagement/alarms/gui/AlarmTopovMessageHandler.java
@@ -16,17 +16,12 @@
 package org.onosproject.faultmanagement.alarms.gui;
 
 import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableSet;
 import org.onlab.osgi.ServiceDirectory;
 import org.onosproject.incubator.net.faultmanagement.alarm.Alarm;
 import org.onosproject.incubator.net.faultmanagement.alarm.AlarmService;
-import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
-import org.onosproject.net.Element;
-import org.onosproject.net.HostId;
 import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.host.HostService;
 import org.onosproject.ui.RequestHandler;
 import org.onosproject.ui.UiConnection;
 import org.onosproject.ui.UiMessageHandler;
@@ -47,39 +42,29 @@
 public class AlarmTopovMessageHandler extends UiMessageHandler {
 
     private static final String ALARM_TOPOV_DISPLAY_START = "alarmTopovDisplayStart";
-    private static final String ALARM_TOPOV_DISPLAY_UPDATE = "alarmTopovDisplayUpdate";
     private static final String ALARM_TOPOV_DISPLAY_STOP = "alarmTopovDisplayStop";
+    private static final int DELAY_MS = 500;
 
-    private static final String ID = "id";
-    private static final String MODE = "mode";
-
-    private enum Mode {
-        IDLE, MOUSE
-    }
 
     private final Logger log = LoggerFactory.getLogger(getClass());
 
+    protected AlarmService alarmService;
     private DeviceService deviceService;
-    private HostService hostService;
-    private AlarmService alarmService;
-
-    private Mode currentMode = Mode.IDLE;
-    private Element elementOfNote;
+    private AlarmMonitor alarmMonitor;
 
     // =======================================================================
     @Override
     public void init(UiConnection connection, ServiceDirectory directory) {
         super.init(connection, directory);
         deviceService = directory.get(DeviceService.class);
-        hostService = directory.get(HostService.class);
         alarmService = directory.get(AlarmService.class);
+        alarmMonitor = new AlarmMonitor(this);
     }
 
     @Override
     protected Collection<RequestHandler> createRequestHandlers() {
         return ImmutableSet.of(
                 new DisplayStartHandler(),
-                new DisplayUpdateHandler(),
                 new DisplayStopHandler()
         );
     }
@@ -94,41 +79,9 @@
 
         @Override
         public void process(ObjectNode payload) {
-            String mode = string(payload, MODE);
-            log.debug("Start Display: mode [{}]", mode);
-
-            clearState();
-            clearForMode();
-
-            switch (mode) {
-                case "mouse":
-                    currentMode = Mode.MOUSE;
-                    sendMouseData();
-                    break;
-
-                default:
-                    currentMode = Mode.IDLE;
-                    break;
-            }
-        }
-    }
-
-    private final class DisplayUpdateHandler extends RequestHandler {
-
-        public DisplayUpdateHandler() {
-            super(ALARM_TOPOV_DISPLAY_UPDATE);
-        }
-
-        @Override
-        public void process(ObjectNode payload) {
-            String id = string(payload, ID);
-            log.debug("Update Display: id [{}]", id);
-
-            if (!Strings.isNullOrEmpty(id)) {
-                updateForMode(id);
-            } else {
-                clearForMode();
-            }
+            log.debug("Start Display");
+            sendDelayedAlarmHighlights();
+            alarmMonitor.startMonitorig();
         }
     }
 
@@ -141,72 +94,54 @@
         @Override
         public void process(ObjectNode payload) {
             log.debug("Stop Display");
-
-            clearState();
-            clearForMode();
+            alarmMonitor.stopMonitoring();
+            clearHighlights();
         }
     }
 
-    // === ------------
-    private void clearState() {
-        currentMode = Mode.IDLE;
-        elementOfNote = null;
+    /**
+     * Sends the highlights with a delay to the client side on the browser.
+     */
+    protected void sendDelayedAlarmHighlights() {
+        createAndSendHighlights(true);
     }
 
-    private void updateForMode(String id) {
-        log.debug("host service: {}", hostService);
-        log.debug("device service: {}", deviceService);
-
-        try {
-            HostId hid = HostId.hostId(id);
-            log.debug("host id {}", hid);
-            elementOfNote = hostService.getHost(hid);
-            log.debug("host element {}", elementOfNote);
-
-        } catch (RuntimeException e) {
-            try {
-                DeviceId did = DeviceId.deviceId(id);
-                log.debug("device id {}", did);
-                elementOfNote = deviceService.getDevice(did);
-                log.debug("device element {}", elementOfNote);
-
-            } catch (RuntimeException e2) {
-                log.debug("Unable to process ID [{}]", id);
-                elementOfNote = null;
-            }
-        }
-
-        switch (currentMode) {
-            case MOUSE:
-                sendMouseData();
-                break;
-
-            default:
-                break;
-        }
-
+    /**
+     * Sends the highlights to the client side on the browser.
+     */
+    protected void sendAlarmHighlights() {
+        createAndSendHighlights(false);
     }
 
-    private void clearForMode() {
-        sendHighlights(new Highlights());
+    private void createAndSendHighlights(boolean toDelay) {
+        Highlights highlights = new Highlights();
+        createBadges(highlights);
+        if (toDelay) {
+            highlights.delay(DELAY_MS);
+        }
+        sendHighlights(highlights);
     }
 
     private void sendHighlights(Highlights highlights) {
         sendMessage(TopoJson.highlightsMessage(highlights));
     }
 
-    private void sendMouseData() {
-        if (elementOfNote != null && elementOfNote instanceof Device) {
-            DeviceId devId = (DeviceId) elementOfNote.id();
-            Set<Alarm> alarmsOnDevice = alarmService.getAlarms(devId);
-            Highlights highlights = new Highlights();
-
-            addDeviceBadge(highlights, devId, alarmsOnDevice.size());
-            sendHighlights(highlights);
-        }
-        // Note: could also process Host, if available
+    private void createBadges(Highlights highlights) {
+        deviceService.getAvailableDevices().forEach(d -> {
+            Set<Alarm> alarmsOnDevice = alarmService.getAlarms(d.id());
+            int alarmSize = alarmsOnDevice.size();
+            log.debug("{} Alarms on device {}", alarmSize, d.id());
+            if (alarmSize > 0) {
+                addDeviceBadge(highlights, d.id(), alarmSize);
+            }
+        });
     }
 
+    private void clearHighlights() {
+        sendHighlights(new Highlights());
+    }
+
+
     private void addDeviceBadge(Highlights h, DeviceId devId, int n) {
         DeviceHighlight dh = new DeviceHighlight(devId.toString());
         dh.setBadge(createBadge(n));
diff --git a/apps/faultmanagement/fmgui/src/main/resources/app/view/alarmTopov/alarmTopovDemo.js b/apps/faultmanagement/fmgui/src/main/resources/app/view/alarmTopov/alarmTopovDemo.js
index 46a4d11..23d41df 100644
--- a/apps/faultmanagement/fmgui/src/main/resources/app/view/alarmTopov/alarmTopovDemo.js
+++ b/apps/faultmanagement/fmgui/src/main/resources/app/view/alarmTopov/alarmTopovDemo.js
@@ -27,26 +27,14 @@
 
     // constants
     var displayStart = 'alarmTopovDisplayStart',
-        displayUpdate = 'alarmTopovDisplayUpdate',
         displayStop = 'alarmTopovDisplayStop';
 
-    // internal state
-    var currentMode = null;
-
 
     // === ---------------------------
     // === Helper functions
 
-    function sendDisplayStart(mode) {
-        wss.sendEvent(displayStart, {
-            mode: mode
-        });
-    }
-
-    function sendDisplayUpdate(what) {
-        wss.sendEvent(displayUpdate, {
-            id: what ? what.id : ''
-        });
+    function sendDisplayStart() {
+        wss.sendEvent(displayStart);
     }
 
     function sendDisplayStop() {
@@ -56,30 +44,15 @@
     // === ---------------------------
     // === Main API functions
 
-    function startDisplay(mode) {
-        if (currentMode === mode) {
-            $log.debug('(in mode', mode, 'already)');
-        } else {
-            currentMode = mode;
-            sendDisplayStart(mode);
-            flash.flash('Starting display mode: ' + mode);
-        }
-    }
-
-    function updateDisplay(m) {
-        if (currentMode) {
-            sendDisplayUpdate(m);
-        }
+    function startDisplay() {
+        sendDisplayStart();
+        flash.flash('Showing alarm counts on devices');
     }
 
     function stopDisplay() {
-        if (currentMode) {
-            currentMode = null;
-            sendDisplayStop();
-            flash.flash('Canceling display mode');
-            return true;
-        }
-        return false;
+        sendDisplayStop();
+        flash.flash('Canceling alarm counts on devices');
+        return true;
     }
 
     // === ---------------------------
@@ -97,7 +70,6 @@
 
             return {
                 startDisplay: startDisplay,
-                updateDisplay: updateDisplay,
                 stopDisplay: stopDisplay
             };
         }]);
diff --git a/apps/faultmanagement/fmgui/src/main/resources/app/view/alarmTopov/alarmTopovOverlay.js b/apps/faultmanagement/fmgui/src/main/resources/app/view/alarmTopov/alarmTopovOverlay.js
index bf389db..a63f476 100644
--- a/apps/faultmanagement/fmgui/src/main/resources/app/view/alarmTopov/alarmTopovOverlay.js
+++ b/apps/faultmanagement/fmgui/src/main/resources/app/view/alarmTopov/alarmTopovOverlay.js
@@ -85,6 +85,7 @@
         },
         activate: function () {
             $log.debug("Alarm topology overlay ACTIVATED");
+            atds.startDisplay();
         },
         deactivate: function () {
             atds.stopDisplay();
@@ -99,37 +100,8 @@
                     $log.debug('Show alarms for selected device. data:', data);
                     ns.navTo("alarmTable", {devId: data.id});
                 }
-            },
-            alarm2button: {
-                gid: '*clocks',
-                tt: 'Show alarms for all devices',
-                cb: function (data) {
-                    $log.debug('Show alarms for all devices. data:', data);
-                    ns.navTo("alarmTable");
-                }
             }
         },
-        // Key bindings for traffic overlay buttons
-        // NOTE: fully qual. button ID is derived from overlay-id and key-name
-        keyBindings: {
-            0: {
-                cb: function () {
-                    atds.stopDisplay();
-                },
-                tt: 'Cancel Alarm Count on Device',
-                gid: 'xMark'
-            },
-            V: {
-                cb: function () {
-                    atds.startDisplay('mouse');
-                },
-                tt: 'Start Alarm Count on Device',
-                gid: '*clock'
-            },
-            _keyOrder: [
-                '0', 'V'
-            ]
-        },
         hooks: {
             // hook for handling escape key
             // Must return true to consume ESC, false otherwise.
@@ -147,16 +119,6 @@
             multi: function (selectOrder) {
                 selectionCallback('multi', selectOrder);
                 tov.addDetailButton('alarm1button');
-                tov.addDetailButton('alarm2button');
-            },
-            mouseover: function (m) {
-                // m has id, class, and type properties
-                $log.debug('mouseover:', m);
-                atds.updateDisplay(m);
-            },
-            mouseout: function () {
-                $log.debug('mouseout');
-                atds.updateDisplay();
             }
         }
     };