Expand and update location code property on BUS

This commit expands and updates the required location code
poperty on BUS in case following condition holds true.

a) if FC or SE or both keyword
under VCEN record has been modified by VPD write
application for Motherboard FRU.

OR

b) if TM or SE or both keyword
under VSYS record has been modified by VPD write
application for Motherboard FRU.

Tested on simics.
-make bus call or use VPD tool application to update
keywords as mentioned above in (a) and (b).
-Introspect that motherboard object on bus.
-Check the value of interface "com.ibm.ipzvpd.Location",
property - "LocationCode"

To build the application
meson -Dibm-parser=enabled -Dvpd-manager=Enabled build
ninja -C build

Signed-off-by: Sunny Srivastava <sunnsr25@in.ibm.com>
Change-Id: Ic964da0f058153bdd43b94679bdfc5596d7f3861
diff --git a/vpd-manager/editor_impl.cpp b/vpd-manager/editor_impl.cpp
index 70eb453..d69d7fa 100644
--- a/vpd-manager/editor_impl.cpp
+++ b/vpd-manager/editor_impl.cpp
@@ -364,6 +364,73 @@
     }
 }
 
+void EditorImpl::expandLocationCode(const std::string& locationCodeType)
+{
+    std::string propertyFCorTM{};
+    std::string propertySE{};
+
+    if (locationCodeType == "fcs")
+    {
+        propertyFCorTM =
+            readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VCEN", "FC");
+        propertySE =
+            readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VCEN", "SE");
+    }
+    else if (locationCodeType == "mts")
+    {
+        propertyFCorTM =
+            readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VSYS", "TM");
+        propertySE =
+            readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VSYS", "SE");
+    }
+
+    const nlohmann::json& groupFRUS =
+        jsonFile["frus"].get_ref<const nlohmann::json::object_t&>();
+    for (const auto& itemFRUS : groupFRUS.items())
+    {
+        const std::vector<nlohmann::json>& groupEEPROM =
+            itemFRUS.value().get_ref<const nlohmann::json::array_t&>();
+        for (const auto& itemEEPROM : groupEEPROM)
+        {
+            // check if the given item implements location code interface
+            if (itemEEPROM["extraInterfaces"].find(LOCATION_CODE_INF) !=
+                itemEEPROM["extraInterfaces"].end())
+            {
+                const std::string& unexpandedLocationCode =
+                    itemEEPROM["extraInterfaces"][LOCATION_CODE_INF]
+                              ["LocationCode"]
+                                  .get_ref<const nlohmann::json::string_t&>();
+                std::size_t idx = unexpandedLocationCode.find(locationCodeType);
+                if (idx != std::string::npos)
+                {
+                    std::string expandedLoctionCode(unexpandedLocationCode);
+
+                    if (locationCodeType == "fcs")
+                    {
+                        expandedLoctionCode.replace(
+                            idx, 3,
+                            propertyFCorTM.substr(0, 4) + ".ND0." + propertySE);
+                    }
+                    else if (locationCodeType == "mts")
+                    {
+                        std::replace(propertyFCorTM.begin(),
+                                     propertyFCorTM.end(), '-', '.');
+                        expandedLoctionCode.replace(
+                            idx, 3, propertyFCorTM + "." + propertySE);
+                    }
+
+                    // update the DBUS interface
+                    makeDbusCall<std::string>(
+                        (INVENTORY_PATH +
+                         itemEEPROM["inventoryPath"]
+                             .get_ref<const nlohmann::json::string_t&>()),
+                        LOCATION_CODE_INF, "LocationCode", expandedLoctionCode);
+                }
+            }
+        }
+    }
+}
+
 void EditorImpl::updateKeyword(const Binary& kwdData)
 {
     vpdFileStream.open(vpdFilePath,