Add support for processing start event triggers

Process application start event triggers' list of conditions on a group
and perform the defined actions.

This re-uses the following structs(and their necessary functions)
directly from phosphor-inventory-manager:
--struct PropertyConditionBase
--struct PropertyCondition

Change-Id: If4090299fe887ef940320091d4d4be9f6aa7dd29
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/src/functor.cpp b/src/functor.cpp
new file mode 100644
index 0000000..f4d2574
--- /dev/null
+++ b/src/functor.cpp
@@ -0,0 +1,63 @@
+#include "functor.hpp"
+#include <sdbusplus/bus.hpp>
+#include <sdbusplus/message.hpp>
+
+namespace phosphor
+{
+namespace dbus
+{
+namespace monitoring
+{
+
+bool PropertyConditionBase::operator()(sdbusplus::bus::bus& bus,
+                                       sdbusplus::message::message&,
+                                       Monitor& mon) const
+{
+    std::string host;
+
+    if (_service)
+    {
+        host.assign(_service);
+    }
+    else
+    {
+        auto mapperCall = bus.new_method_call(
+                              "xyz.openbmc_project.ObjectMapper",
+                              "/xyz/openbmc_project/object_mapper",
+                              "xyz.openbmc_project.ObjectMapper",
+                              "GetObject");
+        mapperCall.append(_path);
+        mapperCall.append(std::vector<std::string>({_iface}));
+        auto mapperResponseMsg = bus.call(mapperCall);
+        if (mapperResponseMsg.is_method_error())
+        {
+            return false;
+        }
+
+        std::map<std::string, std::vector<std::string>> mapperResponse;
+        mapperResponseMsg.read(mapperResponse);
+        if (mapperResponse.empty())
+        {
+            return false;
+        }
+
+        host = mapperResponse.begin()->first;
+    }
+    auto hostCall = bus.new_method_call(host.c_str(),
+                                        _path.c_str(),
+                                        "org.freedesktop.DBus.Properties",
+                                        "Get");
+    hostCall.append(_iface);
+    hostCall.append(_property);
+    auto hostResponseMsg = bus.call(hostCall);
+    if (hostResponseMsg.is_method_error())
+    {
+        return false;
+    }
+
+    return eval(hostResponseMsg);
+}
+
+} // namespace monitoring
+} // namespace dbus
+} // namespace phosphor
diff --git a/src/functor.hpp b/src/functor.hpp
index 9353763..c2c586e 100644
--- a/src/functor.hpp
+++ b/src/functor.hpp
@@ -23,6 +23,121 @@
     return Action(std::forward<T>(action));
 }
 
+struct PropertyConditionBase
+{
+    PropertyConditionBase() = delete;
+    virtual ~PropertyConditionBase() = default;
+    PropertyConditionBase(const PropertyConditionBase&) = default;
+    PropertyConditionBase& operator=(const PropertyConditionBase&) = default;
+    PropertyConditionBase(PropertyConditionBase&&) = default;
+    PropertyConditionBase& operator=(PropertyConditionBase&&) = default;
+
+    /** @brief Constructor
+     *
+     *  The service argument can be nullptr.  If something
+     *  else is provided the function will call the the
+     *  service directly.  If omitted, the function will
+     *  look up the service in the ObjectMapper.
+     *
+     *  @param path - The path of the object containing
+     *     the property to be tested.
+     *  @param iface - The interface hosting the property
+     *     to be tested.
+     *  @param property - The property to be tested.
+     *  @param service - The DBus service hosting the object.
+     */
+    PropertyConditionBase(
+        const char* path,
+        const char* iface,
+        const char* property,
+        const char* service) :
+        _path(path ? path : std::string()),
+        _iface(iface),
+        _property(property),
+        _service(service) {}
+
+    /** @brief Forward comparison to type specific implementation. */
+    virtual bool eval(sdbusplus::message::message&) const = 0;
+
+    /** @brief Test a property value.
+     *
+     * Make a DBus call and test the value of any property.
+     */
+    bool operator()(
+        sdbusplus::bus::bus&,
+        sdbusplus::message::message&,
+        Monitor&) const;
+
+private:
+    std::string _path;
+    std::string _iface;
+    std::string _property;
+    const char* _service;
+};
+
+template <typename T, typename U>
+struct PropertyCondition final : public PropertyConditionBase
+{
+    PropertyCondition() = delete;
+    ~PropertyCondition() = default;
+    PropertyCondition(const PropertyCondition&) = default;
+    PropertyCondition& operator=(const PropertyCondition&) = default;
+    PropertyCondition(PropertyCondition&&) = default;
+    PropertyCondition& operator=(PropertyCondition&&) = default;
+
+    /** @brief Constructor
+     *
+     *  The service argument can be nullptr.  If something
+     *  else is provided the function will call the the
+     *  service directly.  If omitted, the function will
+     *  look up the service in the ObjectMapper.
+     *
+     *  @param path - The path of the object containing
+     *     the property to be tested.
+     *  @param iface - The interface hosting the property
+     *     to be tested.
+     *  @param property - The property to be tested.
+     *  @param condition - The test to run on the property.
+     *  @param service - The DBus service hosting the object.
+     */
+    PropertyCondition(
+        const char* path,
+        const char* iface,
+        const char* property,
+        U&& condition,
+        const char* service) :
+        PropertyConditionBase(path, iface, property, service),
+        _condition(std::forward<decltype(condition)>(condition)) {}
+
+    /** @brief Test a property value.
+     *
+     * Make a DBus call and test the value of any property.
+     */
+    bool eval(sdbusplus::message::message& msg) const override
+    {
+        sdbusplus::message::variant<T> value;
+        msg.read(value);
+        return _condition(std::forward<T>(value.template get<T>()));
+    }
+
+private:
+    U _condition;
+};
+
+template <typename T, typename U>
+auto propertyStart(const char* path,
+                   const char* iface,
+                   const char* property,
+                   U&& condition,
+                   const char* service = nullptr)
+{
+    return PropertyCondition<T, U>(path,
+                                   iface,
+                                   property,
+                                   std::move(condition),
+                                   service);
+}
+
 } // namespace monitoring
 } // namespace dbus
 } // namespace phosphor
diff --git a/src/monitor.cpp b/src/monitor.cpp
index f734b00..2864924 100644
--- a/src/monitor.cpp
+++ b/src/monitor.cpp
@@ -7,12 +7,56 @@
 namespace monitoring
 {
 
+// TODO Remove when generated.cpp included
+const std::vector<std::tuple<std::vector<std::shared_ptr<Event>>,
+                             std::vector<Action>>>
+    Monitor::events
+{};
+
 Monitor::Monitor(sdbusplus::bus::bus& bus) :
     bus(bus)
 {
 
 }
 
+void Monitor::processStart() noexcept
+{
+    sdbusplus::message::message nullMsg{nullptr};
+
+    // Process thru given events that are type 'start'
+    for (auto& event : events)
+    {
+        for (auto& pEvent : std::get<std::vector<std::shared_ptr<Event>>>(event))
+        {
+            if (pEvent->trigger == Event::Trigger::START)
+            {
+                handleEvent(nullMsg, *pEvent, event);
+            }
+        }
+    }
+}
+
+void Monitor::handleEvent(sdbusplus::message::message& msg,
+                          const Event& event,
+                          const std::tuple<std::vector<std::shared_ptr<Event>>,
+                                           std::vector<Action>>& eventDef)
+{
+    // Iterate over conditions
+    for (auto& cond : event)
+    {
+        if (!cond(bus, msg, *this))
+        {
+            continue;
+        }
+        // Perform defined actions
+        for (auto& act : std::get<1>(eventDef))
+        {
+            act(bus, *this);
+        }
+        return;
+    }
+}
+
 } // namespace monitoring
 } // namespace dbus
 } // namespace phosphor
diff --git a/src/monitor.hpp b/src/monitor.hpp
index 2fc91b5..aca64d8 100644
--- a/src/monitor.hpp
+++ b/src/monitor.hpp
@@ -23,9 +23,20 @@
 
         explicit Monitor(sdbusplus::bus::bus& bus);
 
+        void processStart() noexcept;
+
+        void handleEvent(sdbusplus::message::message& msg,
+                         const Event& event,
+                         const std::tuple<std::vector<std::shared_ptr<Event>>,
+                                    std::vector<Action>>& eventDef);
+
     private:
         sdbusplus::bus::bus& bus;
 
+        static const std::vector<
+            std::tuple<std::vector<std::shared_ptr<Event>>,
+                       std::vector<Action>>> events;
+
 };
 
 } // namespace monitoring