Update led-manager to use JSON

Current LED manager uses compile time generated led-gen.hpp and creates
DBus objects for the groups.
We would need this changed to use the generated JSON.

Tested: JSON used at runtime when --enable-json given at configure time.
led-gen.hpp not created when using JSON and led-gen.hpp created by
default when using YAML at build time.

Signed-off-by: George Liu <liuxiwei@inspur.com>
Change-Id: I781f8cb090ece8b87730e6c97795624282857c64
diff --git a/json-config.hpp b/json-config.hpp
new file mode 100644
index 0000000..3d1caec
--- /dev/null
+++ b/json-config.hpp
@@ -0,0 +1,104 @@
+#include "config.h"
+
+#include "ledlayout.hpp"
+
+#include <nlohmann/json.hpp>
+#include <phosphor-logging/log.hpp>
+
+#include <filesystem>
+#include <fstream>
+#include <iostream>
+
+namespace fs = std::filesystem;
+
+using Json = nlohmann::json;
+using LedAction = std::set<phosphor::led::Layout::LedAction>;
+using LedMap = std::map<std::string, LedAction>;
+
+/** @brief Parse LED JSON file and output Json object
+ *
+ *  @param[in] path - path of LED JSON file
+ *
+ *  @return const Json - Json object
+ */
+const Json readJson(const fs::path& path)
+{
+    using namespace phosphor::logging;
+
+    if (!fs::exists(path) || fs::is_empty(path))
+    {
+        log<level::ERR>("Incorrect File Path or empty file",
+                        entry("FILE_PATH=%s", path.c_str()));
+        throw std::runtime_error("Incorrect File Path or empty file");
+    }
+
+    try
+    {
+        std::ifstream jsonFile(path);
+        return Json::parse(jsonFile);
+    }
+    catch (const std::exception& e)
+    {
+        log<level::ERR>("Failed to parse config file",
+                        entry("ERROR=%s", e.what()),
+                        entry("FILE_PATH=%s", path.c_str()));
+        throw std::runtime_error("Failed to parse config file");
+    }
+}
+
+/** @brief Returns action enum based on string
+ *
+ *  @param[in] action - action string
+ *
+ *  @return Action - action enum (On/Blink)
+ */
+phosphor::led::Layout::Action getAction(const std::string& action)
+{
+    assert(action == "On" || action == "Blink");
+
+    return action == "Blink" ? phosphor::led::Layout::Blink
+                             : phosphor::led::Layout::On;
+}
+
+/** @brief Load JSON config and return led map
+ *
+ *  @return LedMap - Generated an std::map of LedAction
+ */
+const LedMap loadJsonConfig(const fs::path& path)
+{
+    LedMap ledMap{};
+
+    // define the default JSON as empty
+    const Json empty{};
+    auto json = readJson(path);
+
+    auto leds = json.value("leds", empty);
+    for (const auto& entry : leds)
+    {
+        fs::path tmpPath(std::string{OBJPATH});
+        tmpPath /= entry.value("group", "");
+        auto objpath = tmpPath.string();
+        auto members = entry.value("members", empty);
+
+        LedAction ledActions{};
+        for (const auto& member : members)
+        {
+            auto name = member.value("name", "");
+            auto action = getAction(member.value("Action", ""));
+            uint8_t dutyOn = member.value("DutyOn", 50);
+            uint16_t period = member.value("Period", 0);
+
+            // Since only have Blink/On and default priority is Blink
+            auto priority = getAction(member.value("Priority", "Blink"));
+            phosphor::led::Layout::LedAction ledAction{name, action, dutyOn,
+                                                       period, priority};
+            ledActions.emplace(ledAction);
+        }
+
+        // Generated an std::map of LedGroupNames to std::set of LEDs
+        // containing the name and properties.
+        ledMap.emplace(objpath, ledActions);
+    }
+
+    return ledMap;
+}