EM: On duplicates use device index

For some platforms the PSU have the same address
but a different bus. To fix this, change the duplicate
names over to using index.

Tested: EM had no duplicate PSU numbers

Change-Id: Ibf9c7fe1b75a6420c858de194346433781d8f389
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/include/Utils.hpp b/include/Utils.hpp
index da3acce..58d4d42 100644
--- a/include/Utils.hpp
+++ b/include/Utils.hpp
@@ -124,8 +124,9 @@
     return false;
 }
 
-void templateCharReplace(
+std::optional<std::string> templateCharReplace(
     nlohmann::json::iterator& keyPair,
     const boost::container::flat_map<std::string, BasicVariantType>&
         foundDevice,
-    const size_t foundDeviceIdx);
+    const size_t foundDeviceIdx,
+    const std::optional<std::string>& replaceStr = std::nullopt);
\ No newline at end of file
diff --git a/src/EntityManager.cpp b/src/EntityManager.cpp
index 2f49e69..b1b5559 100644
--- a/src/EntityManager.cpp
+++ b/src/EntityManager.cpp
@@ -1286,12 +1286,13 @@
             [&, recordPtr, probeName](FoundDeviceT& foundDevices) {
                 _passed = true;
 
+                std::set<nlohmann::json> usedNames;
                 passedProbes.push_back(probeName);
                 std::list<size_t> indexes(foundDevices.size());
                 std::iota(indexes.begin(), indexes.end(), 1);
 
-                size_t indexIdx = probeName.find("$index");
-                bool hasIndex = (indexIdx != std::string::npos);
+                size_t indexIdx = probeName.find("$");
+                bool hasTemplateName = (indexIdx != std::string::npos);
 
                 // copy over persisted configurations and make sure we remove
                 // indexes that are already used
@@ -1323,7 +1324,7 @@
                         _systemConfiguration[recordName] = *fromLastJson;
                         _missingConfigurations.erase(recordName);
                         itr = foundDevices.erase(itr);
-                        if (hasIndex)
+                        if (hasTemplateName)
                         {
                             auto nameIt = fromLastJson->find("Name");
                             if (nameIt == fromLastJson->end())
@@ -1335,6 +1336,7 @@
                             int index = std::stoi(
                                 nameIt->get<std::string>().substr(indexIdx),
                                 nullptr, 0);
+                            usedNames.insert(nameIt.value());
                             auto usedIt = std::find(indexes.begin(),
                                                     indexes.end(), index);
 
@@ -1349,6 +1351,9 @@
                     }
                     itr++;
                 }
+
+                std::optional<std::string> replaceStr;
+
                 for (auto& foundDevice : foundDevices)
                 {
                     nlohmann::json record = *recordPtr;
@@ -1356,18 +1361,59 @@
                         getRecordName(foundDevice, probeName);
                     size_t foundDeviceIdx = indexes.front();
                     indexes.pop_front();
-                    // insert into configuration temporarily to be able to
-                    // reference ourselves
 
-                    _systemConfiguration[recordName] = record;
+                    // check name first so we have no duplicate names
+                    auto getName = record.find("Name");
+                    if (getName == record.end())
+                    {
+                        std::cerr << "Record Missing Name! " << record.dump();
+                        continue; // this should be impossible at this level
+                    }
+
+                    nlohmann::json copyForName = {{"Name", getName.value()}};
+                    nlohmann::json::iterator copyIt = copyForName.begin();
+                    std::optional<std::string> replaceVal = templateCharReplace(
+                        copyIt, foundDevice, foundDeviceIdx, replaceStr);
+
+                    if (!replaceStr && replaceVal)
+                    {
+                        if (usedNames.find(copyIt.value()) != usedNames.end())
+                        {
+                            replaceStr = replaceVal;
+                            copyForName = {{"Name", getName.value()}};
+                            copyIt = copyForName.begin();
+                            templateCharReplace(copyIt, foundDevice,
+                                                foundDeviceIdx, replaceStr);
+                        }
+                    }
+
+                    if (replaceStr)
+                    {
+                        std::cerr << "Duplicates found, replacing "
+                                  << *replaceStr
+                                  << " with found device index.\n Consider "
+                                     "fixing template to not have duplicates\n";
+                    }
 
                     for (auto keyPair = record.begin(); keyPair != record.end();
                          keyPair++)
                     {
+                        if (keyPair.key() == "Name")
+                        {
+                            keyPair.value() = copyIt.value();
+                            usedNames.insert(copyIt.value());
+
+                            continue; // already covered above
+                        }
                         templateCharReplace(keyPair, foundDevice,
-                                            foundDeviceIdx);
+                                            foundDeviceIdx, replaceStr);
                     }
 
+                    // insert into configuration temporarily to be able to
+                    // reference ourselves
+
+                    _systemConfiguration[recordName] = record;
+
                     auto findExpose = record.find("Exposes");
                     if (findExpose == record.end())
                     {
@@ -1382,7 +1428,7 @@
                         {
 
                             templateCharReplace(keyPair, foundDevice,
-                                                foundDeviceIdx);
+                                                foundDeviceIdx, replaceStr);
 
                             bool isBind =
                                 boost::starts_with(keyPair.key(), "Bind");
diff --git a/src/Utils.cpp b/src/Utils.cpp
index 81fa3d0..c92aabc 100644
--- a/src/Utils.cpp
+++ b/src/Utils.cpp
@@ -150,31 +150,39 @@
 // finds the template character (currently set to $) and replaces the value with
 // the field found in a dbus object i.e. $ADDRESS would get populated with the
 // ADDRESS field from a object on dbus
-void templateCharReplace(
+std::optional<std::string> templateCharReplace(
     nlohmann::json::iterator& keyPair,
     const boost::container::flat_map<std::string, BasicVariantType>&
         foundDevice,
-    const size_t foundDeviceIdx)
+    const size_t foundDeviceIdx, const std::optional<std::string>& replaceStr)
 {
+    std::optional<std::string> ret = std::nullopt;
+
     if (keyPair.value().type() == nlohmann::json::value_t::object ||
         keyPair.value().type() == nlohmann::json::value_t::array)
     {
         for (auto nextLayer = keyPair.value().begin();
              nextLayer != keyPair.value().end(); nextLayer++)
         {
-            templateCharReplace(nextLayer, foundDevice, foundDeviceIdx);
+            templateCharReplace(nextLayer, foundDevice, foundDeviceIdx,
+                                replaceStr);
         }
-        return;
+        return ret;
     }
 
     std::string* strPtr = keyPair.value().get_ptr<std::string*>();
     if (strPtr == nullptr)
     {
-        return;
+        return ret;
     }
 
     boost::replace_all(*strPtr, std::string(templateChar) + "index",
                        std::to_string(foundDeviceIdx));
+    if (replaceStr)
+    {
+        boost::replace_all(*strPtr, *replaceStr,
+                           std::to_string(foundDeviceIdx));
+    }
 
     for (auto& foundDevicePair : foundDevice)
     {
@@ -193,7 +201,7 @@
             {
                 std::visit([&](auto&& val) { keyPair.value() = val; },
                            foundDevicePair.second);
-                return;
+                return ret;
             }
             else if (nextItemIdx > strPtr->size() ||
                      std::find(mathChars.begin(), mathChars.end(),
@@ -315,8 +323,21 @@
                 }
                 isOperator = !isOperator;
             }
+
             std::string result = prefix + std::to_string(number);
 
+            std::string replaced(find.begin(), find.end());
+            for (auto it2 = split.begin(); it2 != split.end(); it2++)
+            {
+                replaced += " ";
+                replaced += *it2;
+                if (it2 == it)
+                {
+                    break;
+                }
+            }
+            ret = replaced;
+
             if (it != split.end())
             {
                 for (; it != split.end(); it++)
@@ -335,7 +356,7 @@
     strPtr = keyPair.value().get_ptr<std::string*>();
     if (strPtr == nullptr)
     {
-        return;
+        return ret;
     }
 
     // convert hex numbers to ints
@@ -369,4 +390,5 @@
         {
         }
     }
+    return ret;
 }