Restructure preconditions layout

Preparation for creating an additional precondition and splitting the
precondition check portion from the init/removal of events.

Change-Id: Iaff1f6637fe094c229558649329c1f01aba96ba6
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/control/preconditions.cpp b/control/preconditions.cpp
new file mode 100644
index 0000000..b2bd420
--- /dev/null
+++ b/control/preconditions.cpp
@@ -0,0 +1,81 @@
+#include <algorithm>
+#include <phosphor-logging/log.hpp>
+#include "preconditions.hpp"
+#include "zone.hpp"
+
+namespace phosphor
+{
+namespace fan
+{
+namespace control
+{
+namespace precondition
+{
+
+using namespace phosphor::fan;
+
+Action property_states_match(std::vector<PrecondGroup>&& pg,
+                             std::vector<SetSpeedEvent>&& sse)
+{
+    return [pg = std::move(pg),
+            sse = std::move(sse)](auto& zone, auto& group)
+    {
+        // Compare given precondition entries
+        auto precondState = std::all_of(
+            pg.begin(),
+            pg.end(),
+            [&zone](auto const& entry)
+            {
+                try
+                {
+                    return zone.getPropValueVariant(
+                        std::get<pcPathPos>(entry),
+                        std::get<pcIntfPos>(entry),
+                        std::get<pcPropPos>(entry)) ==
+                                std::get<pcValuePos>(entry);
+                }
+                catch (const std::out_of_range& oore)
+                {
+                    // Default to property variants not equal when not found
+                    return false;
+                }
+            });
+
+        if (precondState)
+        {
+            log<level::DEBUG>(
+                "Preconditions passed, init the associated events",
+                entry("EVENT_COUNT=%u", sse.size()));
+            // Init the events when all the precondition(s) are true
+            std::for_each(
+                sse.begin(),
+                sse.end(),
+                [&zone](auto const& entry)
+                {
+                    zone.initEvent(entry);
+                });
+        }
+        else
+        {
+            log<level::DEBUG>(
+                "Preconditions not met for events, events removed if present",
+                entry("EVENT_COUNT=%u", sse.size()));
+            // Unsubscribe the events' signals when any precondition is false
+            std::for_each(
+                sse.begin(),
+                sse.end(),
+                [&zone](auto const& entry)
+                {
+                    zone.removeEvent(entry);
+                });
+            zone.setFullSpeed();
+        }
+        // Update group's fan control active allowed
+        zone.setActiveAllow(&group, precondState);
+    };
+}
+
+} // namespace precondition
+} // namespace control
+} // namespace fan
+} // namespace phosphor