control: Update config loading

Change the method used to load objects' JSON configuration where a list
of arguments specific to the object's class is given. This allows each
class to be constructed with its specific set of required arguments.
With this change, the zones require a pointer to their manager object
along with a reference to the event loop for their increment and
decrement timers. The manager object stores the cache for all zones,
each zone needs a pointer to its manager to be able to provide access
to that cache.

With the change in how the objects are created from their JSON
configuration files, loading the information into the YAML based
ZoneDefinitions structure is no longer needed.

Change-Id: I4f70cbeb3a708b985ca01a1f3df14ad78da053fb
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/control/json/fan.cpp b/control/json/fan.cpp
index a880915..9fbd03c 100644
--- a/control/json/fan.cpp
+++ b/control/json/fan.cpp
@@ -32,7 +32,7 @@
 constexpr auto FAN_SENSOR_PATH = "/xyz/openbmc_project/sensors/fan_tach/";
 constexpr auto FAN_TARGET_PROPERTY = "Target";
 
-Fan::Fan(sdbusplus::bus::bus& bus, const json& jsonObj) :
+Fan::Fan(const json& jsonObj, sdbusplus::bus::bus& bus) :
     ConfigBase(jsonObj), _bus(bus)
 {
     setInterface(jsonObj);
diff --git a/control/json/fan.hpp b/control/json/fan.hpp
index b718585..e2bf985 100644
--- a/control/json/fan.hpp
+++ b/control/json/fan.hpp
@@ -57,10 +57,10 @@
      * Constructor
      * Parses and populates a zone fan from JSON object data
      *
-     * @param[in] bus - sdbusplus bus object
      * @param[in] jsonObj - JSON object
+     * @param[in] bus - sdbusplus bus object
      */
-    Fan(sdbusplus::bus::bus& bus, const json& jsonObj);
+    Fan(const json& jsonObj, sdbusplus::bus::bus& bus);
 
     /**
      * @brief Get the zone
diff --git a/control/json/manager.cpp b/control/json/manager.cpp
index a072f49..94a39a8 100644
--- a/control/json/manager.cpp
+++ b/control/json/manager.cpp
@@ -67,10 +67,10 @@
     setProfiles();
 
     // Load the zone configurations
-    _zones = getConfig<Zone>(bus);
+    _zones = getConfig<Zone>(false, bus, bus, event, this);
 
     // Load the fan configurations and move each fan into its zone
-    auto fans = getConfig<Fan>(bus);
+    auto fans = getConfig<Fan>(false, bus, bus);
     for (auto& fan : fans)
     {
         auto itZone =
diff --git a/control/json/manager.hpp b/control/json/manager.hpp
index c2a0904..506c8c0 100644
--- a/control/json/manager.hpp
+++ b/control/json/manager.hpp
@@ -122,16 +122,16 @@
      * @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
+     * @param[in] bus - The sdbusplus bus object
+     * @param[in] args - Arguments to be forwarded to each instance of `T`
      *
      * @return Map of configuration entries
      *     Map of configuration keys to their corresponding configuration object
      */
-    template <typename T>
+    template <typename T, typename... Args>
     static std::map<configKey, std::unique_ptr<T>>
-        getConfig(sdbusplus::bus::bus& bus, bool isOptional = false)
+        getConfig(bool isOptional, sdbusplus::bus::bus& bus, Args&&... args)
     {
         std::map<configKey, std::unique_ptr<T>> config;
 
@@ -163,7 +163,8 @@
                         continue;
                     }
                 }
-                auto obj = std::make_unique<T>(bus, entry);
+                auto obj =
+                    std::make_unique<T>(entry, std::forward<Args>(args)...);
                 config.emplace(
                     std::make_pair(obj->getName(), obj->getProfiles()),
                     std::move(obj));
diff --git a/control/json/zone.cpp b/control/json/zone.cpp
index e11e6fc..6249194 100644
--- a/control/json/zone.cpp
+++ b/control/json/zone.cpp
@@ -24,6 +24,7 @@
 #include <nlohmann/json.hpp>
 #include <phosphor-logging/log.hpp>
 #include <sdbusplus/bus.hpp>
+#include <sdeventplus/event.hpp>
 
 #include <algorithm>
 #include <filesystem>
@@ -48,11 +49,12 @@
                                 {{supportedProp, zone::property::supported},
                                  {currentProp, zone::property::current}}}};
 
-Zone::Zone(sdbusplus::bus::bus& bus, const json& jsonObj) :
+Zone::Zone(const json& jsonObj, sdbusplus::bus::bus& bus,
+           const sdeventplus::Event& event, Manager* mgr) :
     ConfigBase(jsonObj),
     ThermalObject(bus, (fs::path{CONTROL_OBJPATH} /= getName()).c_str(), true),
-    _incDelay(0), _floor(0), _target(0), _incDelta(0), _decDelta(0),
-    _requestTargetBase(0), _isActive(true)
+    _manager(mgr), _incDelay(0), _floor(0), _target(0), _incDelta(0),
+    _decDelta(0), _requestTargetBase(0), _isActive(true)
 {
     // Increase delay is optional, defaults to 0
     if (jsonObj.contains("increase_delay"))
diff --git a/control/json/zone.hpp b/control/json/zone.hpp
index 3ae8139..5256018 100644
--- a/control/json/zone.hpp
+++ b/control/json/zone.hpp
@@ -21,6 +21,7 @@
 
 #include <nlohmann/json.hpp>
 #include <sdbusplus/bus.hpp>
+#include <sdeventplus/event.hpp>
 
 #include <any>
 #include <functional>
@@ -30,6 +31,8 @@
 namespace phosphor::fan::control::json
 {
 
+class Manager;
+
 using json = nlohmann::json;
 
 /* Extend the Control::ThermalMode interface */
@@ -69,10 +72,13 @@
      * Constructor
      * Parses and populates a zone from JSON object data
      *
-     * @param[in] bus - sdbusplus bus object
      * @param[in] jsonObj - JSON object
+     * @param[in] bus - sdbusplus bus object
+     * @param[in] event - sdeventplus event loop
+     * @param[in] mgr - Manager of this zone
      */
-    Zone(sdbusplus::bus::bus& bus, const json& jsonObj);
+    Zone(const json& jsonObj, sdbusplus::bus::bus& bus,
+         const sdeventplus::Event& event, Manager* mgr);
 
     /**
      * @brief Get the default ceiling
@@ -156,6 +162,16 @@
     };
 
     /**
+     * @brief Get the manager of the zone
+     *
+     * @return - The manager of the zone
+     */
+    inline auto* getManager() const
+    {
+        return _manager;
+    }
+
+    /**
      * @brief Add a fan object to the zone
      *
      * @param[in] fan - Unique pointer to a fan object that will be moved into
@@ -308,6 +324,9 @@
     }
 
   private:
+    /* The zone's manager */
+    Manager* _manager;
+
     /* The zone's default ceiling value for fans */
     uint64_t _defaultCeiling;
 
diff --git a/control/json_parser.cpp b/control/json_parser.cpp
index 12c2c99..bdd99b3 100644
--- a/control/json_parser.cpp
+++ b/control/json_parser.cpp
@@ -59,94 +59,6 @@
     return false;
 }
 
-const std::vector<ZoneGroup> getZoneGroups(sdbusplus::bus::bus& bus)
-{
-    std::vector<ZoneGroup> zoneGrps;
-
-    // Profiles are optional
-    auto profiles = getConfig<json::Profile>(true);
-    // Fans to be controlled
-    auto fans = getConfig<json::Fan>(bus);
-    // Zones within the system
-    auto zones = getConfig<json::Zone>(bus);
-    // Fan control events are optional
-    auto events = getConfig<json::Event>(bus, true);
-
-    // Ensure all configurations use the same set of active profiles
-    // (In case a profile's active state changes during configuration)
-    std::vector<std::string> activeProfiles;
-    for (const auto& profile : profiles)
-    {
-        if (profile.second->isActive())
-        {
-            activeProfiles.emplace_back(profile.first.first);
-        }
-    }
-
-    // Conditions list empty for JSON based configurations
-    // TODO Remove conditions after YAML based configuration removed
-    std::vector<Condition> conditions;
-    std::vector<ZoneDefinition> zoneDefs;
-    for (const auto& zone : zones)
-    {
-        // Check zone profiles against active profiles
-        if (checkEntry(activeProfiles, zone.second->getProfiles()))
-        {
-            auto zoneName = zone.second->getName();
-            // Create FanDefinition list for zone
-            std::vector<FanDefinition> fanDefs;
-            for (const auto& fan : fans)
-            {
-                // Check fan profiles against active profiles and
-                // if the fan is included in the zone
-                if (checkEntry(activeProfiles, fan.second->getProfiles()) &&
-                    fan.second->getZone() == zoneName)
-                {
-                    // Adjust fan object sensor list to be included in the
-                    // YAML fan definitions structure
-                    std::vector<std::string> fanSensorList;
-                    for (const auto& sensorMap : fan.second->getSensors())
-                    {
-                        auto sensor = sensorMap.first;
-                        sensor.erase(0, 38);
-                        fanSensorList.emplace_back(sensor);
-                    }
-                    fanDefs.emplace_back(
-                        std::make_tuple(fan.second->getName(), fanSensorList,
-                                        fan.second->getInterface()));
-                }
-            }
-
-            // Create SetSpeedEvents list for zone
-            std::vector<SetSpeedEvent> speedEvents;
-            // TODO Populate SetSpeedEvents list with configured events
-
-            // YAML zone name was an integer, JSON is a string
-            // Design direction is for it to be a string and this can be
-            // removed after YAML based configurations are removed.
-            char* zoneName_end;
-            auto zoneNum = std::strtol(zoneName.c_str(), &zoneName_end, 10);
-            if (*zoneName_end)
-            {
-                throw std::runtime_error(
-                    "Zone names must be a string representation of a number");
-            }
-
-            zoneDefs.emplace_back(std::make_tuple(
-                zoneNum, zone.second->getDefaultCeiling(),
-                zone.second->getDefaultFloor(), zone.second->getIncDelay(),
-                zone.second->getDecInterval(), std::vector<ZoneHandler>{},
-                std::move(fanDefs), std::move(speedEvents)));
-        }
-    }
-    // TODO Should only result in a single entry but YAML based configurations
-    // produce a list of zone groups. Change to single zone group after YAML
-    // based configuartions are removed.
-    zoneGrps.emplace_back(std::make_tuple(conditions, zoneDefs));
-
-    return zoneGrps;
-}
-
 const unsigned int getPowerOnDelay(sdbusplus::bus::bus& bus,
                                    const sdeventplus::Event& event)
 {
diff --git a/control/json_parser.hpp b/control/json_parser.hpp
index b7d2202..a703ab6 100644
--- a/control/json_parser.hpp
+++ b/control/json_parser.hpp
@@ -126,16 +126,6 @@
                 const std::vector<std::string>& entryProfiles);
 
 /**
- * @brief Get the configuration definitions for zone groups
- *
- * @param[in] bus - The dbus bus object
- *
- * @return List of zone group objects
- *     Generated list of zone groups including their control configurations
- */
-const std::vector<ZoneGroup> getZoneGroups(sdbusplus::bus::bus& bus);
-
-/**
  * @brief Get the delay(in seconds) to allow the fans to ramp up to the defined
  * power on speed
  *