Remove set speed event

Allows the complete removal of a set speed event from the zone. This is
done when any precondition defined for the event to be active is not
met any longer.

Change-Id: Idbec357f76f0fd7db9107e8c9d3e00461872c528
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/control/preconditions.hpp b/control/preconditions.hpp
index 3bceb19..8b2e93e 100644
--- a/control/preconditions.hpp
+++ b/control/preconditions.hpp
@@ -64,7 +64,8 @@
         else
         {
             zone.setFullSpeed();
-            // TODO Unsubscribe the event signals when any precondition is false
+            // Unsubscribe the event signals when any precondition is false
+            zone.removeEvent(sse);
         }
     };
 }
diff --git a/control/types.hpp b/control/types.hpp
index d45226f..bac5402 100644
--- a/control/types.hpp
+++ b/control/types.hpp
@@ -2,6 +2,7 @@
 #include <string>
 #include <tuple>
 #include <vector>
+#include <sdbusplus/server.hpp>
 
 namespace phosphor
 {
@@ -67,6 +68,12 @@
 constexpr auto eventActionPos = 2;
 using EventData = std::tuple<Group, Handler, Action>;
 
+constexpr auto signalEventDataPos = 0;
+constexpr auto signalMatchPos = 1;
+using SignalEvent =
+    std::tuple<std::unique_ptr<EventData>,
+               std::unique_ptr<sdbusplus::server::match::match>>;
+
 constexpr auto zoneNumPos = 0;
 constexpr auto fullSpeedPos = 1;
 constexpr auto floorSpeedPos = 2;
diff --git a/control/zone.cpp b/control/zone.cpp
index 55aae9d..cef375c 100644
--- a/control/zone.cpp
+++ b/control/zone.cpp
@@ -196,27 +196,57 @@
     // Setup signal matches for property change events
     for (auto& prop : std::get<propChangeListPos>(event))
     {
-        _signalEvents.emplace_back(
-                std::make_unique<EventData>(
-                        EventData
-                        {
-                            std::get<groupPos>(event),
-                            std::get<handlerObjPos>(prop),
-                            std::get<actionPos>(event)
-                        }));
-        _matches.emplace_back(
+        std::unique_ptr<EventData> eventData =
+            std::make_unique<EventData>(
+                EventData
+                {
+                    std::get<groupPos>(event),
+                    std::get<handlerObjPos>(prop),
+                    std::get<actionPos>(event)
+                }
+            );
+        std::unique_ptr<sdbusplus::server::match::match> match =
+            std::make_unique<sdbusplus::server::match::match>(
                 _bus,
                 std::get<signaturePos>(prop).c_str(),
                 std::bind(std::mem_fn(&Zone::handleEvent),
                           this,
                           std::placeholders::_1,
-                          _signalEvents.back().get()));
+                          eventData.get())
+            );
+        _signalEvents.emplace_back(std::move(eventData), std::move(match));
     }
     // Run action function for initial event state
     std::get<actionPos>(event)(*this,
                                std::get<groupPos>(event));
 }
 
+void Zone::removeEvent(const SetSpeedEvent& event)
+{
+    // Find the signal event to be removed
+    auto it = std::find_if(
+        _signalEvents.begin(),
+        _signalEvents.end(),
+        [&event](auto const& se)
+        {
+            auto seEventData = *std::get<signalEventDataPos>(se);
+            // TODO Use the action function target for comparison
+            return
+            (
+                std::get<eventGroupPos>(seEventData) ==
+                    std::get<groupPos>(event) &&
+                std::get<eventActionPos>(seEventData).target_type().name() ==
+                    std::get<actionPos>(event).target_type().name()
+            );
+        });
+    if (it != std::end(_signalEvents))
+    {
+        std::get<signalEventDataPos>(*it).reset();
+        std::get<signalMatchPos>(*it).reset();
+        _signalEvents.erase(it);
+    }
+}
+
 void Zone::refreshProperty(sdbusplus::bus::bus& bus,
                            const std::string& path,
                            const std::string& iface,
diff --git a/control/zone.hpp b/control/zone.hpp
index f618c10..32707cb 100644
--- a/control/zone.hpp
+++ b/control/zone.hpp
@@ -3,7 +3,6 @@
 #include <vector>
 #include <algorithm>
 #include <sdbusplus/bus.hpp>
-#include <sdbusplus/server.hpp>
 #include "fan.hpp"
 #include "types.hpp"
 #include "timer.hpp"
@@ -142,6 +141,13 @@
         void initEvent(const SetSpeedEvent& event);
 
         /**
+         * @brief Removes all the set speed event properties and actions
+         *
+         * @param[in] event - Set speed event
+         */
+        void removeEvent(const SetSpeedEvent& event);
+
+        /**
          * @brief Get the default floor speed
          *
          * @return - The defined default floor speed
@@ -342,14 +348,9 @@
         std::map<const Group*, bool> _active;
 
         /**
-         * @brief List of signal event arguments
+         * @brief List of signal event arguments and Dbus matches for callbacks
          */
-        std::vector<std::unique_ptr<EventData>> _signalEvents;
-
-        /**
-         * @brief list of Dbus matches for callbacks
-         */
-        std::vector<sdbusplus::server::match::match> _matches;
+        std::vector<SignalEvent> _signalEvents;
 
         /**
          * @brief Refresh the given property's cached value