topology: get opposite association

Introduce function getOppositeAssoc to get the opposite association
instead of hardcoding it.

For example powering -> powered_by.

Tested: Topology Unit Tests Pass

Change-Id: I2b902c7e5bd7d7bcc124b4c8f25e2dd14200c6bb
Signed-off-by: Alexander Hansen <alexander.hansen@9elements.com>
diff --git a/src/entity_manager/topology.cpp b/src/entity_manager/topology.cpp
index d2f7f33..8f7b7b1 100644
--- a/src/entity_manager/topology.cpp
+++ b/src/entity_manager/topology.cpp
@@ -101,14 +101,52 @@
         return;
     }
 
-    result[downstream].insert({"contained_by", "containing", upstream});
+    std::string assoc = "contained_by";
+    std::optional<std::string> opposite = getOppositeAssoc(assoc);
+
+    if (!opposite.has_value())
+    {
+        return;
+    }
+
+    result[downstream].insert({assoc, opposite.value(), upstream});
 
     if (powerPaths.contains(downstream))
     {
-        result[downstream].insert({"powering", "powered_by", upstream});
+        assoc = "powering";
+        opposite = getOppositeAssoc(assoc);
+        if (!opposite.has_value())
+        {
+            return;
+        }
+
+        result[downstream].insert({assoc, opposite.value(), upstream});
     }
 }
 
+const std::set<std::pair<std::string, std::string>> assocs = {
+    {"powering", "powered_by"}, {"containing", "contained_by"},
+    // ... extend as needed
+};
+
+std::optional<std::string> Topology::getOppositeAssoc(
+    const AssocName& assocName)
+{
+    for (const auto& entry : assocs)
+    {
+        if (entry.first == assocName)
+        {
+            return entry.second;
+        }
+        if (entry.second == assocName)
+        {
+            return entry.first;
+        }
+    }
+
+    return std::nullopt;
+}
+
 void Topology::remove(const std::string& boardName)
 {
     // Remove the board from boardNames, and then using the path
diff --git a/src/entity_manager/topology.hpp b/src/entity_manager/topology.hpp
index c912d42..39dcae7 100644
--- a/src/entity_manager/topology.hpp
+++ b/src/entity_manager/topology.hpp
@@ -30,6 +30,9 @@
 
     void addDownstreamPort(const Path& path, const nlohmann::json& exposesItem);
 
+    // e.g. contained_by, containing, powered_by, ...
+    using AssocName = std::string;
+
     // @brief: fill associations map with the associations for a port identifier
     // such as 'MB Upstream Port'
     void fillAssocsForPortId(
@@ -42,6 +45,9 @@
         BoardPathsView boardPaths, const Path& upstream,
         const Path& downstream);
 
+    static std::optional<std::string> getOppositeAssoc(
+        const AssocName& assocName);
+
     std::unordered_map<PortType, std::set<Path>> upstreamPorts;
     std::unordered_map<PortType, std::set<Path>> downstreamPorts;
     std::set<Path> powerPaths;