#include "Variable/VariableController2.h" #include "Variable/VariableSynchronizationGroup2.h" #include #include #include #include #include class VariableController2::VariableController2Private { QMap> _variables; QMap> _providers; QMap> _synchronizationGroups; std::unique_ptr _cacheStrategy; bool p_contains(const std::shared_ptr& variable) { return _providers.contains(variable->ID()); } bool v_contains(const std::shared_ptr& variable) { return SciQLop::containers::contains(this->_variables, variable); } bool sg_contains(const std::shared_ptr& variable) { return _synchronizationGroups.contains(variable->ID()); } void _changeRange(const std::shared_ptr& var, DateTimeRange r) { auto provider = _providers[var->ID()]; DateTimeRange newCacheRange; std::vector missingRanges; if(DateTimeRangeHelper::hasnan(var->cacheRange())) { newCacheRange = _cacheStrategy->computeRange(r,r); missingRanges = {newCacheRange}; } else { newCacheRange = _cacheStrategy->computeRange(var->cacheRange(),r); missingRanges = newCacheRange - var->cacheRange(); } for(auto range:missingRanges) { auto data = provider->getData(DataProviderParameters{{range},var->metadata()}); var->mergeDataSeries(data); } var->setCacheRange(newCacheRange); var->setRange(r); } public: VariableController2Private(QObject* parent=Q_NULLPTR) :_cacheStrategy(VariableCacheStrategyFactory::createCacheStrategy(CacheStrategy::SingleThreshold)) { Q_UNUSED(parent); } ~VariableController2Private() = default; std::shared_ptr createVariable(const QString &name, const QVariantHash &metadata, std::shared_ptr provider) { auto newVar = std::make_shared(name,metadata); this->_variables[newVar->ID()] = newVar; this->_providers[newVar->ID()] = std::move(provider); this->_synchronizationGroups[newVar->ID()] = std::make_shared(newVar->ID()); return newVar; } void deleteVariable(const std::shared_ptr& variable) { /* * Removing twice a var is ok but a var without provider has to be a hard error * this means we got the var controller in an inconsistent state */ if(v_contains(variable)) this->_variables.remove(variable->ID()); if(p_contains(variable)) this->_providers.remove(variable->ID()); else SCIQLOP_ERROR(VariableController2Private, "No provider found for given variable"); } void asyncChangeRange(const std::shared_ptr& variable, const DateTimeRange& r) { } void changeRange(const std::shared_ptr& variable, DateTimeRange r) { if(p_contains(variable)) { if(!DateTimeRangeHelper::hasnan(r)) { auto group = _synchronizationGroups[variable->ID()]; if(auto transformation = DateTimeRangeHelper::computeTransformation(variable->range(),r); transformation.has_value()) { for(auto varId:group->variables()) { auto var = _variables[varId]; auto newRange = var->range().transform(transformation.value()); _changeRange(var,newRange); } } else // force new range to all variables -> may be weird if more than one var in the group // @TODO ensure that there is no side effects { for(auto varId:group->variables()) { auto var = _variables[varId]; _changeRange(var,r); } } } else { SCIQLOP_ERROR(VariableController2Private, "Invalid range containing NaN"); } } else { SCIQLOP_ERROR(VariableController2Private, "No provider found for given variable"); } } void synchronize(const std::shared_ptr& var, const std::shared_ptr& with) { if(v_contains(var) && v_contains(with)) { if(sg_contains(var) && sg_contains(with)) { auto dest_group = this->_synchronizationGroups[with->ID()]; this->_synchronizationGroups[var->ID()] = dest_group; dest_group->addVariable(var->ID()); } else { SCIQLOP_ERROR(VariableController2Private, "At least one of the given variables isn't in a sync group"); } } else { SCIQLOP_ERROR(VariableController2Private, "At least one of the given variables is not found"); } } const std::set> variables() { std::set> vars; for(const auto &var:_variables) { vars.insert(var); } return vars; } }; VariableController2::VariableController2() :impl{spimpl::make_unique_impl()} {} std::shared_ptr VariableController2::createVariable(const QString &name, const QVariantHash &metadata, const std::shared_ptr& provider, const DateTimeRange &range) { auto var = impl->createVariable(name, metadata, provider); emit variableAdded(var); if(!DateTimeRangeHelper::hasnan(range)) impl->changeRange(var,range); else SCIQLOP_ERROR(VariableController2, "Creating a variable with default constructed DateTimeRange is an error"); return var; } void VariableController2::deleteVariable(const std::shared_ptr& variable) { impl->deleteVariable(variable); emit variableDeleted(variable); } void VariableController2::changeRange(const std::shared_ptr& variable, const DateTimeRange& r) { impl->changeRange(variable, r); } void VariableController2::asyncChangeRange(const std::shared_ptr &variable, const DateTimeRange &r) { impl->asyncChangeRange(variable, r); } const std::set > VariableController2::variables() { return impl->variables(); } void VariableController2::synchronize(const std::shared_ptr &var, const std::shared_ptr &with) { impl->synchronize(var, with); }