control: Parse/add zones to manager

The manager will create and manage the zone objects across the entire
system. This required additional updates to how the profiles were
determined and restrict to only creating objects if their configured
profiles(which is optional) is active or no profile was configured.

Also reorganized some functionality into the manager object so the JSON
parser object can be removed once the full JSON code path is complete.

Change-Id: Ieb5d87a3d0789fee5e9cdde97217b3532add73df
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/control/json/manager.hpp b/control/json/manager.hpp
index 597fdd9..60cf2b7 100644
--- a/control/json/manager.hpp
+++ b/control/json/manager.hpp
@@ -15,8 +15,9 @@
  */
 #pragma once
 
-#include "json_parser.hpp"
+#include "json_config.hpp"
 #include "profile.hpp"
+#include "zone.hpp"
 
 #include <nlohmann/json.hpp>
 #include <sdbusplus/bus.hpp>
@@ -27,6 +28,18 @@
 
 using json = nlohmann::json;
 
+/* Application name to be appended to the path for loading a JSON config file */
+constexpr auto confAppName = "control";
+
+/**
+ * Configuration object key to uniquely map to the configuration object
+ * Pair constructed of:
+ *      std::string = Configuration object's name
+ *      std::vector<std::string> = List of profiles the configuration object
+ *                                 is included in
+ */
+using configKey = std::pair<std::string, std::vector<std::string>>;
+
 /**
  * @class Manager - Represents the fan control manager's configuration
  *
@@ -59,6 +72,69 @@
     Manager(sdbusplus::bus::bus& bus, const sdeventplus::Event& event);
 
     /**
+     * @brief Get the active profiles of the system where an empty list
+     * represents that only configuration entries without a profile defined will
+     * be loaded.
+     *
+     * @return - The list of active profiles
+     */
+    static const std::vector<std::string>& getActiveProfiles();
+
+    /**
+     * @brief Load the configuration of a given JSON class object based on the
+     * active profiles
+     *
+     * @param[in] bus - The sdbusplus bus object
+     * @param[in] isOptional - JSON configuration file is optional or not
+     *                         Defaults to false
+     *
+     * @return Map of configuration entries
+     *     Map of configuration keys to their corresponding configuration object
+     */
+    template <typename T>
+    static std::map<configKey, std::unique_ptr<T>>
+        getConfig(sdbusplus::bus::bus& bus, bool isOptional = false)
+    {
+        std::map<configKey, std::unique_ptr<T>> config;
+
+        auto confFile = fan::JsonConfig::getConfFile(
+            bus, confAppName, T::confFileName, isOptional);
+        if (!confFile.empty())
+        {
+            for (const auto& entry : fan::JsonConfig::load(confFile))
+            {
+                if (entry.contains("profiles"))
+                {
+                    std::vector<std::string> profiles;
+                    for (const auto& profile : entry["profiles"])
+                    {
+                        profiles.emplace_back(
+                            profile.template get<std::string>());
+                    }
+                    // Do not create the object if its profiles are not in the
+                    // list of active profiles
+                    if (!std::any_of(profiles.begin(), profiles.end(),
+                                     [](const auto& name) {
+                                         return std::find(
+                                                    getActiveProfiles().begin(),
+                                                    getActiveProfiles().end(),
+                                                    name) !=
+                                                getActiveProfiles().end();
+                                     }))
+                    {
+                        continue;
+                    }
+                }
+                auto obj = std::make_unique<T>(bus, entry);
+                config.emplace(
+                    std::make_pair(obj->getName(), obj->getProfiles()),
+                    std::move(obj));
+            }
+        }
+        return config;
+    }
+
+    /**
      * @brief Get the configured power on delay(OPTIONAL)
      *
      * @return Power on delay in seconds
@@ -73,11 +149,34 @@
     /* The parsed JSON object */
     json _jsonObj;
 
+    /**
+     * The sdbusplus bus object to use
+     */
+    sdbusplus::bus::bus& _bus;
+
+    /**
+     * The sdeventplus even loop to use
+     */
+    sdeventplus::Event _event;
+
     /* List of profiles configured */
-    const std::map<configKey, std::unique_ptr<Profile>> _profiles;
+    std::map<configKey, std::unique_ptr<Profile>> _profiles;
 
     /* List of active profiles */
-    std::vector<std::string> _activeProfiles;
+    static std::vector<std::string> _activeProfiles;
+
+    /* List of zones configured */
+    std::map<configKey, std::unique_ptr<Zone>> _zones;
+
+    /**
+     * @brief Parse and set the configured profiles from the profiles JSON file
+     *
+     * Retrieves the optional profiles JSON configuration file, parses it, and
+     * creates a list of configured profiles available to the other
+     * configuration files. These profiles can be used to remove or include
+     * entries within the other configuration files.
+     */
+    void setProfiles();
 };
 
 } // namespace phosphor::fan::control::json