Add timer event management

Events defined to have timers require the ability to find a timer, add a
timer to the event, and removing a timer event entirely. These event
timers are intended to allow actions based on the event to be delayed or
recurring based on the timer defined.

Change-Id: Ieaf26f031c5e5aac9472e92354bfb76392642cb4
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/control/types.hpp b/control/types.hpp
index 0d7610c..b0b84f3 100644
--- a/control/types.hpp
+++ b/control/types.hpp
@@ -81,8 +81,11 @@
 constexpr auto eventActionsPos = 3;
 using EventData = std::tuple<Group, std::string, Handler, std::vector<Action>>;
 
-constexpr auto timerTimerPos = 0;
-using TimerEvent = std::tuple<phosphor::fan::util::Timer>;
+constexpr auto timerEventDataPos = 0;
+constexpr auto timerTimerPos = 1;
+using TimerEvent =
+    std::tuple<std::unique_ptr<EventData>,
+               std::unique_ptr<phosphor::fan::util::Timer>>;
 
 constexpr auto signalEventDataPos = 0;
 constexpr auto signalMatchPos = 1;
diff --git a/control/zone.cpp b/control/zone.cpp
index b698c12..018f594 100644
--- a/control/zone.cpp
+++ b/control/zone.cpp
@@ -259,6 +259,17 @@
     auto eventTimer = std::get<timerPos>(event);
     if (std::get<intervalPos>(eventTimer) != seconds(0))
     {
+        // Associate event data with timer
+        std::unique_ptr<EventData> eventData =
+            std::make_unique<EventData>(
+                    EventData
+                    {
+                        std::get<groupPos>(event),
+                        "",
+                        nullptr,
+                        std::get<actionsPos>(event)
+                    }
+            );
         std::unique_ptr<util::Timer> timer =
             std::make_unique<util::Timer>(
                 _sdEvents,
@@ -273,7 +284,7 @@
             timer->start(std::get<intervalPos>(eventTimer),
                          std::get<typePos>(eventTimer));
         }
-        _timerEvents.emplace_back(std::move(timer));
+        addTimer(std::move(eventData), std::move(timer));
     }
     // Run action functions for initial event state
     std::for_each(
@@ -332,6 +343,38 @@
     }
 }
 
+std::vector<TimerEvent>::iterator Zone::findTimer(
+        const Group& eventGroup,
+        const std::vector<Action>& eventActions)
+{
+    for (auto it = _timerEvents.begin(); it != _timerEvents.end(); ++it)
+    {
+        auto teEventData = *std::get<timerEventDataPos>(*it);
+        if (std::get<eventActionsPos>(teEventData).size() ==
+            eventActions.size())
+        {
+            // TODO openbmc/openbmc#2328 - Use the action function target
+            // for comparison
+            auto actsEqual = [](auto const& a1,
+                                auto const& a2)
+                    {
+                        return a1.target_type().name() ==
+                               a2.target_type().name();
+                    };
+            if (std::get<eventGroupPos>(teEventData) == eventGroup &&
+                std::equal(eventActions.begin(),
+                           eventActions.end(),
+                           std::get<eventActionsPos>(teEventData).begin(),
+                           actsEqual))
+            {
+                return it;
+            }
+        }
+    }
+
+    return _timerEvents.end();
+}
+
 void Zone::timerExpired(Group eventGroup, std::vector<Action> eventActions)
 {
     // Perform the actions
diff --git a/control/zone.hpp b/control/zone.hpp
index 9c08032..1fdeaf2 100644
--- a/control/zone.hpp
+++ b/control/zone.hpp
@@ -1,6 +1,7 @@
 #pragma once
 #include <chrono>
 #include <vector>
+#include <cassert>
 #include <algorithm>
 #include <sdbusplus/bus.hpp>
 #include "fan.hpp"
@@ -139,6 +140,18 @@
                              const bool hasOwner);
 
         /**
+         * @brief Get the group's list of service names
+         *
+         * @param[in] group - Group to get service names for
+         *
+         * @return - The list of service names
+         */
+        inline auto getGroupServices(const Group* group)
+        {
+            return _services.at(*group);
+        }
+
+        /**
          * @brief Initialize a set speed event properties and actions
          *
          * @param[in] event - Set speed event
@@ -264,6 +277,64 @@
         void decTimerExpired();
 
         /**
+         * @brief Get the event pointer used with this zone's timers
+         *
+         * @return - The Dbus event pointer for timers
+         */
+        inline auto& getEventPtr()
+        {
+            return _sdEvents;
+        }
+
+        /**
+         * @brief Get the list of timer events
+         *
+         * @return - List of timer events
+         */
+        inline auto& getTimerEvents()
+        {
+            return _timerEvents;
+        }
+
+        /**
+         * @brief Find the first instance of a timer event
+         *
+         * @param[in] eventGroup - Group associated with a timer
+         * @param[in] eventActions - List of actions associated with a timer
+         *
+         * @return - Iterator to the timer event
+         */
+        std::vector<TimerEvent>::iterator findTimer(
+                const Group& eventGroup,
+                const std::vector<Action>& eventActions);
+
+        /**
+         * @brief Add a timer to the list of timer based events
+         *
+         * @param[in] data - Event data for timer
+         * @param[in] timer - Timer to be added
+         */
+        inline void addTimer(
+                std::unique_ptr<EventData>&& data,
+                std::unique_ptr<phosphor::fan::util::Timer>&& timer)
+        {
+            _timerEvents.emplace_back(std::move(data), std::move(timer));
+        };
+
+        /**
+         * @brief Remove the given timer event
+         *
+         * @param[in] teIter - Iterator pointing to the timer event to remove
+         */
+        inline void removeTimer(std::vector<TimerEvent>::iterator& teIter)
+        {
+            assert(teIter != std::end(_timerEvents));
+            std::get<timerEventDataPos>(*teIter).reset();
+            std::get<timerTimerPos>(*teIter).reset();
+            _timerEvents.erase(teIter);
+        }
+
+        /**
          * @brief Callback function for event timers that processes the given
          * actions for a group
          *
@@ -395,7 +466,7 @@
         /**
          * @brief List of timers for events
          */
-        std::vector<std::unique_ptr<phosphor::fan::util::Timer>> _timerEvents;
+        std::vector<TimerEvent> _timerEvents;
 
         /**
          * @brief Get the request speed base if defined, otherwise the