/** * Handler for all exercise objects * $Id$ * $HeadURL$ * $Author$ * Created by Hanna E. Rathje, SLSE, 2015-09-03 */ #include "handler_explosion_area.h" #include "handler_charge_administration.h" #include #include namespace AreaEffectSimulation { HandlerExplosionArea::HandlerExplosionArea(MainHandler *mainHandler) : HandlerBaseTmpl(mainHandler, QStringLiteral("ExplosionArea"), s_areaCount[AesType::AtExplosionArea], s_areaCountCentral[AesType::AtExplosionArea]) , Interface::Fts::ExplosionAreaModifyRequestHandler(mainHandler->dds()->fts()) , Interface::Fts::ExplosionAreaRemoveRequestHandler(mainHandler->dds()->fts()) , Interface::Fts::ExplosionAreaPauseResumeRequestHandler(m_mainHandler->dds()->fts()) { } bool HandlerExplosionArea::init() { // create area explosion objects bool bRet = true; auto cb = [this, &bRet] (const Database::AesExplosionArea &data) { ObjectExplosionArea *ifs(new ObjectExplosionArea(m_mainHandler, this)); connect(ifs, &ObjectExplosionArea::effectStateChanged, this, &HandlerExplosionArea::onEffectStateChanged); 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[AesType::AtExplosionArea] + s_maxActiveAreas[AesType::AtExplosionSingle])) { ERROR_LOG(m_logger) << "More active explosion areas in database than allowed - ignoring the rest!"; ifs->removeObject(); delete ifs; return; } } else { if (totalAreasCentral() >= (s_maxActiveAreasCentral[AesType::AtExplosionArea] + s_maxActiveAreasCentral[AesType::AtExplosionSingle])) { ERROR_LOG(m_logger) << "More active explosion areas in database than allowed - ignoring the rest!"; ifs->removeObject(); delete ifs; return; } } if (ifs->isObjectInTrainingArea()) { if (ifs->data().isCentral) ++m_areaCountCentral; else ++m_areaCount; } m_objectMap.insert(ifs->id(), ifs); connect(ifs, &ObjectExplosionArea::newAiv, this, &HandlerExplosionArea::newAiv); connect(ifs, &ObjectExplosionArea::removeAiv, this, &HandlerExplosionArea::removeAiv); }; if (!m_mainHandler->db()->select(cb) || !bRet) { ERROR_LOG(m_logger) << "Error reading data from database!"; return false; } 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 HandlerExplosionArea::totalAreas() const { return s_areaCount[AesType::AtExplosionArea] + s_areaCount[AesType::AtExplosionSingle]; } int HandlerExplosionArea::totalAreasCentral() const { return s_areaCountCentral[AesType::AtExplosionArea] + s_areaCountCentral[AesType::AtExplosionSingle]; } static void fillData(const ExplosionAreaModifyRequest &src, Database::AesExplosionArea &dst) { if (src.id() < 0) // is the id given as negative? set id -> used by OC-Laptop dst.id = src.id(); dst.impactPosition.rx() = src.area().cornerBottomLeft().lon(); dst.impactPosition.ry() = src.area().cornerBottomLeft().lat(); dst.rotationAngle = src.area().rotation(); 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.effectSourceId = src.effectSourceId(); dst.impactLength = src.area().height(); dst.impactWidth = 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.cannonCount = src.cannonCount(); dst.cannonRounds = src.cannonRounds(); dst.altitude = src.altitude(); dst.firePurpose = QString::fromStdString(src.purpose()); dst.fireRequestTime = QDateTime::fromMSecsSinceEpoch(src.fireRequestTime()); dst.effectMarkingInTa = src.effectMarkingInTa(); dst.externalId = src.externalId().is_set() ? src.externalId().get() : 0; } void HandlerExplosionArea::onExplosionAreaModifyRequest(const rti::core::SampleIdentity &cookie, const ExplosionAreaModifyRequest &request) { DEBUG_LOG(m_logger) << "onExplosionAreaModifyRequest: " << request; Core::FunctionReplyObject ret = explosionAreaModifyRequest(request); if (ret.error()) WARNING_LOG(m_logger) << ret(); m_mainHandler->dds()->fts()->explosionAreaModifyReply(cookie, ret); } Core::FunctionReplyObject HandlerExplosionArea::explosionAreaCreateRequest(const ExplosionAreaModifyRequest &request) { if (!request.partyId().is_set()) return Core::FunctionReplyObject(tr_lts("dds", "Explosion areas need a party id.")); int chargeNeeded = request.cannonCount() * request.cannonRounds(); if (chargeNeeded <= 0) return Core::FunctionReplyObject(tr_lts("dds", "Invalid impact count (cannon round or cannon count <= 0).")); if (request.id() == 0) { int chargeLeft = m_mainHandler->chargeAdministrationHandler()->availableCharge(request.chargeTypeId(), request.partyId().get()); if (chargeNeeded > chargeLeft) return Core::FunctionReplyObject(tr_lts("dds", "Invalid impact count (%1 charges needed but only %2 charges available for Charge Id %3 and Party Id %4).")) .arg(chargeNeeded) .arg(chargeLeft) .arg(request.chargeTypeId()) .arg(request.partyId().get()); } Database::AesExplosionArea newData; fillData(request, newData); // check: effectStart > time(NULL) ? ObjectExplosionArea *ifs(new ObjectExplosionArea(m_mainHandler, this)); connect(ifs, &ObjectExplosionArea::effectStateChanged, this, &HandlerExplosionArea::onEffectStateChanged); const Core::FunctionReplyObject ret = ifs->createObject(newData); if (ret.error()) { delete ifs; return ret; } if (ifs->data().isCentral) { if (totalAreasCentral() >= (s_maxActiveAreasCentral[AesType::AtExplosionArea] + s_maxActiveAreasCentral[AesType::AtExplosionSingle]) && 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 explosion areas and explosion singles")); } } else { if (totalAreas() >= (s_maxActiveAreas[AesType::AtExplosionArea] + s_maxActiveAreas[AesType::AtExplosionSingle]) && 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 explosion areas and explosion singles")); } } if (ifs->data().isCentral) { ++m_areaCountCentral; DEBUG_LOG(m_logger) << "m_areaCountCentral " << m_areaCountCentral; } else if (ifs->isObjectInTrainingArea()) { ++m_areaCount; DEBUG_LOG(m_logger) << "m_areaCount = " << m_areaCount; } else { DEBUG_LOG(m_logger) << "Counting of [AesType::AtExplosionArea] not affected"; } m_objectMap.insert(ifs->id(), ifs); connect(ifs, &ObjectExplosionArea::newAiv, this, &HandlerExplosionArea::newAiv); connect(ifs, &ObjectExplosionArea::removeAiv, this, &HandlerExplosionArea::removeAiv); return ret; } Core::FunctionReplyObject HandlerExplosionArea::explosionAreaModifyRequest(const ExplosionAreaModifyRequest &request) { Core::FunctionReplyObject ret; if (request.id() == 0 || ((request.id() < 0) && !getObjectFromMap(m_objectMap, std::abs(request.id()), ret))) return explosionAreaCreateRequest(request); ObjectExplosionArea *ifs = getObjectFromMap(m_objectMap, std::abs(request.id()), ret); if (!ifs) return ret; // Todo: IsObjectModifiable() ?!? AreaEffectSimulation::Database::AesExplosionArea aea(ifs->data()); fillData(request, aea); auto poly = Polygons::explosionArea(aea); std::vector _form; ObjectBase::ddsVecFromPoly(poly, _form); bool isCentral = ifs->checkIsCentral(_form); bool wasCentral = ifs->data().isCentral; /*! * Check if the max amount is reached if the effect start added after creation. !*/ if(!ifs->isActivationTimeSet() && request.effectStart().is_set()) { if (isCentral) { if (totalAreasCentral() >= (s_maxActiveAreasCentral[AesType::AtExplosionArea] + s_maxActiveAreasCentral[AesType::AtExplosionSingle])) { return Core::FunctionReplyObject(1, tr_lts("dds", "Too many active central explosion areas and explosion singles")); } } else { if (totalAreas() >= (s_maxActiveAreas[AesType::AtExplosionArea] + s_maxActiveAreas[AesType::AtExplosionSingle])) { return Core::FunctionReplyObject(1, tr_lts("dds", "Too many active explosion areas and explosion singles")); } } } // For counting, only Elements being at least prepared are important: if (request.effectStart().is_set() && ifs->isObjectModifiable()) { // Calculate new polygon here. Not nice, though 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::AtExplosionArea] + s_maxActiveAreas[AesType::AtExplosionSingle])) return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Too many active explosion areas and explosion singles")); m_areaCount++; m_areaCountCentral--; DEBUG_LOG(m_logger) << "s_areaCount[AesType::AtExplosionArea] = " << m_areaCount; DEBUG_LOG(m_logger) << "s_areaCountCentral[AesType::AtExplosionArea] = " << m_areaCountCentral; } else // Change from training area to central { if (totalAreasCentral() >= (s_maxActiveAreasCentral[AesType::AtExplosionArea] + s_maxActiveAreasCentral[AesType::AtExplosionSingle])) return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Too many active central explosion areas and explosion singles")); m_areaCount--; m_areaCountCentral++; DEBUG_LOG(m_logger) << "s_areaCount[AesType::AtExplosionArea] = " << m_areaCount; DEBUG_LOG(m_logger) << "s_areaCountCentral[AesType::AtExplosionArea] = " << m_areaCountCentral; } } } if (request.id() < 0 && checkStateForSfm(ifs)) { DEBUG_LOG(m_logger) << "Overwrite Effect State for OC"; aea.effectStateId = AesEffectState::EsPrepared; } return ifs->updateObject(aea); } Core::FunctionReplyObject HandlerExplosionArea::explosionAreaModifyGeometryRequest(const ExplosionAreaModifyRequest &request) { // WARNING: request.area.cornerBottomLeft() contains center point! Core::FunctionReplyObject ret; ObjectExplosionArea *ifs = getObjectFromMap(m_objectMap, 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::AtExplosionArea] + s_maxActiveAreas[AesType::AtExplosionSingle]) && request.effectStart().is_set() && !ifs->isActivationTimeSet() // if time was not set before change and now check count && !ifs->isObjectModifiable()) return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Too many active explosion areas and explosion singles")); // Todo: IsObjectModifiable() ?!? AreaEffectSimulation::Database::AesExplosionArea aea(ifs->data()); aea.impactPosition = Polygons::centerPoint2BottomLeft(QPointF(request.area().cornerBottomLeft().lon(), request.area().cornerBottomLeft().lat()), ifs->data().impactWidth, ifs->data().impactLength, request.area().rotation()); aea.rotationAngle = request.area().rotation(); return ifs->updateObject(aea); } Core::FunctionReplyObject HandlerExplosionArea::modifyPartyParticipant(qint32 itemId, qint32 partyId, qint32 participantId) { ObjectExplosionArea *ifs = m_objectMap.value(itemId); if (!ifs) return Core::FunctionReplyObject(itemId, tr_lts("dds", "Explosion Area with id %1 not found.")).arg(itemId); AreaEffectSimulation::Database::AesExplosionArea aea(ifs->data()); aea.partyId = partyId; aea.participantId= participantId; return ifs->updateObject(aea); } void HandlerExplosionArea::onExplosionAreaRemoveRequest(const rti::core::SampleIdentity &cookie, const Core::RemoveElementRequest &request) { m_mainHandler->dds()->fts()->explosionAreaRemoveReply(cookie, removeReply(&DatabaseInterface::removeAesExplosionArea, request)); } void HandlerExplosionArea::onExplosionAreaPauseResumeRequest(const rti::core::SampleIdentity &cookie, const ExplosionAreaPauseResumeRequest &request) { DEBUG_LOG(m_logger) << "onExplosionAreaPauseResumeRequest" << request; Core::FunctionReplyObject ret; ObjectExplosionArea *ifs = getObjectFromMap(m_objectMap, request.id(), ret); if (!ifs) { m_mainHandler->dds()->fts()->explosionAreaPauseResumeReply(cookie, ret); return; } ret = ifs->resumePause(request); if (ret.error()) ERROR_LOG(m_logger) << ret(); m_mainHandler->dds()->fts()->explosionAreaPauseResumeReply(cookie, ret); } } // Namespace AreaEffectSimulation