control: Remove JSON zone object include of YAML zone object

This completes another step at separating the JSON based zone object
from the YAML based zone object. Unfortunately a couple ties to the YAML
based zone object still exists thru including the current set of
functors. Those will need to be replicated into the JSON based binary in
a follow-up commit.

The primary addition here was to extend the `ThermalMode` interface by
the JSON based zone object including the necessary methods to support
it. Some `TODO`s were noted and will be handled later as additional
functionality is ported over the JSON based binary.

Change-Id: Ia1c4a680541609933f733497c0987d3b6b0f1c33
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/control/json/zone.cpp b/control/json/zone.cpp
index 243fade..f5f8606 100644
--- a/control/json/zone.cpp
+++ b/control/json/zone.cpp
@@ -13,18 +13,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include "config.h"
+
 #include "zone.hpp"
 
-#include "../zone.hpp"
 #include "fan.hpp"
 #include "functor.hpp"
 #include "handlers.hpp"
-#include "types.hpp"
 
+#include <cereal/archives/json.hpp>
+#include <cereal/cereal.hpp>
 #include <nlohmann/json.hpp>
 #include <phosphor-logging/log.hpp>
 #include <sdbusplus/bus.hpp>
 
+#include <algorithm>
+#include <filesystem>
+#include <fstream>
 #include <iterator>
 #include <map>
 #include <numeric>
@@ -36,6 +41,7 @@
 
 using json = nlohmann::json;
 using namespace phosphor::logging;
+namespace fs = std::filesystem;
 
 const std::map<std::string, std::map<std::string, propHandler>>
     Zone::_intfPropHandlers = {{thermModeIntf,
@@ -43,7 +49,9 @@
                                  {currentProp, zone::property::current}}}};
 
 Zone::Zone(sdbusplus::bus::bus& bus, const json& jsonObj) :
-    ConfigBase(jsonObj), _incDelay(0), _floor(0), _target(0)
+    ConfigBase(jsonObj),
+    ThermalObject(bus, (fs::path{CONTROL_OBJPATH} /= getName()).c_str(), true),
+    _incDelay(0), _floor(0), _target(0)
 {
     if (jsonObj.contains("profiles"))
     {
@@ -92,6 +100,49 @@
     // TODO Add from `requestSpeedIncrease` method in YAML zone object
 }
 
+void Zone::setPersisted(const std::string& intf, const std::string& prop)
+{
+    if (std::find_if(_propsPersisted[intf].begin(), _propsPersisted[intf].end(),
+                     [&prop](const auto& p) { return prop == p; }) !=
+        _propsPersisted[intf].end())
+    {
+        _propsPersisted[intf].emplace_back(prop);
+    }
+}
+
+std::string Zone::current(std::string value)
+{
+    auto current = ThermalObject::current();
+    std::transform(value.begin(), value.end(), value.begin(), toupper);
+
+    auto supported = ThermalObject::supported();
+    auto isSupported =
+        std::any_of(supported.begin(), supported.end(), [&value](auto& s) {
+            std::transform(s.begin(), s.end(), s.begin(), toupper);
+            return value == s;
+        });
+
+    if (value != current && isSupported)
+    {
+        current = ThermalObject::current(value);
+        if (isPersisted("xyz.openbmc_project.Control.ThermalMode", "Current"))
+        {
+            saveCurrentMode();
+        }
+        // TODO Trigger event(s) for current mode property change
+        // auto eData =
+        // _objects[_path]["xyz.openbmc_project.Control.ThermalMode"]
+        //                      ["Current"];
+        // if (eData != nullptr)
+        // {
+        //     sdbusplus::message::message nullMsg{nullptr};
+        //     handleEvent(nullMsg, eData);
+        // }
+    }
+
+    return current;
+}
+
 void Zone::setFullSpeed(const json& jsonObj)
 {
     if (!jsonObj.contains("full_speed"))
@@ -201,6 +252,29 @@
     }
 }
 
+bool Zone::isPersisted(const std::string& intf, const std::string& prop)
+{
+    auto it = _propsPersisted.find(intf);
+    if (it == _propsPersisted.end())
+    {
+        return false;
+    }
+
+    return std::any_of(it->second.begin(), it->second.end(),
+                       [&prop](const auto& p) { return prop == p; });
+}
+
+void Zone::saveCurrentMode()
+{
+    fs::path path{CONTROL_PERSIST_ROOT_PATH};
+    // Append zone name and property description
+    path /= getName();
+    path /= "CurrentMode";
+    std::ofstream ofs(path.c_str(), std::ios::binary);
+    cereal::JSONOutputArchive oArch(ofs);
+    oArch(ThermalObject::current());
+}
+
 /**
  * Properties of interfaces supported by the zone configuration that return
  * a ZoneHandler function that sets the zone's property value(s).
@@ -235,6 +309,7 @@
         }
     }
 
+    // TODO Use this zone object's extended `supported` method in the handler
     return make_zoneHandler(handler::setZoneProperty<std::vector<std::string>>(
         Zone::thermModeIntf, Zone::supportedProp, &control::Zone::supported,
         std::move(values), persist));
@@ -253,6 +328,7 @@
         return {};
     }
 
+    // TODO Use this zone object's `current` method in the handler
     return make_zoneHandler(handler::setZoneProperty<std::string>(
         Zone::thermModeIntf, Zone::currentProp, &control::Zone::current,
         jsonObj["value"].get<std::string>(), persist));
diff --git a/control/json/zone.hpp b/control/json/zone.hpp
index b91af2f..291a5c5 100644
--- a/control/json/zone.hpp
+++ b/control/json/zone.hpp
@@ -17,7 +17,7 @@
 
 #include "config_base.hpp"
 #include "fan.hpp"
-#include "types.hpp"
+#include "xyz/openbmc_project/Control/ThermalMode/server.hpp"
 
 #include <nlohmann/json.hpp>
 #include <sdbusplus/bus.hpp>
@@ -32,6 +32,10 @@
 
 using json = nlohmann::json;
 
+/* Extend the Control::ThermalMode interface */
+using ThermalObject = sdbusplus::server::object::object<
+    sdbusplus::xyz::openbmc_project::Control::server::ThermalMode>;
+
 /* Interface property handler function */
 using propHandler = std::function<ZoneHandler(const json&, bool)>;
 
@@ -48,7 +52,7 @@
  * (When no profile for a zone is given, the zone defaults to always exist)
  *
  */
-class Zone : public ConfigBase
+class Zone : public ConfigBase, public ThermalObject
 {
   public:
     /* JSON file name for zones */
@@ -187,6 +191,23 @@
      */
     void requestIncrease(uint64_t targetDelta);
 
+    /**
+     * @brief Set a property to be persisted
+     *
+     * @param[in] intf - Interface containing property
+     * @param[in] prop - Property to be persisted
+     */
+    void setPersisted(const std::string& intf, const std::string& prop);
+
+    /**
+     * @brief Overridden thermal object's set 'Current' property function
+     *
+     * @param[in] value - Value to set 'Current' to
+     *
+     * @return - The updated value of the 'Current' property
+     */
+    std::string current(std::string value) override;
+
   private:
     /* The zone's full speed value for fans */
     uint64_t _fullSpeed;
@@ -209,6 +230,9 @@
     /* Map of whether floor changes are allowed by a string identifier */
     std::map<std::string, bool> _floorChange;
 
+    /* Map of interfaces to persisted properties the zone hosts*/
+    std::map<std::string, std::vector<std::string>> _propsPersisted;
+
     /**
      * Zone interface handler functions for its
      * configured interfaces (OPTIONAL)
@@ -262,6 +286,22 @@
      * to not be persisted when not given.
      */
     void setInterfaces(const json& jsonObj);
+
+    /**
+     * @brief Is the property persisted
+     *
+     * @param[in] intf - Interface containing property
+     * @param[in] prop - Property to check if persisted
+     *
+     * @return - True if property is to be persisted, false otherwise
+     */
+    bool isPersisted(const std::string& intf, const std::string& prop);
+
+    /**
+     * @brief Save the thermal control current mode property to persisted
+     * storage
+     */
+    void saveCurrentMode();
 };
 
 /**