host-bmc: refine remote terminus functionality

This commit introduces support for migrating remote terminus-related
functionalities into the host-bmc directory, a move aimed at optimizing
remote terminus operations for future endeavors. By consolidating these
functionalities, tracking and implementing future enhancements become
more streamlined and manageable.

Change-Id: I52b6ced7acacb004b6055ae710193a959d986659
Signed-off-by: Kamalkumar Patel <kamalkumar.patel@ibm.com>
diff --git a/host-bmc/utils.cpp b/host-bmc/utils.cpp
new file mode 100644
index 0000000..f025ada
--- /dev/null
+++ b/host-bmc/utils.cpp
@@ -0,0 +1,208 @@
+#include "common/utils.hpp"
+
+#include "libpldm/entity.h"
+
+#include "utils.hpp"
+
+#include <iostream>
+
+namespace pldm
+{
+namespace hostbmc
+{
+namespace utils
+{
+Entities getParentEntites(const EntityAssociations& entityAssoc)
+{
+    Entities parents{};
+    for (const auto& et : entityAssoc)
+    {
+        parents.push_back(et[0]);
+    }
+
+    bool found = false;
+    for (auto it = parents.begin(); it != parents.end();
+         it = found ? parents.erase(it) : std::next(it))
+    {
+        uint16_t parent_contained_id =
+            pldm_entity_node_get_remote_container_id(*it);
+        found = false;
+        for (const auto& evs : entityAssoc)
+        {
+            for (size_t i = 1; i < evs.size() && !found; i++)
+            {
+                uint16_t node_contained_id =
+                    pldm_entity_node_get_remote_container_id(evs[i]);
+
+                pldm_entity parent_entity = pldm_entity_extract(*it);
+                pldm_entity node_entity = pldm_entity_extract(evs[i]);
+
+                if (node_entity.entity_type == parent_entity.entity_type &&
+                    node_entity.entity_instance_num ==
+                        parent_entity.entity_instance_num &&
+                    node_contained_id == parent_contained_id)
+                {
+                    found = true;
+                }
+            }
+            if (found)
+            {
+                break;
+            }
+        }
+    }
+
+    return parents;
+}
+
+void addObjectPathEntityAssociations(const EntityAssociations& entityAssoc,
+                                     pldm_entity_node* entity,
+                                     const fs::path& path,
+                                     ObjectPathMaps& objPathMap)
+{
+    if (entity == nullptr)
+    {
+        return;
+    }
+
+    bool found = false;
+    pldm_entity node_entity = pldm_entity_extract(entity);
+    if (!entityMaps.contains(node_entity.entity_type))
+    {
+        lg2::info(
+            "{ENTITY_TYPE} Entity fetched from remote PLDM terminal does not exist.",
+            "ENTITY_TYPE", (int)node_entity.entity_type);
+        return;
+    }
+
+    std::string entityName = entityMaps.at(node_entity.entity_type);
+    for (const auto& ev : entityAssoc)
+    {
+        pldm_entity ev_entity = pldm_entity_extract(ev[0]);
+        if (ev_entity.entity_instance_num == node_entity.entity_instance_num &&
+            ev_entity.entity_type == node_entity.entity_type)
+        {
+            uint16_t node_contained_id =
+                pldm_entity_node_get_remote_container_id(ev[0]);
+            uint16_t entity_contained_id =
+                pldm_entity_node_get_remote_container_id(entity);
+
+            if (node_contained_id != entity_contained_id)
+            {
+                continue;
+            }
+
+            fs::path p = path / fs::path{entityName +
+                                         std::to_string(
+                                             node_entity.entity_instance_num)};
+            std::string entity_path = p.string();
+            // If the entity obtained from the remote PLDM terminal is not in
+            // the MAP, or there is no auxiliary name PDR, add it directly.
+            // Otherwise, check whether the DBus service of entity_path exists,
+            // and overwrite the entity if it does not exist.
+            if (!objPathMap.contains(entity_path))
+            {
+                objPathMap[entity_path] = entity;
+            }
+            else
+            {
+                try
+                {
+                    pldm::utils::DBusHandler().getService(entity_path.c_str(),
+                                                          nullptr);
+                }
+                catch (const std::exception& e)
+                {
+                    objPathMap[entity_path] = entity;
+                }
+            }
+
+            for (size_t i = 1; i < ev.size(); i++)
+            {
+                addObjectPathEntityAssociations(entityAssoc, ev[i], p,
+                                                objPathMap);
+            }
+            found = true;
+        }
+    }
+
+    if (!found)
+    {
+        std::string dbusPath =
+            path / fs::path{entityName +
+                            std::to_string(node_entity.entity_instance_num)};
+
+        try
+        {
+            pldm::utils::DBusHandler().getService(dbusPath.c_str(), nullptr);
+        }
+        catch (const std::exception& e)
+        {
+            objPathMap[dbusPath] = entity;
+        }
+    }
+}
+
+void updateEntityAssociation(const EntityAssociations& entityAssoc,
+                             pldm_entity_association_tree* entityTree,
+                             ObjectPathMaps& objPathMap)
+{
+    std::vector<pldm_entity_node*> parentsEntity =
+        getParentEntites(entityAssoc);
+    for (const auto& entity : parentsEntity)
+    {
+        fs::path path{"/xyz/openbmc_project/inventory"};
+        std::deque<std::string> paths{};
+        pldm_entity node_entity = pldm_entity_extract(entity);
+        auto node = pldm_entity_association_tree_find_with_locality(
+            entityTree, &node_entity, false);
+        if (!node)
+        {
+            continue;
+        }
+
+        bool found = true;
+        while (node)
+        {
+            if (!pldm_entity_is_exist_parent(node))
+            {
+                break;
+            }
+
+            pldm_entity parent = pldm_entity_get_parent(node);
+            try
+            {
+                paths.push_back(entityMaps.at(parent.entity_type) +
+                                std::to_string(parent.entity_instance_num));
+            }
+            catch (const std::exception& e)
+            {
+                lg2::error(
+                    "Parent entity not found in the entityMaps, type: {ENTITY_TYPE}, num: {NUM}, e: {ERROR}",
+                    "ENTITY_TYPE", (int)parent.entity_type, "NUM",
+                    (int)parent.entity_instance_num, "ERROR", e);
+                found = false;
+                break;
+            }
+
+            node = pldm_entity_association_tree_find_with_locality(
+                entityTree, &parent, false);
+        }
+
+        if (!found)
+        {
+            continue;
+        }
+
+        while (!paths.empty())
+        {
+            path = path / fs::path{paths.back()};
+            paths.pop_back();
+        }
+
+        addObjectPathEntityAssociations(entityAssoc, entity, path, objPathMap);
+    }
+}
+} // namespace utils
+} // namespace hostbmc
+} // namespace pldm