Action that creates/starts a timer

Another action is provided to the timer and is performed when the timer
expires.

Change-Id: Ie6a06b0d56272a158d74bf03287183f07f00aed8
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/control/actions.cpp b/control/actions.cpp
index a608293..b1eb9be 100644
--- a/control/actions.cpp
+++ b/control/actions.cpp
@@ -11,6 +11,76 @@
 
 using namespace phosphor::fan;
 
+Action call_actions_based_on_timer(Timer&& tConf, std::vector<Action>&& actions)
+{
+    return [tConf = std::move(tConf),
+            actions = std::move(actions)](control::Zone& zone,
+                                          const Group& group)
+    {
+        try
+        {
+            // Find any services that do not have an owner
+            auto services = zone.getGroupServices(&group);
+            auto setTimer = std::any_of(
+                services.begin(),
+                services.end(),
+                [](const auto& s)
+                {
+                    return !std::get<hasOwnerPos>(s);
+                });
+            if (setTimer &&
+                zone.findTimer(group, actions) ==
+                    std::end(zone.getTimerEvents()))
+            {
+                // Associate event data with timer
+                std::unique_ptr<EventData> eventData =
+                    std::make_unique<EventData>(
+                            EventData
+                            {
+                                group,
+                                "",
+                                nullptr,
+                                actions
+                            }
+                    );
+                // Create/start timer and associate event data with it
+                std::unique_ptr<util::Timer> timer =
+                    std::make_unique<util::Timer>(
+                            zone.getEventPtr(),
+                            [&zone,
+                            actions = &actions,
+                            group = &group]()
+                            {
+                                zone.timerExpired(*group, *actions);
+                            });
+                if (!timer->running())
+                {
+                    timer->start(std::get<intervalPos>(tConf),
+                                 std::get<typePos>(tConf));
+                }
+                zone.addTimer(std::move(eventData), std::move(timer));
+            }
+            else
+            {
+                // Stop and remove any timers for this group
+                auto timer = zone.findTimer(group, actions);
+                if (timer != std::end(zone.getTimerEvents()))
+                {
+                    if (std::get<timerTimerPos>(*timer)->running())
+                    {
+                        std::get<timerTimerPos>(*timer)->stop();
+                    }
+                    zone.removeTimer(timer);
+                }
+            }
+        }
+        catch (const std::out_of_range& oore)
+        {
+            // Group not found, no timers set
+        }
+    };
+}
+
 void set_request_speed_base_with_max(control::Zone& zone,
                                      const Group& group)
 {
diff --git a/control/actions.hpp b/control/actions.hpp
index 3061814..fff8250 100644
--- a/control/actions.hpp
+++ b/control/actions.hpp
@@ -15,6 +15,21 @@
 {
 
 /**
+ * @brief An action that wraps a list of actions with a timer
+ * @details Sets up a list of actions to be invoked when the defined timer
+ * expires (or for each expiration of a repeating timer).
+ *
+ * @param[in] tConf - Timer configuration parameters
+ * @param[in] action - List of actions to be called when the timer expires
+ *
+ * @return Action lambda function
+ *     An Action function that creates a timer
+ */
+Action call_actions_based_on_timer(
+        Timer&& tConf,
+        std::vector<Action>&& actions);
+
+/**
  * @brief An action to set the request speed base
  * @details A new target speed is determined using a speed delta being added
  * or subtracted, for increases or decrease respectively, from a base speed.