/** * Handler for all exercise objects * $Id$ * $HeadURL$ * $Author$ * Created by Malte Diers, SLSE, 2017-04-05 */ #include "handler_functional_area.h" #include "Utils/polygons.h" #include namespace AreaEffectSimulation { HandlerFunctionalArea::HandlerFunctionalArea(MainHandler *mainHandler) : HandlerBaseTmpl(mainHandler, QStringLiteral("FunctionalArea"), s_areaCount[AesType::AtFunctionalArea], s_areaCountCentral[AesType::AtFunctionalArea]) , Interface::Fts::FunctionalAreaModifyRequestHandler(mainHandler->dds()->fts()) , Interface::Fts::FunctionalAreaRemoveRequestHandler(mainHandler->dds()->fts()) { } bool HandlerFunctionalArea::init() { QVector dataVec; // read all FunctionalAreas from database if (!m_mainHandler->db()->select(dataVec)) { ERROR_LOG(m_logger) << "Error reading data from database!"; return false; } QVector functionalAreaTypeVec; // read parties from db if (!m_mainHandler->db()->select(functionalAreaTypeVec)) { ERROR_LOG(m_logger) << "Error while reading FunctionalAreaType data from database"; return false; } // if there are no functionalAreaTypes in db and this instance of AreaEffectSimulation runs not in ex_0 // functionalAreaTypes are fetched from ex_0 AES if (m_mainHandler->dds()->exerciseId() > 0 && functionalAreaTypeVec.isEmpty()) functionalAreaTypeVec = loadDefaultFunctionalAreaTypes(true); if (functionalAreaTypeVec.isEmpty()) { ERROR_LOG(m_logger) << "Error while reading functionalAreaType data from database"; return false; } for (const Database::AesFunctionalAreaType ¤tFunctionalAreaType : qAsConst(functionalAreaTypeVec)) { FunctionalAreaType *ddsData = new FunctionalAreaType(currentFunctionalAreaType.id, currentFunctionalAreaType.name.toStdString(), currentFunctionalAreaType.pointSymbol.toStdString(), currentFunctionalAreaType.deconTime, currentFunctionalAreaType.deconMode, currentFunctionalAreaType.maintTime, currentFunctionalAreaType.maintMode, currentFunctionalAreaType.medicTime, currentFunctionalAreaType.medicMode, currentFunctionalAreaType.supplyTime, currentFunctionalAreaType.supplyMode, currentFunctionalAreaType.notfightTime, currentFunctionalAreaType.notfightMode ); m_functionalAreaTypes.insert(currentFunctionalAreaType.id, ddsData); m_mainHandler->dds()->dts()->publish(*ddsData); } // create functional area objects for (const Database::AesFunctionalArea &dbData : qAsConst(dataVec)) { ObjectFunctionalArea *ifs(new ObjectFunctionalArea(m_mainHandler, this)); connect(ifs, &ObjectFunctionalArea::effectStateChanged, this, &HandlerFunctionalArea::onEffectStateChanged); Core::FunctionReplyObject ret = ifs->createObject(dbData); if (ret.error()) { delete ifs; ERROR_LOG(m_logger) << ret(); return false; } if (!ifs->data().isCentral) { if (totalAreas() >= s_maxActiveAreas[AesType::AtFunctionalArea]) { ERROR_LOG(m_logger) << "More active functional areas in database than allowed - ignoring the rest!"; ifs->removeObject(); delete ifs; continue; } } else { if (totalAreasCentral() >= s_maxActiveAreasCentral[AesType::AtFunctionalArea]) { ERROR_LOG(m_logger) << "More active functional areas in database than allowed - ignoring the rest!"; ifs->removeObject(); delete ifs; continue; } } if (ifs->isObjectInTrainingArea()) { if (ifs->data().isCentral) ++m_areaCountCentral; else ++m_areaCount; } m_objectMap.insert(ifs->id(), ifs); connect(ifs, &ObjectFunctionalArea::newAiv, this, &HandlerFunctionalArea::newAiv); connect(ifs, &ObjectFunctionalArea::removeAiv, this, &HandlerFunctionalArea::removeAiv); } DEBUG_LOG(m_logger) << "m_exeObjMap.size() = " << m_objectMap.size(); return true; } //------------------------------------------------------------------------------------------ QVector HandlerFunctionalArea::loadDefaultFunctionalAreaTypes(bool withInsert) const { QVector functionalAreaTypes; if (!m_mainHandler->dbEx0()->select(functionalAreaTypes)) ERROR_LOG(m_logger) << "Error while reading party data from database (ex_0)"; auto cb = [](const Database::AesFunctionalAreaType & p1, const Database::AesFunctionalAreaType & p2) -> bool { return p1.id < p2.id; }; std::sort(functionalAreaTypes.begin(), functionalAreaTypes.end(), cb); if (withInsert) { for (auto it = functionalAreaTypes.begin(); it != functionalAreaTypes.end(); ++it) m_mainHandler->db()->insert(*it); } return functionalAreaTypes; } int HandlerFunctionalArea::totalAreas() const { return s_areaCount[AesType::AtFunctionalArea]; } int HandlerFunctionalArea::totalAreasCentral() const { return s_areaCountCentral[AesType::AtFunctionalArea]; } template static void fillData(const T &src, Database::AesFunctionalArea &dst) { if (src.id() < 0) // is the id given as negative? set id -> used by OC-Laptop dst.id = src.id(); dst.name = QString::fromStdString(src.name()); dst.effectStart = src.effectStart().is_set() && src.effectStart().get() > 0 ? QDateTime::fromMSecsSinceEpoch(src.effectStart().get()) : QDateTime(); dst.effectDuration = src.effectDuration(); dst.position.rx() = src.area().cornerBottomLeft().lon(); dst.position.ry() = src.area().cornerBottomLeft().lat(); dst.length = src.area().height(); dst.width = src.area().width(); dst.partyId = src.partyId().is_set() ? src.partyId().get() : 0; dst.chargeTypeId = src.chargeTypeId(); dst.participantId = src.participantId().is_set() ? src.participantId().get() : 0; dst.pointSymbol = src.pointSymbol().is_set() ? QString::fromStdString(src.pointSymbol().get()) : QString(); dst.functionalAreaTypeId = src.functionalAreaTypeId(); dst.deconMode = src.deconMode(); dst.deconTime = src.deconTime(); dst.maintMode = src.maintMode(); dst.maintTime = src.maintTime(); dst.medicMode = src.medicMode(); dst.medicTime = src.medicTime(); dst.supplyMode = src.supplyMode(); dst.supplyTime = src.supplyTime(); } void HandlerFunctionalArea::onFunctionalAreaModifyRequest(const rti::core::SampleIdentity &cookie, const FunctionalAreaModifyRequest &request) { DEBUG_LOG(m_logger) << "onFunctionalAreaModifyRequest: " << request; const Core::FunctionReplyObject ret = functionalAreaModifyRequest(request); if (ret.error()) WARNING_LOG(m_logger) << ret(); m_mainHandler->dds()->fts()->functionalAreaModifyReply(cookie, ret); } Core::FunctionReplyObject HandlerFunctionalArea::functionalAreaCreateRequest(const FunctionalAreaModifyRequest &request) { if (!request.partyId().is_set() && (request.supplyMode() != AesOperatingMode_def::OmWaitingTime)) return Core::FunctionReplyObject(tr_lts("dds", "Functional areas need a party id.")); if ((!request.participantId().is_set()) && (request.supplyMode() == AesOperatingMode_def::OmWaitingTime)) return Core::FunctionReplyObject(tr_lts("dds", "Functional areas Supply need a participant id.")); Database::AesFunctionalArea newData; fillData(request, newData); // check: effectStart > time(NULL) ? ObjectFunctionalArea *ifs(new ObjectFunctionalArea(m_mainHandler, this)); connect(ifs, &ObjectFunctionalArea::effectStateChanged, this, &HandlerFunctionalArea::onEffectStateChanged); const Core::FunctionReplyObject ret = ifs->createObject(newData); if (ret.error()) { delete ifs; ifs = nullptr; return ret; } if (ifs->data().isCentral) { if (totalAreasCentral() >= s_maxActiveAreasCentral[AesType::AtFunctionalArea] && request.effectStart().is_set()) { ifs->removeObject(); //Not finally deleted from db after this,Fallback if DB deletion is not working correct ifs->removeObjectFromDb(); delete ifs; return Core::FunctionReplyObject(1, tr_lts("dds", "Too many active central functional areas.")); } } else { if (totalAreas() >= s_maxActiveAreas[AesType::AtFunctionalArea] && request.effectStart().is_set()) { ifs->removeObject(); //Not finally deleted from db after this,Fallback if DB deletion is not working correct ifs->removeObjectFromDb(); delete ifs; return Core::FunctionReplyObject(1, tr_lts("dds", "Too many active functional areas.")); } } if (ifs->data().isCentral) { ++m_areaCountCentral; DEBUG_LOG(m_logger) << "s_areaCountCentral[AesType::AtFunctionalArea] = " << m_areaCountCentral; } else if (ifs->isObjectInTrainingArea()) { ++m_areaCount; DEBUG_LOG(m_logger) << "s_areaCount[AesType::AtFunctionalArea] = " << m_areaCount; } m_objectMap.insert(ifs->id(), ifs); connect(ifs, &ObjectFunctionalArea::newAiv, this, &HandlerFunctionalArea::newAiv); connect(ifs, &ObjectFunctionalArea::removeAiv, this, &HandlerFunctionalArea::removeAiv); return ret; } Core::FunctionReplyObject HandlerFunctionalArea::functionalAreaModifyRequest(const FunctionalAreaModifyRequest &request) { Core::FunctionReplyObject ret; if (request.id() == 0 || ((request.id() < 0) && !getObjectFromMap(m_objectMap, std::abs(request.id()), ret))) return functionalAreaCreateRequest(request); ObjectFunctionalArea *ifs = getObjectFromMap(m_objectMap, std::abs(request.id()), ret); if (!ifs) return ret; // Anzahl aktiver Areas ist erreicht, der Wirkbeginn ist (soll) gesetzt sein, aber die Area war // vorher noch ohne Wirkbeginn // if (totalAreas() >= s_maxActiveAreas[AesType::AtFunctionalArea] && request.effectStart().is_set() && !ifs->isObjectModifiable()) // return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Too many active functional areas.")); // Todo: IsObjectModifiable() ?!? AreaEffectSimulation::Database::AesFunctionalArea aea(ifs->data()); fillData(request, aea); // Calculate new polygon here. Not nice, though auto poly = Polygons::functionalArea(aea); std::vector _form; ObjectBase::ddsVecFromPoly(poly, _form); bool isCentral = ifs->checkIsCentral(_form); bool wasCentral = ifs->data().isCentral; /*! * If the effect start added after creation, the max amount need to be checked !*/ if(!ifs->isActivationTimeSet() && request.effectStart().is_set()) { if (isCentral) { if (totalAreasCentral() >= s_maxActiveAreasCentral[AesType::AtFunctionalArea]) { return Core::FunctionReplyObject(1, tr_lts("dds", "Too many active central functional areas.")); } } else { if (totalAreas() >= s_maxActiveAreas[AesType::AtFunctionalArea]) { return Core::FunctionReplyObject(1, tr_lts("dds", "Too many active functional areas.")); } } } // For counting, only Elements being at least prepared are important: if (request.effectStart().is_set() && ifs->isObjectModifiable()) { // Supply-Truck always isCentral // if ( request.supplyMode() == AesOperatingMode_def::OmWaitingTime) // { // isCentral = true; // wasCentral = true; // } DEBUG_LOG(m_logger) << "isCentral: " << isCentral; DEBUG_LOG(m_logger) << "wasCentral: " << wasCentral; // only change if element changed from central to training area or vice versa if (isCentral != wasCentral) { // Change from central to training area if (wasCentral) { if (totalAreas() >= s_maxActiveAreas[AesType::AtFunctionalArea]) return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Too many active functional areas.")); m_areaCount++; m_areaCountCentral--; DEBUG_LOG(m_logger) << "s_areaCount[AesType::AtFunctionalArea] = " << m_areaCount; DEBUG_LOG(m_logger) << "s_areaCountCentral[AesType::AtFunctionalArea] = " << m_areaCountCentral; } else // Change from training area to central { if (totalAreasCentral() >= s_maxActiveAreasCentral[AesType::AtFunctionalArea]) return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Too many active central functional areas.")); m_areaCount--; m_areaCountCentral++; DEBUG_LOG(m_logger) << "s_areaCount[AesType::AtFunctionalArea] = " << m_areaCount; DEBUG_LOG(m_logger) << "s_areaCountCentral[AesType::AtFunctionalArea] = " << m_areaCountCentral; } } } if (request.id() < 0 && checkStateForSfm(ifs)) { DEBUG_LOG(m_logger) << "Overwrite functinal area Effect State for OC"; aea.effectStateId = AesEffectState::EsPrepared; } return ifs->updateObject(aea); } void HandlerFunctionalArea::onFunctionalAreaRemoveRequest(const rti::core::SampleIdentity &cookie, const Core::RemoveElementRequest &request) { m_mainHandler->dds()->fts()->functionalAreaRemoveReply(cookie, removeReply(&DatabaseInterface::removeAesFunctionalArea, request)); } } // Namespace AreaEffectSimulation