monitor:JSON: Parse fan monitoring conditions

Optional conditions can be used to include monitoring a fan or not based
on the results of the condition function configured. These condition
functions have their own required set of parameters, so parsing the JSON
for these conditions are done per supported condition function. This
adds the JSON parsing support for the current condition functions.

Tested:
    `propertiesMatch` JSON parameters parsed into condition function
    Any required parameters missing throws an exception
    The `propertiesMatch` condition functions the same using JSON

Change-Id: I0f843951f4e83f2a5d44068820694010538788c1
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/monitor/json_parser.cpp b/monitor/json_parser.cpp
index 34d1995..9b773c2 100644
--- a/monitor/json_parser.cpp
+++ b/monitor/json_parser.cpp
@@ -51,6 +51,8 @@
 
 const std::map<std::string, trustHandler> trusts = {
     {"nonzerospeed", tClass::getNonZeroSpeed}};
+const std::map<std::string, condHandler> conditions = {
+    {"propertiesmatch", condition::getPropertiesMatch}};
 
 const std::vector<CreateGroupFunction> getTrustGrps(const json& obj)
 {
@@ -189,8 +191,36 @@
             funcDelay = fan["functional_delay"].get<size_t>();
         }
 
-        // TODO Handle optional conditions
+        // Handle optional conditions
         auto cond = std::experimental::optional<Condition>();
+        if (fan.contains("condition"))
+        {
+            if (!fan["condition"].contains("name"))
+            {
+                // Log error on missing required parameter
+                log<level::ERR>(
+                    "Missing required fan monitor condition parameter",
+                    entry("REQUIRED_PARAMETER=%s", "{name}"));
+                throw std::runtime_error(
+                    "Missing required fan monitor condition parameter");
+            }
+            auto name = fan["condition"]["name"].get<std::string>();
+            // The function for fan monitoring condition
+            // (Must have a supported function within the condition namespace)
+            std::transform(name.begin(), name.end(), name.begin(), tolower);
+            auto handler = conditions.find(name);
+            if (handler != conditions.end())
+            {
+                cond = handler->second(fan["condition"]);
+            }
+            else
+            {
+                log<level::INFO>(
+                    "No handler found for configured condition",
+                    entry("CONDITION_NAME=%s", name.c_str()),
+                    entry("JSON_DUMP=%s", fan["condition"].dump().c_str()));
+            }
+        }
 
         fanDefs.emplace_back(
             std::tuple(fan["inventory"].get<std::string>(), funcDelay,