Report: make dbus properties writable

ReadingParametersFutureVersion interface for Reports is enhanced from
read-only to read write and supports modification of readingParameteres,
which is done by updating metrics at the first place and re-registering
them for sensors updates. Similar ReportActions interface is enhanced to
read write. Additionally reportActions policy was modified that reports
always contain 'LogToMetricReportsCollection' action. The whole change
enables Redfish support for PATCH method added on webserver side.

Tested:
- New unit tests were created, ran all new and previous UTs, all passed
- Tested under QEMU, interface was checked for RW via dbus cli commands,
  checked if Reading Parameters of the Report can be read or written,
  if metrics are properly updated and registration/unregistration for
  updates works properly, checked if actions of Report can be read or
  written, if actions are properly updated and related action behavior
  follows the change accordingly
- Tested under QEMU, verified if 'LogToMetricReportsCollection' action
  is always added when Report is created or when actions of Report are
  updated by dbus interface
- Tested via webserver if it communicates properly with dbus interfaces
  of Telemetry and read/write operations via Redfish can be successfully
  executed

Signed-off-by: Lukasz Kazmierczak <lukasz.kazmierczak@intel.com>
Change-Id: I7f2fe8eae1631c436cf61a516d5fd0b8358a76bd
diff --git a/src/report_factory.cpp b/src/report_factory.cpp
index 261fc75..039846e 100644
--- a/src/report_factory.cpp
+++ b/src/report_factory.cpp
@@ -40,10 +40,60 @@
                 std::make_unique<Clock>());
         });
 
-    return std::make_unique<Report>(
-        bus->get_io_context(), objServer, id, name, reportingType,
-        reportActions, period, appendLimit, reportUpdates, reportManager,
-        reportStorage, std::move(metrics), enabled, std::make_unique<Clock>());
+    return std::make_unique<Report>(bus->get_io_context(), objServer, id, name,
+                                    reportingType, reportActions, period,
+                                    appendLimit, reportUpdates, reportManager,
+                                    reportStorage, std::move(metrics), *this,
+                                    enabled, std::make_unique<Clock>());
+}
+
+void ReportFactory::updateMetrics(
+    std::vector<std::shared_ptr<interfaces::Metric>>& metrics, bool enabled,
+    const ReadingParameters& metricParams) const
+{
+    auto labeledMetricParams = convertMetricParams(metricParams);
+    std::vector<std::shared_ptr<interfaces::Metric>> oldMetrics = metrics;
+    std::vector<std::shared_ptr<interfaces::Metric>> newMetrics;
+
+    for (const auto& labeledMetricParam : labeledMetricParams)
+    {
+        auto existing = std::find_if(oldMetrics.begin(), oldMetrics.end(),
+                                     [labeledMetricParam](auto metric) {
+                                         return labeledMetricParam ==
+                                                metric->dumpConfiguration();
+                                     });
+
+        if (existing != oldMetrics.end())
+        {
+            newMetrics.emplace_back(*existing);
+            oldMetrics.erase(existing);
+            continue;
+        }
+
+        namespace ts = utils::tstring;
+        newMetrics.emplace_back(std::make_shared<Metric>(
+            getSensors(labeledMetricParam.at_label<ts::SensorPath>()),
+            labeledMetricParam.at_label<ts::OperationType>(),
+            labeledMetricParam.at_label<ts::Id>(),
+            labeledMetricParam.at_label<ts::CollectionTimeScope>(),
+            labeledMetricParam.at_label<ts::CollectionDuration>(),
+            std::make_unique<Clock>()));
+
+        if (enabled)
+        {
+            newMetrics.back()->initialize();
+        }
+    }
+
+    if (enabled)
+    {
+        for (auto& metric : oldMetrics)
+        {
+            metric->deinitialize();
+        }
+    }
+
+    metrics = std::move(newMetrics);
 }
 
 Sensors ReportFactory::getSensors(
@@ -65,8 +115,30 @@
     boost::asio::yield_context& yield,
     const ReadingParameters& metricParams) const
 {
+    if (metricParams.empty())
+    {
+        return {};
+    }
     auto tree = utils::getSubTreeSensors(yield, bus);
+    return getMetricParamsFromSensorTree(metricParams, tree);
+}
 
+std::vector<LabeledMetricParameters> ReportFactory::convertMetricParams(
+    const ReadingParameters& metricParams) const
+{
+    if (metricParams.empty())
+    {
+        return {};
+    }
+    auto tree = utils::getSubTreeSensors(bus);
+    return getMetricParamsFromSensorTree(metricParams, tree);
+}
+
+std::vector<LabeledMetricParameters>
+    ReportFactory::getMetricParamsFromSensorTree(
+        const ReadingParameters& metricParams,
+        const std::vector<utils::SensorTree>& tree) const
+{
     return utils::transform(metricParams, [&tree](const auto& item) {
         auto [sensorPaths, operationType, id, collectionTimeScope,
               collectionDuration] = item;