/** * Handler for all exercise objects * $Id$ * $HeadURL$ * $Author$ * Created by Hanna E. Rathje, SLSE, 2015-09-03 */ #include "handler_bccontamination.h" #include "handler_danger_area.h" #include "Utils/polygons.h" namespace AreaEffectSimulation { HandlerBCContamination::HandlerBCContamination(MainHandler *mainHandler) : HandlerBaseTmpl(mainHandler, QStringLiteral("BCContamination"), s_areaCount[static_cast(AesType::AtBCContamination)], s_areaCountCentral[static_cast(AesType::AtBCContamination)]) , Interface::Fts::BCContaminationModifyRequestHandler(mainHandler->dds()->fts()) , Interface::Fts::BCContaminationRemoveRequestHandler(mainHandler->dds()->fts()) {} bool HandlerBCContamination::init() { bool bRet = true; auto cb = [this, &bRet] (const Database::AesBCContamination &data) { ERROR_LOG(m_logger) << "TotalC: " << totalAreasCentral() << " Total: " << totalAreas(); ObjectBCContamination *ifs(new ObjectBCContamination(m_mainHandler, this)); connect(ifs, &ObjectBCContamination::effectStateChanged, this, &HandlerBCContamination::onEffectStateChanged); connect(ifs, &ObjectBCContamination::changedToCentral, this, &HandlerBCContamination::onChangedToCentral); Core::FunctionReplyObject ret = ifs->createObject(data); if (ret.error()) { delete ifs; ERROR_LOG(m_logger) << ret(); bRet = false; return; } if(!ifs->data().isCentral) { if (totalAreas() >= (s_maxActiveAreas[static_cast(AesType::AtBCContamination)] + s_maxActiveAreas[static_cast(AesType::AtNContamination)])) { ERROR_LOG(m_logger) << "More active bc contaminationsin database than allowed - ignoring the rest!"; ifs->removeObject(); delete ifs; return; } } else { if (totalAreasCentral() >= (s_maxActiveAreasCentral[static_cast(AesType::AtBCContamination)] + s_maxActiveAreasCentral[static_cast(AesType::AtNContamination)])) { ERROR_LOG(m_logger) << "More active bc contaminationsin database than allowed - ignoring the rest!"; ifs->removeObject(); delete ifs; return; } } m_objectMap.insert(ifs->id(), ifs); connect(ifs, &ObjectBCContamination::newAiv, this, &HandlerBCContamination::newAiv); connect(ifs, &ObjectBCContamination::removeAiv, this, &HandlerBCContamination::removeAiv); if (ifs->isObjectInTrainingArea()) { if (ifs->data().isCentral) ++m_areaCountCentral; else ++m_areaCount; } }; if (!m_mainHandler->db()->select(cb) || !bRet) { ERROR_LOG(m_logger) << "Error reading data from database!"; return true; } DEBUG_LOG(m_logger) << "m_exeObjMap.size() = " << m_objectMap.size(); DEBUG_LOG(m_logger) << "m_areaCount = " << m_areaCount; DEBUG_LOG(m_logger) << "m_areaCountCentral = " << m_areaCountCentral; return true; } int HandlerBCContamination::totalAreas() const { return s_areaCount[static_cast(AesType::AtBCContamination)] + s_areaCount[static_cast(AesType::AtNContamination)]; } int HandlerBCContamination::totalAreasCentral() const { return s_areaCountCentral[static_cast(AesType::AtBCContamination)] + s_areaCountCentral[static_cast(AesType::AtNContamination)]; } void HandlerBCContamination::onChangedToCentral() { s_areaCount[static_cast(AesType::AtBCContamination)]--; s_areaCountCentral[static_cast(AesType::AtBCContamination)]++; DEBUG_LOG(m_logger) << "m_areaCount after Recount = " << m_areaCount; DEBUG_LOG(m_logger) << "m_areaCountCentral after Recount = " << m_areaCountCentral; } static void fillData(const BCContaminationModifyRequest &src, Database::AesBCContamination &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.impactPosition.rx() = src.impactPosition.lon; dst.impactPosition.ry() = src.impactPosition.lat; dst.impactRadius = src.impactRadius; 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.weatherSourceId = src.weatherSource; dst.externalId = src.externalId.is_set() ? src.externalId.get() : 0; dst.upperOffset = src.upperOffset; dst.lowerOffset = src.lowerOffset; // weather parameter are delivered, when adding in OC-laptop if (src.weatherPosition.is_set()) { dst.weatherPosition.rx() = src.weatherPosition.get().lon; dst.weatherPosition.ry() = src.weatherPosition.get().lat; } else dst.weatherPosition = dst.impactPosition; // initial, is not used during update therefore it's ok here if(src.windSpeed.is_set()) dst.windSpeed = src.windSpeed.get(); if(src.propagationDirection.is_set()) dst.propagationDirection = src.propagationDirection.get(); if(src.weatherTimestamp.is_set()) dst.weatherTimestamp = QDateTime::fromMSecsSinceEpoch(src.weatherTimestamp.get()); else if(src.effectStart.is_set()) dst.weatherTimestamp = QDateTime::fromMSecsSinceEpoch(src.effectStart.get()); } void HandlerBCContamination::onBCContaminationModifyRequest(const rti::core::SampleIdentity &cookie, const BCContaminationModifyRequest &request) { DEBUG_LOG(m_logger) << "onBCContaminationModifyRequest: " << request; const Core::FunctionReplyObject ret = bCContaminationModifyRequest(request); if (ret.error()) WARNING_LOG(m_logger) << ret(); m_mainHandler->dds()->fts()->bCContaminationModifyReply(cookie, ret); } Core::FunctionReplyObject HandlerBCContamination::bCContaminationCreateRequest(const BCContaminationModifyRequest &request) { Database::AesBCContamination newData; fillData(request, newData); ObjectBCContamination *ifs(new ObjectBCContamination(m_mainHandler, this)); connect(ifs, &ObjectBCContamination::effectStateChanged, this, &HandlerBCContamination::onEffectStateChanged); Core::FunctionReplyObject ret = ifs->createObject(newData); if (ret.error()) { delete ifs; return ret; } ERROR_LOG(m_logger) << "Is Central: " << ifs->data().isCentral << " upperOffset=" << ifs->data().upperOffset << " lowerOffset=" << ifs->data().lowerOffset; if (ifs->data().isCentral) { if (totalAreasCentral() >= (s_maxActiveAreasCentral[static_cast(AesType::AtBCContamination)] + s_maxActiveAreasCentral[static_cast(AesType::AtNContamination)]) && 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 B/C or N contamination areas.")); } } else { if (totalAreas() >= (s_maxActiveAreas[static_cast(AesType::AtBCContamination)] + s_maxActiveAreas[static_cast(AesType::AtNContamination)]) && 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 B/C or N contamination areas.")); } } connect(ifs, &ObjectBCContamination::newAiv, this, &HandlerBCContamination::newAiv); connect(ifs, &ObjectBCContamination::removeAiv, this, &HandlerBCContamination::removeAiv); if (ifs->data().isCentral) { ++m_areaCountCentral; DEBUG_LOG(m_logger) << "s_areaCountCentral[AesType::AtBCContamination] = " << m_areaCountCentral; } else if (ifs->isObjectInTrainingArea()) { ++m_areaCount; DEBUG_LOG(m_logger) << "s_areaCount[AesType::AtBCContamination] = " << m_areaCount; } else { DEBUG_LOG(m_logger) << "Counting of [AesType::AtBCContamination] not affected"; } m_objectMap.insert(ifs->id(), ifs); if (request.withDangerArea.is_set() && request.withDangerArea.get()) { DangerAreaModifyRequest req; req.id = 0; #ifdef GUEZ_MODE const QString name = QString::fromStdString(tr_lts("dds","%1 - Gefahrenbereich")).arg(ifs->data().name); #else const QString name = QString::fromStdString(tr_lts("dds","%1 - Danger Area")).arg(ifs->data().name); #endif req.name = name.toStdString(); req.partyId = ifs->data().partyId; req.effectDuration = ifs->data().effectDuration; req.chargeTypeId = ifs->data().chargeTypeId; req.segments = Polygons::dangerAreaDefaultSegments(ifs->data().impactPosition, ifs->data().impactRadius + 50); req.associatedAesId = ifs->data().id; if(ifs->data().effectStart.isValid()) req.effectStart = ifs->data().effectStart.toMSecsSinceEpoch(); Core::FunctionReplyObject bretDangerArea= m_mainHandler->dangerAreaHandler()->dangerAreaCreateRequest(req); if (bretDangerArea.error()) ERROR_LOG(m_logger)<<"Couldn't create associated dangerArea to bcContamination: "<data().name; } return ret; } Core::FunctionReplyObject HandlerBCContamination::bCContaminationModifyRequest(const BCContaminationModifyRequest &request) { Core::FunctionReplyObject ret; ObjectBCContamination *ifs = nullptr; if (request.externalId.is_set() && request.externalId.get() > 0) ifs = getObjectFromMapByExternalId(m_objectMap, request.externalId.get(), ret); if (!ifs) { if (request.id == 0 || ((request.id < 0) && !getObjectFromMap(m_objectMap, std::abs(request.id), ret))) return bCContaminationCreateRequest(request); ifs = getObjectFromMap(m_objectMap, std::abs(request.id), ret); if (!ifs) return ret; } if (request.effectStart.is_set() && (request.effectStart.get() + request.effectDuration < m_mainHandler->dds()->currentPartitionTime().toMSecsSinceEpoch())) return removeObject(ifs); Database::AesBCContamination aea(ifs->data()); fillData(request, aea); DEBUG_LOG(m_logger) << "request.upperOffset=" << request.upperOffset << " request.lowerOffset=" << request.lowerOffset << " aea.upperOffset=" << aea.upperOffset << " aea.lowerOffset=" << aea.lowerOffset; // Calculate new polygon here. Not nice, though auto poly = Polygons::bcContamination(aea, m_mainHandler->dds()->pdmDtc()->volatilityTypeId(aea.chargeTypeId, aea.igniterTypeId, aea.igniterFunctionId), m_mainHandler->dds()->pdmDtc()->expansionFactor(aea.chargeTypeId, aea.igniterTypeId, aea.igniterFunctionId), m_mainHandler->dds()->currentPartitionTime()); 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[static_cast(AesType::AtBCContamination)] + s_maxActiveAreasCentral[static_cast(AesType::AtNContamination)]) /*&& request.effectStart.is_set()*/) { return Core::FunctionReplyObject(1, tr_lts("dds", "Too many active central B/C or N contamination areas.")); } } else { if (totalAreas() >= (s_maxActiveAreas[static_cast(AesType::AtBCContamination)] + s_maxActiveAreas[static_cast(AesType::AtNContamination)]) /*&& request.effectStart.is_set()*/) { return Core::FunctionReplyObject(1, tr_lts("dds", "Too many active B/C or N contamination areas.")); } } } // For counting, only Elements being at least prepared are important: if (request.effectStart.is_set() && ifs->isObjectModifiable()) { 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[static_cast(AesType::AtBCContamination)] + s_maxActiveAreas[static_cast(AesType::AtNContamination)])) return Core::FunctionReplyObject(request.id, tr_lts("dds", "Too many active B/C or N contamination areas.")); m_areaCount++; m_areaCountCentral--; DEBUG_LOG(m_logger) << "s_areaCount[AesType::AtBCContamination] = " << m_areaCount; DEBUG_LOG(m_logger) << "s_areaCountCentral[AesType::AtBCContamination] = " << m_areaCountCentral; } else // Change from training area to central { if (totalAreasCentral() >= (s_maxActiveAreasCentral[static_cast(AesType::AtBCContamination)] + s_maxActiveAreasCentral[static_cast(AesType::AtNContamination)])) return Core::FunctionReplyObject(request.id, tr_lts("dds", "Too many active central B/C or N contamination areas.")); m_areaCount--; m_areaCountCentral++; DEBUG_LOG(m_logger) << "s_areaCount[AesType::AtBCContamination] = " << m_areaCount; DEBUG_LOG(m_logger) << "s_areaCountCentral[AesType::AtBCContamination] = " << m_areaCountCentral; } } } if (request.id < 0 && checkStateForSfm(ifs)) { DEBUG_LOG(m_logger) << "Overwrite bc contamination Effect State for OC"; aea.effectStateId = AesEffectState::EsPrepared; } ret = ifs->updateObject(aea); // check / update danger area if(!ret.error()) { Database::AesDangerArea dangerArea; if (m_mainHandler->dangerAreaHandler()->getDangerAreaByAssociatedAesId(ifs->id(), &dangerArea)) { DEBUG_LOG(m_logger)<<"[bCContaminationModifyRequest] modify danger area associated to bcId: " <id() <<" dangerAreaId: "<data().impactPosition, ifs->data().impactRadius + 50); dangerRequest.associatedAesId = ifs->data().id; if(ifs->data().effectStart.isValid()) dangerRequest.effectStart = ifs->data().effectStart.toMSecsSinceEpoch(); Core::FunctionReplyObject bretDangerArea= m_mainHandler->dangerAreaHandler()->dangerAreaModifyRequest(dangerRequest); if (bretDangerArea.error()) ERROR_LOG(m_logger)<<"[bCContaminationModifyRequest] couldn't update danger area: bccontamination.id: "<id() <<" dangerArea.name: "<id(); DangerAreaModifyRequest newDangerRequest; newDangerRequest.id = 0; #ifdef GUEZ_MODE const QString name = QString::fromStdString(tr_lts("dds","%1 - Gefahrenbereich")).arg(ifs->data().name); #else const QString name = QString::fromStdString(tr_lts("dds","%1 - Danger Area")).arg(ifs->data().name); #endif newDangerRequest.name = name.toStdString(); newDangerRequest.partyId = ifs->data().partyId; newDangerRequest.effectDuration = ifs->data().effectDuration; newDangerRequest.chargeTypeId = ifs->data().chargeTypeId; newDangerRequest.segments = Polygons::dangerAreaDefaultSegments(ifs->data().impactPosition, ifs->data().impactRadius + 50); newDangerRequest.associatedAesId = ifs->data().id; if(ifs->data().effectStart.isValid()) newDangerRequest.effectStart = ifs->data().effectStart.toMSecsSinceEpoch(); Core::FunctionReplyObject bretDangerArea = m_mainHandler->dangerAreaHandler()->dangerAreaCreateRequest(newDangerRequest); if (bretDangerArea.error()) ERROR_LOG(m_logger)<<"[bCContaminationModifyRequest] couldn't add danger area: bccontamination.id: "<id() <<" dangerArea.name: "<dds()->fts()->bCContaminationRemoveReply(cookie, removeReply(&DatabaseInterface::removeAesBCContamination, request)); // remove if dangerarea is associated if (ret) { Database::AesDangerArea dangerArea; if (m_mainHandler->dangerAreaHandler()->getDangerAreaByAssociatedAesId(request.id, &dangerArea)) { bool bret = m_mainHandler->dangerAreaHandler()->dangerAreaRemoveRequest(Core::RemoveElementRequest(dangerArea.id)); if (!bret) ERROR_LOG(m_logger)<<"[onBCContaminationRemoveRequest] couldn't remove danger area: "<