Files
BCIgui/Masterarbeit/openvibe/sdk-master/kernel/src/kernel/scenario/ovkCScenario.cpp
T
2021-10-14 13:47:35 +02:00

1461 lines
52 KiB
C++
Executable File

#include "ovkCScenario.h"
#include "ovkCScenarioSettingKeywordParserCallback.h"
#include "ovkTBox.hpp"
#include "ovkCBoxUpdater.h"
#include "ovkCComment.h"
#include "ovkCMetadata.h"
#include "ovkCLink.h"
#include "../ovkCObjectVisitorContext.h"
#include "../../tools/ovk_setting_checker.h"
#include <iostream>
#include <cstdlib>
#include <algorithm>
#define OV_AttributeId_Box_Disabled OpenViBE::CIdentifier(0x341D3912, 0x1478DE86)
#define OVD_AttributeId_SettingOverrideFilename OpenViBE::CIdentifier(0x8D21FF41, 0xDF6AFE7E)
// The following is a hack, can be removed once there is a copy constructor for scenarios, boxes, etc
#include <ovp_global_defines.h>
//___________________________________________________________________//
// //
namespace OpenViBE {
namespace Kernel {
namespace {
template <class T>
struct STestTrue
{
bool operator()(typename std::map<CIdentifier, T>::const_iterator /*it*/) const { return true; }
};
struct STestEqSourceBox
{
explicit STestEqSourceBox(const CIdentifier& boxId) : m_BoxId(boxId) { }
bool operator()(const std::map<CIdentifier, CLink*>::const_iterator& it) const { return it->second->getSourceBoxIdentifier() == m_BoxId; }
const CIdentifier& m_BoxId;
};
struct STestEqSourceBoxOutput
{
STestEqSourceBoxOutput(const CIdentifier& boxId, const size_t index) : m_BoxId(boxId), m_OutputIdx(index) { }
bool operator()(const std::map<CIdentifier, CLink*>::const_iterator& it) const
{
return it->second->getSourceBoxIdentifier() == m_BoxId && it->second->getSourceBoxOutputIndex() == m_OutputIdx;
}
const CIdentifier& m_BoxId;
size_t m_OutputIdx;
};
struct STestEqTargetBox
{
explicit STestEqTargetBox(const CIdentifier& boxId) : m_BoxId(boxId) { }
bool operator()(const std::map<CIdentifier, CLink*>::const_iterator& it) const { return it->second->getTargetBoxIdentifier() == m_BoxId; }
const CIdentifier& m_BoxId;
};
struct STestEqTargetBoxInput
{
STestEqTargetBoxInput(const CIdentifier& boxId, const size_t index) : m_BoxId(boxId), m_InputIdx(index) { }
bool operator()(const std::map<CIdentifier, CLink*>::const_iterator& it) const
{
return it->second->getTargetBoxIdentifier() == m_BoxId && it->second->getTargetBoxInputIndex() == m_InputIdx;
}
const CIdentifier& m_BoxId;
size_t m_InputIdx;
};
template <class T, class TTest>
CIdentifier getNextID(const std::map<CIdentifier, T>& elementMap, const CIdentifier& previousID, const TTest& testFunctor)
{
typename std::map<CIdentifier, T>::const_iterator it;
if (previousID == CIdentifier::undefined()) { it = elementMap.begin(); }
else
{
it = elementMap.find(previousID);
if (it == elementMap.end()) { return CIdentifier::undefined(); }
++it;
}
while (it != elementMap.end())
{
if (testFunctor(it)) { return it->first; }
++it;
}
return CIdentifier::undefined();
}
/*
template <class T, class TTest>
CIdentifier getNextID(const std::map<CIdentifier, T*>& elementMap, const CIdentifier& previousID, const TTest& testFunctor)
{
typename std::map<CIdentifier, T*>::const_iterator it;
if(previousID==CIdentifier::undefined())
{
it=elementMap.begin();
}
else
{
it=elementMap.find(previousID);
if(it==elementMap.end()) { return CIdentifier::undefined(); }
++it;
}
while(it!=elementMap.end())
{
if(testFunctor(it)) { return it->first; }
++it;
}
return CIdentifier::undefined();
}
*/
} // namespace
//___________________________________________________________________//
// //
CScenario::CScenario(const IKernelContext& ctx, const CIdentifier& identifier) : TBox<IScenario>(ctx), m_firstMetadataID(CIdentifier::undefined())
{
// Some operations on boxes manipulate the owner scenario, for example removing inputs
// by default we set the scenario as owning itself to avoid segfaults
this->setOwnerScenario(this);
this->m_identifier = identifier;
}
//___________________________________________________________________//
// //
bool CScenario::clear()
{
this->getLogManager() << LogLevel_Debug << "Clearing scenario\n";
for (auto& box : m_boxes) { delete box.second; }
m_boxes.clear();
for (auto& comment : m_comments) { delete comment.second; }
m_comments.clear();
for (auto& metadata : m_metadatas) { delete metadata.second; }
m_metadatas.clear();
m_firstMetadataID = CIdentifier::undefined();
m_nextMetadataID.clear();
for (auto& link : m_links) { delete link.second; }
m_links.clear();
m_outdatedBoxes.clear();
while (this->getSettingCount()) { this->removeSetting(0); }
while (this->getInputCount()) { this->removeScenarioInput(0); }
while (this->getOutputCount()) { this->removeScenarioOutput(0); }
this->removeAllAttributes();
return true;
}
bool CScenario::removeScenarioInput(const size_t index)
{
OV_ERROR_UNLESS_KRF(index < this->getInputCount(), "Input index = [" << index << "] is out of range (max index = [" << (this->getInputCount() - 1) << "])",
ErrorType::OutOfBound);
this->removeInput(index);
// Remove the link within the scenario to this input
if (index < m_scenarioInputLinks.size()) { m_scenarioInputLinks.erase(m_scenarioInputLinks.begin() + index); }
return true;
}
bool CScenario::removeScenarioOutput(const size_t index)
{
OV_ERROR_UNLESS_KRF(index < this->getOutputCount(),
"Output index = [" << index << "] is out of range (max index = [" << (this->getOutputCount() - 1) << "])",
Kernel::ErrorType::OutOfBound);
this->removeOutput(index);
// Remove the link within the scenario to this output
if (index < m_scenarioOutputLinks.size()) { m_scenarioOutputLinks.erase(m_scenarioOutputLinks.begin() + index); }
return true;
}
bool CScenario::merge(const IScenario& scenario, IScenarioMergeCallback* scenarioMergeCallback, const bool mergeSettings, const bool preserveIDs)
{
std::map<CIdentifier, CIdentifier> oldToNewIdMap;
// Copy boxes
{
CIdentifier* listID = nullptr;
size_t nbElems = 0;
scenario.getBoxIdentifierList(&listID, &nbElems);
for (size_t i = 0; i < nbElems; ++i)
{
CIdentifier boxID = listID[i];
const IBox* box = scenario.getBoxDetails(boxID);
CIdentifier newID;
CIdentifier suggestedNewID = preserveIDs ? box->getIdentifier() : CIdentifier::undefined();
this->addBox(newID, *box, suggestedNewID);
oldToNewIdMap[boxID] = newID;
if (scenarioMergeCallback) { scenarioMergeCallback->process(boxID, newID); }
}
scenario.releaseIdentifierList(listID);
}
// Copy links
{
CIdentifier* listID = nullptr;
size_t nbElems = 0;
scenario.getLinkIdentifierList(&listID, &nbElems);
for (size_t i = 0; i < nbElems; ++i)
{
CIdentifier linkID = listID[i];
const ILink* link = scenario.getLinkDetails(linkID);
CIdentifier newID;
this->connect(newID, oldToNewIdMap[link->getSourceBoxIdentifier()],
link->getSourceBoxOutputIndex(), oldToNewIdMap[link->getTargetBoxIdentifier()],
link->getTargetBoxInputIndex(), CIdentifier::undefined());
if (scenarioMergeCallback) { scenarioMergeCallback->process(linkID, newID); }
}
scenario.releaseIdentifierList(listID);
}
// Copy comments
// Copy metadata
{
CIdentifier* listID = nullptr;
size_t nbElems = 0;
scenario.getMetadataIdentifierList(&listID, &nbElems);
for (size_t i = 0; i < nbElems; ++i)
{
CIdentifier metadataID = listID[i];
const IMetadata* metadata = scenario.getMetadataDetails(metadataID);
CIdentifier newID;
CIdentifier suggestedNewID = preserveIDs ? metadataID : CIdentifier::undefined();
this->addMetadata(newID, suggestedNewID);
IMetadata* newMetadata = this->getMetadataDetails(newID);
newMetadata->initializeFromExistingMetadata(*metadata);
}
scenario.releaseIdentifierList(listID);
}
// Copy settings if requested
const size_t previousSettingCount = this->getSettingCount();
if (mergeSettings)
{
for (size_t i = 0; i < scenario.getSettingCount(); ++i)
{
CIdentifier typeID;
CString name;
CString defaultValue;
CString value;
bool isModifiable;
CIdentifier id;
scenario.getSettingType(i, typeID);
scenario.getSettingName(i, name);
scenario.getSettingDefaultValue(i, defaultValue);
scenario.getSettingValue(i, value);
scenario.getSettingMod(i, isModifiable);
scenario.getInterfacorIdentifier(Setting, i, id);
this->addSetting(name, typeID, defaultValue, size_t(-1), isModifiable, id, true);
this->setSettingValue(previousSettingCount + i, value);
}
// In this case we also merge the attributes
CIdentifier attributeIdentifier;
while ((attributeIdentifier = scenario.getNextAttributeIdentifier(attributeIdentifier)) != CIdentifier::undefined())
{
CString attributeValue = scenario.getAttributeValue(attributeIdentifier);
this->addAttribute(attributeIdentifier, attributeValue);
}
}
return true;
}
//___________________________________________________________________//
// //
CIdentifier CScenario::getNextBoxIdentifier(const CIdentifier& previousID) const
{
return getNextID<CBox*, STestTrue<CBox*>>(m_boxes, previousID, STestTrue<CBox*>());
}
const IBox* CScenario::getBoxDetails(const CIdentifier& boxID) const
{
const auto it = m_boxes.find(boxID);
OV_ERROR_UNLESS_KRN(it != m_boxes.end(), "Box [" << boxID.str() << "] is not part of the scenario", Kernel::ErrorType::ResourceNotFound);
return it->second;
}
bool CScenario::isBox(const CIdentifier& boxID) const { return m_boxes.count(boxID) == 1; }
IBox* CScenario::getBoxDetails(const CIdentifier& boxID)
{
// this->getLogManager() << Kernel::LogLevel_Debug << "Getting box details from scenario\n";
const auto it = m_boxes.find(boxID);
OV_ERROR_UNLESS_KRN(it != m_boxes.end(), "Box [" << boxID.str() << "] is not part of the scenario", Kernel::ErrorType::ResourceNotFound);
return it->second;
}
bool CScenario::addBox(CIdentifier& boxID, const CIdentifier& suggestedBoxID)
{
boxID = getUnusedIdentifier(suggestedBoxID);
CBox* box = new CBox(this->getKernelContext());
box->setOwnerScenario(this);
box->setIdentifier(boxID);
m_boxes[boxID] = box;
return true;
}
bool CScenario::addBox(CIdentifier& boxID, const IBox& box, const CIdentifier& suggestedBoxID)
{
if (!addBox(boxID, suggestedBoxID))
{
// error is handled in addBox
return false;
}
IBox* newBox = getBoxDetails(boxID);
if (!newBox)
{
// error is handled in getBoxDetails
return false;
}
return newBox->initializeFromExistingBox(box);
}
bool CScenario::addBox(CIdentifier& boxID, const CIdentifier& boxAlgorithmID, const CIdentifier& suggestedBoxID)
{
if (!addBox(boxID, suggestedBoxID))
{
// error is handled in addBox
return false;
}
IBox* newBox = getBoxDetails(boxID);
if (!newBox)
{
// error is handled in getBoxDetails
return false;
}
return newBox->initializeFromAlgorithmClassIdentifier(boxAlgorithmID);
}
bool CScenario::addBox(CIdentifier& boxID, const Plugins::IBoxAlgorithmDesc& boxAlgorithmDesc, const CIdentifier& suggestedBoxID)
{
if (!addBox(boxID, suggestedBoxID))
{
// error is handled in addBox
return false;
}
IBox* newBox = getBoxDetails(boxID);
if (!newBox)
{
// error is handled in getBoxDetails
return false;
}
return dynamic_cast<CBox*>(newBox)->initializeFromBoxAlgorithmDesc(boxAlgorithmDesc);
}
bool CScenario::removeBox(const CIdentifier& boxID)
{
// Finds the box according to its identifier
auto itBox = m_boxes.find(boxID);
OV_ERROR_UNLESS_KRF(itBox != m_boxes.end(), "Box [" << boxID.str() << "] is not part of the scenario", Kernel::ErrorType::ResourceNotFound);
// Find all the links that are used by this box
auto itLink = m_links.begin();
while (itLink != m_links.end())
{
auto itLinkCurrent = itLink;
++itLink;
if (itLinkCurrent->second->getSourceBoxIdentifier() == boxID || itLinkCurrent->second->getTargetBoxIdentifier() == boxID)
{
// Deletes this link
delete itLinkCurrent->second;
// Removes link from the link list
m_links.erase(itLinkCurrent);
}
}
// Deletes the box itself
delete itBox->second;
// Removes box from the box list
m_boxes.erase(itBox);
return true;
}
//___________________________________________________________________//
CIdentifier CScenario::getNextCommentIdentifier(const CIdentifier& previousID) const
{
return getNextID<CComment*, STestTrue<CComment*>>(m_comments, previousID, STestTrue<CComment*>());
}
const IComment* CScenario::getCommentDetails(const CIdentifier& commentID) const
{
const auto it = m_comments.find(commentID);
OV_ERROR_UNLESS_KRN(it != m_comments.end(), "Comment [" << commentID.str() << "] is not part of the scenario", Kernel::ErrorType::ResourceNotFound);
return it->second;
}
bool CScenario::isComment(const CIdentifier& commentID) const { return m_comments.find(commentID) != m_comments.end(); }
IComment* CScenario::getCommentDetails(const CIdentifier& commentID)
{
const auto it = m_comments.find(commentID);
OV_ERROR_UNLESS_KRN(it != m_comments.end(), "Comment [" << commentID.str() << "] is not part of the scenario", Kernel::ErrorType::ResourceNotFound);
return it->second;
}
bool CScenario::addComment(CIdentifier& commentID, const CIdentifier& suggestedCommentID)
{
commentID = getUnusedIdentifier(suggestedCommentID);
CComment* newComment = new CComment(this->getKernelContext(), *this);
newComment->setIdentifier(commentID);
m_comments[commentID] = newComment;
return true;
}
bool CScenario::addComment(CIdentifier& commentID, const IComment& comment, const CIdentifier& suggestedCommentID)
{
if (!addComment(commentID, suggestedCommentID))
{
// error is handled in addComment above
return false;
}
IComment* newComment = getCommentDetails(commentID);
if (!newComment)
{
// error is handled in getCommentDetails
return false;
}
return newComment->initializeFromExistingComment(comment);
}
bool CScenario::removeComment(const CIdentifier& commentID)
{
// Finds the comment according to its identifier
auto it = m_comments.find(commentID);
OV_ERROR_UNLESS_KRF(it != m_comments.end(), "Comment [" << commentID.str() << "] is not part of the scenario", Kernel::ErrorType::ResourceNotFound);
delete it->second; // Deletes the comment itself
m_comments.erase(it); // Removes comment from the comment list
return true;
}
CIdentifier CScenario::getNextMetadataIdentifier(const CIdentifier& previousID) const
{
if (previousID == CIdentifier::undefined()) { return m_firstMetadataID; }
if (m_metadatas.count(previousID) == 0) { return CIdentifier::undefined(); }
return m_nextMetadataID.at(previousID);
}
const IMetadata* CScenario::getMetadataDetails(const CIdentifier& metadataID) const
{
const auto it = m_metadatas.find(metadataID);
OV_ERROR_UNLESS_KRN(it != m_metadatas.end(), "Metadata [" << metadataID.str() << "] is not part of the scenario", Kernel::ErrorType::ResourceNotFound);
return it->second;
}
IMetadata* CScenario::getMetadataDetails(const CIdentifier& metadataID)
{
const auto it = m_metadatas.find(metadataID);
OV_ERROR_UNLESS_KRN(it != m_metadatas.end(), "Metadata [" << metadataID.str() << "] is not part of the scenario", Kernel::ErrorType::ResourceNotFound);
return it->second;
}
bool CScenario::isMetadata(const CIdentifier& metadataID) const { return m_metadatas.count(metadataID) > 0; }
bool CScenario::addMetadata(CIdentifier& metadataID, const CIdentifier& suggestedMetadataID)
{
metadataID = getUnusedIdentifier(suggestedMetadataID);
CMetadata* metadata = new CMetadata(this->getKernelContext(), *this);
metadata->setIdentifier(metadataID);
m_nextMetadataID[metadataID] = m_firstMetadataID;
m_firstMetadataID = metadataID;
m_metadatas[metadataID] = metadata;
return true;
}
bool CScenario::removeMetadata(const CIdentifier& metadataID)
{
// Finds the comment according to its identifier
auto itMetadata = m_metadatas.find(metadataID);
OV_ERROR_UNLESS_KRF(itMetadata != m_metadatas.end(), "Comment [" << metadataID.str() << "] is not part of the scenario",
Kernel::ErrorType::ResourceNotFound);
// Deletes the metadata and remove it from the cache
delete itMetadata->second;
m_metadatas.erase(itMetadata);
if (metadataID == m_firstMetadataID)
{
m_firstMetadataID = m_nextMetadataID[m_firstMetadataID];
m_nextMetadataID.erase(metadataID);
}
else
{
const auto previousID = std::find_if(m_nextMetadataID.begin(), m_nextMetadataID.end(), [metadataID](const std::pair<CIdentifier, CIdentifier>& v)
{
return v.second == metadataID;
});
OV_FATAL_UNLESS_K(previousID != m_nextMetadataID.end(), "Removing metadata [" << metadataID << "] which is not in the cache ",
Kernel::ErrorType::Internal);
m_nextMetadataID[previousID->first] = m_nextMetadataID[metadataID];
m_nextMetadataID.erase(metadataID);
}
return true;
}
// Links
CIdentifier CScenario::getNextLinkIdentifier(const CIdentifier& previousID) const
{
return getNextID<CLink*, STestTrue<CLink*>>(m_links, previousID, STestTrue<CLink*>());
}
CIdentifier CScenario::getNextLinkIdentifierFromBox(const CIdentifier& previousID, const CIdentifier& boxID) const
{
return getNextID<CLink*, STestEqSourceBox>(m_links, previousID, STestEqSourceBox(boxID));
}
CIdentifier CScenario::getNextLinkIdentifierFromBoxOutput(const CIdentifier& previousID, const CIdentifier& boxID, const size_t index) const
{
return getNextID<CLink*, STestEqSourceBoxOutput>(m_links, previousID, STestEqSourceBoxOutput(boxID, index));
}
CIdentifier CScenario::getNextLinkIdentifierToBox(const CIdentifier& previousID, const CIdentifier& boxID) const
{
return getNextID<CLink*, STestEqTargetBox>(m_links, previousID, STestEqTargetBox(boxID));
}
CIdentifier CScenario::getNextLinkIdentifierToBoxInput(const CIdentifier& previousID, const CIdentifier& boxID, const size_t index) const
{
return getNextID<CLink*, STestEqTargetBoxInput>(m_links, previousID, STestEqTargetBoxInput(boxID, index));
}
bool CScenario::isLink(const CIdentifier& boxID) const
{
const auto itLink = m_links.find(boxID);
return itLink != m_links.end();
}
bool CScenario::setHasIO(const bool hasIO)
{
m_hasIO = hasIO;
return true;
}
bool CScenario::hasIO() const { return m_hasIO; }
bool CScenario::setScenarioInputLink(const size_t scenarioInputIdx, const CIdentifier& boxID, const size_t boxInputIdx)
{
if (boxID != CIdentifier::undefined())
{
OV_ERROR_UNLESS_KRF(
scenarioInputIdx < this->getInputCount(),
"Scenario Input index = [" << scenarioInputIdx << "] is out of range (max index = [" << (this->getInputCount() - 1) << "])",
ErrorType::OutOfBound);
OV_ERROR_UNLESS_KRF(
this->isBox(boxID),
"Box [" << boxID.str() << "] is not part of the scenario",
ErrorType::ResourceNotFound);
OV_ERROR_UNLESS_KRF(
boxInputIdx < this->getBoxDetails(boxID)->getInputCount(),
"Box Input index = [" << boxInputIdx << "] is out of range (max index = [" << (this->getBoxDetails(boxID)->getInputCount() - 1) << "])",
ErrorType::OutOfBound);
}
if (scenarioInputIdx >= m_scenarioInputLinks.size()) { m_scenarioInputLinks.resize(this->getInputCount()); }
// Remove any existing inputs connected to the target
for (size_t i = 0; i < m_scenarioInputLinks.size(); ++i)
{
CIdentifier id;
size_t index;
this->getScenarioInputLink(i, id, index);
if (id == boxID && index == boxInputIdx) { this->removeScenarioInputLink(i, id, index); }
}
// Remove any existing link to this input
for (auto& kv : m_links)
{
CIdentifier linkID = kv.first;
const CLink* link = kv.second;
if (link->getTargetBoxIdentifier() == boxID && link->getTargetBoxInputIndex() == boxInputIdx) { this->disconnect(linkID); }
}
m_scenarioInputLinks[scenarioInputIdx] = std::make_pair(boxID, boxInputIdx);
return true;
}
bool CScenario::setScenarioInputLink(const size_t scenarioInputIdx, const CIdentifier& boxID, const CIdentifier& boxInputID)
{
size_t boxInputIdx = size_t(-1);
if (boxID != CIdentifier::undefined())
{
OV_ERROR_UNLESS_KRF(this->isBox(boxID), "Box [" << boxID.str() << "] is not part of the scenario", Kernel::ErrorType::ResourceNotFound);
this->getBoxDetails(boxID)->getInterfacorIndex(Input, boxInputID, boxInputIdx);
}
return this->setScenarioInputLink(scenarioInputIdx, boxID, boxInputIdx);
}
bool CScenario::setScenarioOutputLink(const size_t scenarioOutputIdx, const CIdentifier& boxID, const size_t boxOutputIdx)
{
if (boxID != CIdentifier::undefined())
{
OV_ERROR_UNLESS_KRF(scenarioOutputIdx < this->getOutputCount(),
"Scenario output index = [" << scenarioOutputIdx << "] is out of range (max index = [" << (this->getOutputCount() - 1) << "])",
ErrorType::OutOfBound);
OV_ERROR_UNLESS_KRF(this->isBox(boxID),
"Box [" << boxID.str() << "] is not part of the scenario",
ErrorType::ResourceNotFound);
OV_ERROR_UNLESS_KRF(boxOutputIdx < this->getBoxDetails(boxID)->getOutputCount(),
"Box output index = [" << boxOutputIdx << "] is out of range (max index = [" << (this->getBoxDetails(boxID)->getOutputCount() - 1)
<< "])",
ErrorType::OutOfBound);
}
if (scenarioOutputIdx >= m_scenarioOutputLinks.size()) { m_scenarioOutputLinks.resize(this->getOutputCount()); }
// Remove any existing outputs connected to the target
for (size_t i = 0; i < m_scenarioOutputLinks.size(); ++i)
{
CIdentifier id;
size_t index;
this->getScenarioOutputLink(i, id, index);
if (id == boxID && index == boxOutputIdx) { this->removeScenarioOutputLink(i, id, index); }
}
m_scenarioOutputLinks[scenarioOutputIdx] = std::make_pair(boxID, boxOutputIdx);
return true;
}
bool CScenario::setScenarioOutputLink(const size_t scenarioOutputIdx, const CIdentifier& boxID, const CIdentifier& boxOutputID)
{
size_t boxOutputIdx = size_t(-1);
if (boxID != CIdentifier::undefined())
{
OV_ERROR_UNLESS_KRF(this->isBox(boxID), "Box [" << boxID.str() << "] is not part of the scenario", Kernel::ErrorType::ResourceNotFound);
this->getBoxDetails(boxID)->getInterfacorIndex(Output, boxOutputID, boxOutputIdx);
}
return this->setScenarioOutputLink(scenarioOutputIdx, boxID, boxOutputIdx);
}
bool CScenario::getScenarioInputLink(const size_t scenarioInputIdx, CIdentifier& boxID, size_t& boxInputIdx) const
{
OV_ERROR_UNLESS_KRF(scenarioInputIdx < this->getInputCount(),
"Scenario input index = [" << scenarioInputIdx << "] is out of range (max index = [" << (this->getInputCount() - 1) << "])",
ErrorType::OutOfBound);
if (scenarioInputIdx >= m_scenarioInputLinks.size()) { m_scenarioInputLinks.resize(this->getInputCount()); }
boxID = m_scenarioInputLinks[scenarioInputIdx].first;
boxInputIdx = m_scenarioInputLinks[scenarioInputIdx].second;
return true;
}
bool CScenario::getScenarioInputLink(const size_t scenarioInputIdx, CIdentifier& boxID, CIdentifier& boxOutputID) const
{
size_t index;
boxOutputID = CIdentifier::undefined();
this->getScenarioInputLink(scenarioInputIdx, boxID, index);
if (boxID != CIdentifier::undefined())
{
if (m_boxes.find(boxID) != m_boxes.end()) { this->getBoxDetails(boxID)->getInterfacorIdentifier(Input, index, boxOutputID); }
}
return true;
}
bool CScenario::getScenarioOutputLink(const size_t scenarioOutputIdx, CIdentifier& boxID, size_t& boxOutputIdx) const
{
OV_ERROR_UNLESS_KRF(scenarioOutputIdx < this->getOutputCount(),
"Scenario output index = [" << scenarioOutputIdx << "] is out of range (max index = [" << (this->getOutputCount() - 1) << "])",
ErrorType::OutOfBound);
if (scenarioOutputIdx >= m_scenarioOutputLinks.size()) { m_scenarioOutputLinks.resize(this->getOutputCount()); }
boxID = m_scenarioOutputLinks[scenarioOutputIdx].first;
boxOutputIdx = m_scenarioOutputLinks[scenarioOutputIdx].second;
return true;
}
bool CScenario::getScenarioOutputLink(const size_t scenarioOutputIdx, CIdentifier& boxID, CIdentifier& boxOutputID) const
{
size_t index;
boxOutputID = CIdentifier::undefined();
this->getScenarioOutputLink(scenarioOutputIdx, boxID, index);
if (boxID != CIdentifier::undefined())
{
if (m_boxes.find(boxID) != m_boxes.end()) { this->getBoxDetails(boxID)->getInterfacorIdentifier(Output, index, boxOutputID); }
}
return true;
}
// Note: In current implementation only the scenarioInputIdx is necessary as it can only be connected to one input
// but to keep things simpler we give it all the info
bool CScenario::removeScenarioInputLink(const size_t scenarioInputIdx, const CIdentifier& boxID, const size_t boxInputIdx)
{
if (boxID != CIdentifier::undefined())
{
OV_ERROR_UNLESS_KRF(scenarioInputIdx < this->getInputCount(),
"Scenario Input index = [" << scenarioInputIdx << "] is out of range (max index = [" << (this->getInputCount() - 1) << "])",
ErrorType::OutOfBound);
OV_ERROR_UNLESS_KRF(this->isBox(boxID), "Box [" << boxID.str() << "] is not part of the scenario", Kernel::ErrorType::ResourceNotFound);
OV_ERROR_UNLESS_KRF(boxInputIdx < this->getBoxDetails(boxID)->getInputCount(),
"Box Input index = [" << boxInputIdx << "] is out of range (max index = [" << (this->getBoxDetails(boxID)->getInputCount() - 1) <<
"])",
ErrorType::OutOfBound);
}
// This should not happen either
if (scenarioInputIdx >= m_scenarioInputLinks.size()) { m_scenarioInputLinks.resize(this->getInputCount()); }
m_scenarioInputLinks[scenarioInputIdx] = std::make_pair(CIdentifier::undefined(), 0);
return true;
}
// Note: In current implementation only the scenarioOutputIdx is necessary as it can only be connected to one Output
// but to keep things simpler we give it all the info
bool CScenario::removeScenarioOutputLink(const size_t scenarioOutputIdx, const CIdentifier& boxID, const size_t boxOutputIdx)
{
if (boxID != CIdentifier::undefined())
{
OV_ERROR_UNLESS_KRF(scenarioOutputIdx < this->getOutputCount(),
"Scenario output index = [" << scenarioOutputIdx << "] is out of range (max index = [" << (this->getOutputCount() - 1) << "])",
ErrorType::OutOfBound);
OV_ERROR_UNLESS_KRF(this->isBox(boxID), "Box [" << boxID.str() << "] is not part of the scenario", Kernel::ErrorType::ResourceNotFound);
OV_ERROR_UNLESS_KRF(boxOutputIdx < this->getBoxDetails(boxID)->getOutputCount(),
"Box output index = [" << boxOutputIdx << "] is out of range (max index = [" << (this->getBoxDetails(boxID)->getOutputCount() - 1)
<< "])",
ErrorType::OutOfBound);
}
// This should not happen either
if (scenarioOutputIdx >= m_scenarioOutputLinks.size()) { m_scenarioOutputLinks.resize(this->getOutputCount()); }
m_scenarioOutputLinks[scenarioOutputIdx] = std::make_pair(CIdentifier::undefined(), 0);
return true;
}
const ILink* CScenario::getLinkDetails(const CIdentifier& linkID) const
{
const auto it = m_links.find(linkID);
OV_ERROR_UNLESS_KRN(it != m_links.end(), "link [" << linkID.str() << "] is not part of the scenario", Kernel::ErrorType::ResourceNotFound);
return it->second;
}
ILink* CScenario::getLinkDetails(const CIdentifier& linkID)
{
const auto it = m_links.find(linkID);
OV_ERROR_UNLESS_KRN(it != m_links.end(), "Link [" << linkID.str() << "] is not part of the scenario", Kernel::ErrorType::ResourceNotFound);
return it->second;
}
bool CScenario::connect(CIdentifier& linkID, const CIdentifier& srcBoxID, const size_t srcBoxOutputIdx,
const CIdentifier& dstBoxID, const size_t dstBoxInputIdx, const CIdentifier& suggestedLinkID)
{
const auto itBox1 = m_boxes.find(srcBoxID);
const auto itBox2 = m_boxes.find(dstBoxID);
OV_ERROR_UNLESS_KRF(itBox1 != m_boxes.end(), "Source Box [" << srcBoxID.str() << "] is not part of the scenario", Kernel::ErrorType::ResourceNotFound);
OV_ERROR_UNLESS_KRF(itBox2 != m_boxes.end(), "Target Box [" << dstBoxID.str() << "] is not part of the scenario", Kernel::ErrorType::ResourceNotFound);
CBox* srcBox = itBox1->second;
CBox* dstBox = itBox2->second;
OV_ERROR_UNLESS_KRF(dstBoxInputIdx < dstBox->getInterfacorCountIncludingDeprecated(Input),
"Target box input index = [" << dstBoxInputIdx << "] is out of range (max index = [" << (dstBox->getInputCount() - 1) << "])",
ErrorType::OutOfBound);
OV_ERROR_UNLESS_KRF(srcBoxOutputIdx < srcBox->getInterfacorCountIncludingDeprecated(Output),
"Source box output index = [" << srcBoxOutputIdx << "] is out of range (max index = [" << (srcBox->getOutputCount() - 1) << "])",
ErrorType::OutOfBound);
// Looks for any connected link to this box input and removes it
auto itLink = m_links.begin();
while (itLink != m_links.end())
{
const auto itLinkCurrent = itLink;
++itLink;
CLink* link = itLinkCurrent->second;
if (link)
{
if (link->getTargetBoxIdentifier() == dstBoxID && link->getTargetBoxInputIndex() == dstBoxInputIdx)
{
delete link;
m_links.erase(itLinkCurrent);
}
}
}
linkID = getUnusedIdentifier(suggestedLinkID);
CLink* link = new CLink(this->getKernelContext(), *this);
CIdentifier srcBoxOutputID;
CIdentifier dstBoxInputID;
this->getSourceBoxOutputIdentifier(srcBoxID, srcBoxOutputIdx, srcBoxOutputID);
this->getTargetBoxInputIdentifier(dstBoxID, dstBoxInputIdx, dstBoxInputID);
link->setIdentifier(linkID);
link->setSource(srcBoxID, srcBoxOutputIdx, srcBoxOutputID);
link->setTarget(dstBoxID, dstBoxInputIdx, dstBoxInputID);
m_links[link->getIdentifier()] = link;
return true;
}
bool CScenario::connect(CIdentifier& linkID, const CIdentifier& srcBoxID, const CIdentifier& srcBoxOutputID,
const CIdentifier& dstBoxID, const CIdentifier& dstBoxInputID, const CIdentifier& suggestedLinkID)
{
size_t srcBoxOutputIdx;
size_t dstBoxInputIdx;
this->getSourceBoxOutputIndex(srcBoxID, srcBoxOutputID, srcBoxOutputIdx);
this->getTargetBoxInputIndex(dstBoxID, dstBoxInputID, dstBoxInputIdx);
return this->connect(linkID, srcBoxID, srcBoxOutputIdx, dstBoxID, dstBoxInputIdx, suggestedLinkID);
}
bool CScenario::disconnect(const CIdentifier& srcBoxID, const size_t srcBoxOutputIdx, const CIdentifier& dstBoxID, const size_t dstBoxInputIdx)
{
// Looks for any link with the same signature
for (auto itLink = m_links.begin(); itLink != m_links.end(); ++itLink)
{
CLink* link = itLink->second;
if (link)
{
if (link->getTargetBoxIdentifier() == dstBoxID && link->getTargetBoxInputIndex() == dstBoxInputIdx)
{
if (link->getSourceBoxIdentifier() == srcBoxID && link->getSourceBoxOutputIndex() == srcBoxOutputIdx)
{
// Found a link, so removes it
delete link;
m_links.erase(itLink);
return true;
}
}
}
}
OV_ERROR_KRF("Link is not part of the scenario", Kernel::ErrorType::ResourceNotFound);
}
bool CScenario::disconnect(const CIdentifier& srcBoxID, const CIdentifier& srcBoxOutputID, const CIdentifier& dstBoxID, const CIdentifier& dstBoxInputID)
{
size_t srcBoxOutputIdx;
size_t dstBoxInputIdx;
this->getSourceBoxOutputIndex(srcBoxID, srcBoxOutputID, srcBoxOutputIdx);
this->getTargetBoxInputIndex(dstBoxID, dstBoxInputID, dstBoxInputIdx);
return this->disconnect(srcBoxID, srcBoxOutputIdx, dstBoxID, dstBoxInputIdx);
}
bool CScenario::disconnect(const CIdentifier& linkID)
{
// Finds the link according to its identifier
auto itLink = m_links.find(linkID);
OV_ERROR_UNLESS_KRF(itLink != m_links.end(), "Link [" << linkID.str() << "] is not part of the scenario", Kernel::ErrorType::ResourceNotFound);
// Deletes the link itself
delete itLink->second;
// Removes link from the link list
m_links.erase(itLink);
return true;
}
//___________________________________________________________________//
// //
bool CScenario::applyLocalSettings()
{
for (auto& box : m_boxes)
{
// Expand all the variables inside the newly created scenario by replacing only the $var variables
CScenarioSettingKeywordParserCallback scenarioSettingKeywordParserCallback(*this);
this->getConfigurationManager().registerKeywordParser("var", scenarioSettingKeywordParserCallback);
for (size_t settingIndex = 0; settingIndex < box.second->getSettingCount(); ++settingIndex)
{
CString settingName = "";
CString settingValue = "";
box.second->getSettingName(settingIndex, settingName);
box.second->getSettingValue(settingIndex, settingValue);
box.second->setSettingValue(settingIndex, this->getConfigurationManager().expandOnlyKeyword("var", settingValue, true));
box.second->getSettingValue(settingIndex, settingValue);
if (box.second->hasAttribute(OVD_AttributeId_SettingOverrideFilename))
{
settingValue = box.second->getAttributeValue(OVD_AttributeId_SettingOverrideFilename);
box.second->setAttributeValue(
OVD_AttributeId_SettingOverrideFilename, this->getConfigurationManager().expandOnlyKeyword("var", settingValue, true));
}
}
this->getConfigurationManager().unregisterKeywordParser("var");
}
return true;
}
bool CScenario::isMetabox()
{
// A scenario with inputs and/or outputs is a metabox
if (this->getInputCount() + this->getOutputCount() > 0) { return true; }
// TODO_JL: Find a way to check for other conditions as well
return false;
}
//___________________________________________________________________//
// //
bool CScenario::acceptVisitor(IObjectVisitor& objectVisitor)
{
CObjectVisitorContext objectVisitorContext(getKernelContext());
if (!objectVisitor.processBegin(objectVisitorContext, *this)) { return false; }
for (auto& box : m_boxes) { if (!box.second->acceptVisitor(objectVisitor)) { return false; } }
for (auto& comment : m_comments) { if (!comment.second->acceptVisitor(objectVisitor)) { return false; } }
for (auto& link : m_links) { if (!link.second->acceptVisitor(objectVisitor)) { return false; } }
if (!objectVisitor.processEnd(objectVisitorContext, *this)) { return false; }
return true;
}
//___________________________________________________________________//
// //
CIdentifier CScenario::getUnusedIdentifier(const CIdentifier& suggestedID) const
{
uint64_t newID = (uint64_t(rand()) << 32) + uint64_t(rand());
if (suggestedID != CIdentifier::undefined()) { newID = suggestedID.id() - 1; }
CIdentifier result;
std::map<CIdentifier, CBox*>::const_iterator itBox;
std::map<CIdentifier, CComment*>::const_iterator itComment;
std::map<CIdentifier, CLink*>::const_iterator itLink;
do
{
newID++;
result = CIdentifier(newID);
itBox = m_boxes.find(result);
itComment = m_comments.find(result);
itLink = m_links.find(result);
} while (itBox != m_boxes.end() || itComment != m_comments.end() || itLink != m_links.end() || result == CIdentifier::undefined());
return result;
}
bool CScenario::checkSettings(IConfigurationManager* configurationManager)
{
for (auto& box : m_boxes)
{
if (!box.second->hasAttribute(OV_AttributeId_Box_Disabled))
{
this->applyLocalSettings();
// Expand all the variables inside the newly created scenario by replacing only the $var variables
CScenarioSettingKeywordParserCallback scenarioSettingKeywordParserCallback(*this);
this->getConfigurationManager().registerKeywordParser("var", scenarioSettingKeywordParserCallback);
for (size_t settingIndex = 0; settingIndex < box.second->getSettingCount(); ++settingIndex)
{
CString settingName = "";
CString rawSettingValue = "";
CIdentifier typeID;
if (box.second->hasAttribute(OVD_AttributeId_SettingOverrideFilename)) { return true; }
box.second->getSettingName(settingIndex, settingName);
box.second->getSettingValue(settingIndex, rawSettingValue);
box.second->getSettingType(settingIndex, typeID);
CString settingValue = rawSettingValue;
if (configurationManager) { settingValue = configurationManager->expand(settingValue); }
else { settingValue = this->getConfigurationManager().expandOnlyKeyword("var", settingValue); }
const auto settingTypeName = this->getTypeManager().getTypeName(typeID);
OV_ERROR_UNLESS_KRF(
::checkSettingValue(settingValue, typeID, this->getTypeManager()),
"<" << box.second->getName() << "> The following value: ["<< rawSettingValue <<"] expanded as ["<< settingValue <<
"] given as setting is not a valid [" << settingTypeName << "] value.",
ErrorType::BadValue);
}
this->getConfigurationManager().unregisterKeywordParser("var");
}
}
return true;
}
//___________________________________________________________________//
// //
CIdentifier CScenario::getNextOutdatedBoxIdentifier(const CIdentifier& previousID) const
{
return getNextID<std::shared_ptr<CBox>, STestTrue<std::shared_ptr<CBox>>>(m_outdatedBoxes, previousID, STestTrue<std::shared_ptr<CBox>>());
}
bool CScenario::hasOutdatedBox()
{
for (auto& box : m_boxes) { if (box.second->hasAttribute(OV_AttributeId_Box_ToBeUpdated)) { return true; } }
return false;
}
bool CScenario::isBoxOutdated(const CIdentifier& boxId)
{
IBox* box = getBoxDetails(boxId);
if (!box) { return false; }
CIdentifier boxHashCode1;
CIdentifier boxHashCode2;
if (box->getAlgorithmClassIdentifier() == OVP_ClassId_BoxAlgorithm_Metabox)
{
CIdentifier metaboxId;
metaboxId.fromString(box->getAttributeValue(OVP_AttributeId_Metabox_ID));
boxHashCode1 = getKernelContext().getMetaboxManager().getMetaboxHash(metaboxId);
}
else { boxHashCode1 = this->getKernelContext().getPluginManager().getPluginObjectHashValue(box->getAlgorithmClassIdentifier()); }
boxHashCode2.fromString(box->getAttributeValue(OV_AttributeId_Box_InitialPrototypeHashValue));
if (!(boxHashCode1 == CIdentifier::undefined() || boxHashCode1 == boxHashCode2)) { return true; }
return false;
}
bool CScenario::checkOutdatedBoxes()
{
bool result = false;
m_outdatedBoxes.clear();
m_updatedBoxIOCorrespondence[Input] = std::map<CIdentifier, std::map<size_t, size_t>>();
m_updatedBoxIOCorrespondence[Output] = std::map<CIdentifier, std::map<size_t, size_t>>();
for (auto& box : m_boxes)
{
// Do not attempt to update boxes which do not have existing box algorithm identifiers
auto boxAlgorithmClassID = box.second->getAlgorithmClassIdentifier();
if (boxAlgorithmClassID != OVP_ClassId_BoxAlgorithm_Metabox
&& !dynamic_cast<const Plugins::IBoxAlgorithmDesc*>(this->getKernelContext().getPluginManager().getPluginObjectDescCreating(boxAlgorithmClassID)))
{
continue;
}
// Do not attempt to update metaboxes which do not have an associated scenario
if (boxAlgorithmClassID == OVP_ClassId_BoxAlgorithm_Metabox)
{
CString metaboxIdentifier = box.second->getAttributeValue(OVP_AttributeId_Metabox_ID);
if (metaboxIdentifier == CString("")) { continue; }
CIdentifier metaboxId;
metaboxId.fromString(metaboxIdentifier);
CString metaboxScenarioPath(this->getKernelContext().getMetaboxManager().getMetaboxFilePath(metaboxId));
if (metaboxScenarioPath == CString("")) { continue; }
}
// Box Updater instance which is in charge of create updated boxes and links
CBoxUpdater boxUpdater(*this, box.second);
if (!boxUpdater.initialize())
{
OV_WARNING_K("Could not check for update the box with id " << box.second->getIdentifier());
continue;
}
// exception for boxes that could not be automatically updated
if (boxUpdater.flaggedForManualUpdate())
{
if (this->isBoxOutdated(box.second->getIdentifier()))
{
auto toBeUpdatedBox = std::make_shared<CBox>(getKernelContext());
toBeUpdatedBox->initializeFromAlgorithmClassIdentifierNoInit(boxAlgorithmClassID);
m_outdatedBoxes[box.second->getIdentifier()] = toBeUpdatedBox;
m_boxes[box.first]->setAttributeValue(OV_AttributeId_Box_ToBeUpdated, "");
result = true;
}
continue;
}
// collect updated boxes
if (boxUpdater.isUpdateRequired())
{
m_updatedBoxIOCorrespondence[Input][box.second->getIdentifier()] = boxUpdater.getOriginalToUpdatedInterfacorCorrespondence(Input);
m_updatedBoxIOCorrespondence[Output][box.second->getIdentifier()] = boxUpdater.getOriginalToUpdatedInterfacorCorrespondence(Output);
// it is important to set box algorithm at
// last so the box listener is never called
boxUpdater.getUpdatedBox().setAlgorithmClassIdentifier(boxAlgorithmClassID);
// copy requested box into a new instance managed in scenario
auto newBox = std::make_shared<CBox>(this->getKernelContext());
newBox->initializeFromExistingBox(boxUpdater.getUpdatedBox());
m_outdatedBoxes[box.second->getIdentifier()] = newBox;
m_boxes[box.first]->setAttributeValue(OV_AttributeId_Box_ToBeUpdated, "");
result = true;
}
}
return result;
}
template <class T, class TTest>
void getIdentifierList(const std::map<CIdentifier, T>& elementMap, const TTest& testFunctor, CIdentifier** listID, size_t* size)
{
*listID = new CIdentifier[elementMap.size()];
size_t index = 0;
for (auto it = elementMap.begin(); it != elementMap.end(); ++it) { if (testFunctor(it)) { (*listID)[index++] = it->first; } }
*size = index;
}
void CScenario::getBoxIdentifierList(CIdentifier** listID, size_t* size) const
{
getIdentifierList<CBox*, STestTrue<CBox*>>(m_boxes, STestTrue<CBox*>(), listID, size);
}
void CScenario::getCommentIdentifierList(CIdentifier** listID, size_t* size) const
{
getIdentifierList<CComment*, STestTrue<CComment*>>(m_comments, STestTrue<CComment*>(), listID, size);
}
void CScenario::getMetadataIdentifierList(CIdentifier** listID, size_t* size) const
{
getIdentifierList<CMetadata*, STestTrue<CMetadata*>>(m_metadatas, STestTrue<CMetadata*>(), listID, size);
}
void CScenario::getLinkIdentifierList(CIdentifier** listID, size_t* size) const
{
getIdentifierList<CLink*, STestTrue<CLink*>>(m_links, STestTrue<CLink*>(), listID, size);
}
void CScenario::getLinkIdentifierFromBoxList(const CIdentifier& boxID, CIdentifier** listID, size_t* size) const
{
getIdentifierList<CLink*, STestEqSourceBox>(m_links, STestEqSourceBox(boxID), listID, size);
}
void CScenario::getLinkIdentifierFromBoxOutputList(const CIdentifier& boxID, const size_t index, CIdentifier** listID, size_t* size) const
{
getIdentifierList<CLink*, STestEqSourceBoxOutput>(m_links, STestEqSourceBoxOutput(boxID, index), listID, size);
}
void CScenario::getLinkIdentifierToBoxList(const CIdentifier& boxID, CIdentifier** listID, size_t* size) const
{
getIdentifierList<CLink*, STestEqTargetBox>(m_links, STestEqTargetBox(boxID), listID, size);
}
void CScenario::getLinkIdentifierToBoxInputList(const CIdentifier& boxID, const size_t index, CIdentifier** listID, size_t* size) const
{
getIdentifierList<CLink*, STestEqTargetBoxInput>(m_links, STestEqTargetBoxInput(boxID, index), listID, size);
}
void CScenario::getOutdatedBoxIdentifierList(CIdentifier** listID, size_t* size) const
{
getIdentifierList<std::shared_ptr<CBox>, STestTrue<std::shared_ptr<CBox>>>(m_outdatedBoxes, STestTrue<std::shared_ptr<CBox>>(), listID, size);
}
void CScenario::releaseIdentifierList(CIdentifier* listID) const { delete[] listID; }
bool CScenario::getSourceBoxOutputIndex(const CIdentifier& srcBoxID, const CIdentifier& srcBoxOutputID, size_t& srcBoxOutputIdx)
{
const auto itSourceBox = m_boxes.find(srcBoxID);
OV_ERROR_UNLESS_KRF(itSourceBox != m_boxes.end(), "Source Box [" << srcBoxID.str() << "] is not part of the scenario", Kernel::ErrorType::ResourceNotFound);
m_boxes[srcBoxID]->getInterfacorIndex(Output, srcBoxOutputID, srcBoxOutputIdx);
return true;
}
bool CScenario::getTargetBoxInputIndex(const CIdentifier& dstBoxID, const CIdentifier& dstBoxInputID, size_t& dstBoxInputIdx)
{
const auto itTargetBox = m_boxes.find(dstBoxID);
OV_ERROR_UNLESS_KRF(itTargetBox != m_boxes.end(), "Target Box [" << dstBoxID.str() << "] is not part of the scenario", Kernel::ErrorType::ResourceNotFound);
m_boxes[dstBoxID]->getInterfacorIndex(Input, dstBoxInputID, dstBoxInputIdx);
return true;
}
bool CScenario::getSourceBoxOutputIdentifier(const CIdentifier& srcBoxID, const size_t& srcBoxOutputIdx, CIdentifier& srcBoxOutputID)
{
const auto itSourceBox = m_boxes.find(srcBoxID);
OV_ERROR_UNLESS_KRF(itSourceBox != m_boxes.end(), "Source Box [" << srcBoxID.str() << "] is not part of the scenario", Kernel::ErrorType::ResourceNotFound);
m_boxes[srcBoxID]->getInterfacorIdentifier(Output, srcBoxOutputIdx, srcBoxOutputID);
return true;
}
bool CScenario::getTargetBoxInputIdentifier(const CIdentifier& dstBoxID, const size_t& dstBoxInputIdx, CIdentifier& dstBoxInputID)
{
const auto itTargetBox = m_boxes.find(dstBoxID);
OV_ERROR_UNLESS_KRF(itTargetBox != m_boxes.end(), "Target Box [" << dstBoxID.str() << "] is not part of the scenario", Kernel::ErrorType::ResourceNotFound);
m_boxes[dstBoxID]->getInterfacorIdentifier(Input, dstBoxInputIdx, dstBoxInputID);
return true;
}
/**
* \brief Process to the update of the identified box.
* It consists in recreate the prototype of the box according to the updated reference box which is the box
* resulting of the add/pull requests to the kernel prototype.
* \param boxID the identifier of the box to be updated
* \return true when update has been done successfully
* \return false in case of failure
*/
bool CScenario::updateBox(const CIdentifier& boxID)
{
// Check if box must be updated
const auto itSourceBox = m_boxes.find(boxID);
OV_ERROR_UNLESS_KRF(itSourceBox != m_boxes.end(), "Box [" << boxID.str() << "] is not part of the scenario", Kernel::ErrorType::ResourceNotFound);
auto itUpdateBox = m_outdatedBoxes.find(boxID);
if (itUpdateBox == m_outdatedBoxes.end())
{
this->checkOutdatedBoxes();
itUpdateBox = m_outdatedBoxes.find(boxID);
}
OV_ERROR_UNLESS_KRF(itUpdateBox != m_outdatedBoxes.end(), "Box [" << boxID.str() << "] misses an updated version", Kernel::ErrorType::ResourceNotFound);
if (itUpdateBox->second->hasAttribute(OV_AttributeId_Box_FlagNeedsManualUpdate)
|| itUpdateBox->second->hasAttribute(OV_AttributeId_Box_FlagCanAddInput)
|| itUpdateBox->second->hasAttribute(OV_AttributeId_Box_FlagCanAddOutput)
|| itUpdateBox->second->hasAttribute(OV_AttributeId_Box_FlagCanAddSetting)
|| itUpdateBox->second->hasAttribute(OV_AttributeId_Box_FlagCanModifyInput)
|| itUpdateBox->second->hasAttribute(OV_AttributeId_Box_FlagCanModifyOutput)
|| itUpdateBox->second->hasAttribute(OV_AttributeId_Box_FlagCanModifySetting))
{
OV_ERROR_KRF(m_boxes[boxID]->getName() << " must be manually updated. Its prototype is too complex.", Kernel::ErrorType::NotImplemented);
}
OV_ERROR_UNLESS_KRF(itUpdateBox != m_outdatedBoxes.end(), "Box [" << boxID.str() << "] does not have to be updated", Kernel::ErrorType::ResourceNotFound);
// get all non-updatable attributes from the source box
std::map<CIdentifier, CString> nonUpdatableAttributes;
{
CIdentifier attributeId = CIdentifier::undefined();
while ((attributeId = itSourceBox->second->getNextAttributeIdentifier(attributeId)) != CIdentifier::undefined())
{
const auto& updatableAttrs = CBoxUpdater::UPDATABLE_ATTRIBUTES;
if (std::find(updatableAttrs.cbegin(), updatableAttrs.cend(), attributeId) == updatableAttrs.cend())
{
nonUpdatableAttributes[attributeId] = itSourceBox->second->getAttributeValue(attributeId);
}
}
}
// gather links coming to and from the box
std::map<EBoxInterfacorType, std::vector<std::shared_ptr<CLink>>> links;
for (auto interfacorType : { Input, Output })
{
links[interfacorType] = std::vector<std::shared_ptr<CLink>>();
for (size_t index = 0; index < itUpdateBox->second->getInterfacorCountIncludingDeprecated(interfacorType); ++index)
{
CIdentifier* linkIdentifierList = nullptr;
size_t linkCount = 0;
if (interfacorType == Input) { this->getLinkIdentifierToBoxInputList(boxID, index, &linkIdentifierList, &linkCount); }
else if (interfacorType == Output) { this->getLinkIdentifierFromBoxOutputList(boxID, index, &linkIdentifierList, &linkCount); }
for (size_t i = 0; i < linkCount; ++i)
{
auto link = std::make_shared<CLink>(this->getKernelContext(), *this);
link->initializeFromExistingLink(*this->getLinkDetails(linkIdentifierList[i]));
if (this->getLinkDetails(linkIdentifierList[i])->hasAttribute(OV_AttributeId_Link_Invalid))
{
link->addAttribute(OV_AttributeId_Link_Invalid, "");
}
links[interfacorType].emplace_back(link);
}
this->releaseIdentifierList(linkIdentifierList);
}
}
OV_FATAL_UNLESS_K(this->removeBox(boxID), "Failed to remove redundant box", Kernel::ErrorType::Internal);
CIdentifier updatedBoxIdentifier;
OV_FATAL_UNLESS_K(this->addBox(updatedBoxIdentifier, *(itUpdateBox->second.get()), boxID), "Failed to add box to the scenario",
Kernel::ErrorType::Internal);
OV_FATAL_UNLESS_K(updatedBoxIdentifier == boxID, "Updated box failed to initialize with same identifier", Kernel::ErrorType::Internal);
auto updatedBox = this->getBoxDetails(boxID);
for (const auto& attr : nonUpdatableAttributes)
{
if (attr.first == OV_AttributeId_Box_ToBeUpdated) { continue; }
if (updatedBox->hasAttribute(attr.first)) { updatedBox->setAttributeValue(attr.first, attr.second); }
else { updatedBox->addAttribute(attr.first, attr.second); }
}
// Reconnect links
std::map<EBoxInterfacorType, std::set<size_t>> isInterfacorConnected;
isInterfacorConnected[Input] = std::set<size_t>();
isInterfacorConnected[Output] = std::set<size_t>();
for (auto& link : links[Input])
{
CIdentifier newLinkIdentifier;
auto index = m_updatedBoxIOCorrespondence.at(Input).at(boxID).at(link->getTargetBoxInputIndex());
this->connect(newLinkIdentifier, link->getSourceBoxIdentifier(), link->getSourceBoxOutputIndex(), boxID, index, link->getIdentifier());
isInterfacorConnected[Input].insert(index);
if (link->hasAttribute(OV_AttributeId_Link_Invalid)) { this->getLinkDetails(newLinkIdentifier)->setAttributeValue(OV_AttributeId_Link_Invalid, ""); }
}
for (const auto& link : links[Output])
{
CIdentifier newLinkIdentifier;
auto index = m_updatedBoxIOCorrespondence.at(Output).at(boxID).at(link->getSourceBoxOutputIndex());
this->connect(newLinkIdentifier, boxID, index, link->getTargetBoxIdentifier(), link->getTargetBoxInputIndex(), link->getIdentifier());
isInterfacorConnected[Output].insert(index);
if (link->hasAttribute(OV_AttributeId_Link_Invalid)) { this->getLinkDetails(newLinkIdentifier)->setAttributeValue(OV_AttributeId_Link_Invalid, ""); }
}
// Cleanup the i/o that are redundant and disconnected
for (auto t : { Input, Output })
{
size_t i = updatedBox->getInterfacorCountIncludingDeprecated(t);
while (i > 0)
{
--i;
bool isDeprecated;
updatedBox->getInterfacorDeprecatedStatus(t, i, isDeprecated);
if (isDeprecated && isInterfacorConnected.at(t).find(i) == isInterfacorConnected.at(t).end()) { updatedBox->removeInterfacor(t, i, true); }
}
}
// Cleanup the settings that are redundant and have the same value as default
size_t settingIndex = updatedBox->getInterfacorCountIncludingDeprecated(Setting);
while (settingIndex > 0)
{
settingIndex--;
bool isDeprecated;
CString value;
CString defaultValue;
updatedBox->getInterfacorDeprecatedStatus(Setting, settingIndex, isDeprecated);
updatedBox->getSettingValue(settingIndex, value);
updatedBox->getSettingDefaultValue(settingIndex, defaultValue);
if (isDeprecated && value == defaultValue) { updatedBox->removeInterfacor(Setting, settingIndex, true); }
}
bool hasDeprecatedInterfacor = false;
for (auto t : { Setting, Input, Output })
{
hasDeprecatedInterfacor |= (updatedBox->getInterfacorCount(t) != updatedBox->getInterfacorCountIncludingDeprecated(t));
}
if (hasDeprecatedInterfacor)
{
OV_WARNING_K(m_boxes[boxID]->getName()
<< " box has not been fully updated. Deprecated Inputs, Outputs or Settings are pending.\n"
<< " Please remove them before exporting scenario\n");
this->getBoxDetails(boxID)->setAttributeValue(OV_AttributeId_Box_PendingDeprecatedInterfacors, "");
}
else { this->getLogManager() << LogLevel_Info << m_boxes[boxID]->getName() << " box has been updated successfully\n"; }
return true;
}
bool CScenario::removeDeprecatedInterfacorsFromBox(const CIdentifier& boxID)
{
// Check if box must be updated
IBox* box = getBoxDetails(boxID);
if (!box) { return false; }
for (auto interfacorType : { Input, Output, Setting })
{
const auto nInterfacor = box->getInterfacorCountIncludingDeprecated(interfacorType);
if (nInterfacor == 0) { continue; }
auto index = nInterfacor;
do
{
index--;
bool isDeprecated = false;
box->getInterfacorDeprecatedStatus(interfacorType, index, isDeprecated);
if (isDeprecated) { box->removeInterfacor(interfacorType, index); }
} while (index != 0);
}
this->getLogManager() << LogLevel_Info << m_boxes[boxID]->getName()
<< " Deprecated I/O and settings have been removed successfully\n";
box->removeAttribute(OV_AttributeId_Box_PendingDeprecatedInterfacors);
return true;
}
bool CScenario::containsBoxWithDeprecatedInterfacors() const
{
for (const auto& box : m_boxes)
{
for (const auto interfacorType : { Input, Output, Setting })
{
if (box.second->getInterfacorCountIncludingDeprecated(interfacorType) > box.second->getInterfacorCount(interfacorType)) { return true; }
}
}
return false;
}
} // namespace Kernel
} // namespace OpenViBE