/** * The ObjectMissionPlan class represents a ObjectMissionPlan. It holds the data and offers some conversion methods. * $Id$ * $HeadURL$ * $Author$ * Created by Steve Kemayou, ESZS, 2025-04-08 */ #include "object_mission_plan.h" #include namespace ParticipantManagement { namespace UasHandling { ObjectMissionPlan::ObjectMissionPlan(const std::shared_ptr &ddsHandler, const std::shared_ptr &db, const ParticipantManagement::MissionPlan & missionPlan, QObject *parent) : QObject(parent) , m_ddsHandler(ddsHandler) , m_db(db) , m_missionplan(missionPlan) , m_logger(getLogger("ObjectMissionPlan")) { DEBUG_LOG(m_logger)<<" - ctor ObjectMissionPlan: planId: "< &dbItems, const QMap &dbActions) { m_mapMissionItems.clear(); m_dbMissionActions.clear(); for (const ParticipantManagement::Database::PpmMissionItem &item : qAsConst(dbItems)) { ParticipantManagement::MissionItem msi; msi.actions().reserve(dbActions.size()); msi.name(item.name.toStdString()); msi.location(Core::GeoPosition(item.location.x(), item.location.y(), item.location.z())); msi.itemNumber(item.elementNumber); std::vector actionsVec; for (const auto &action : dbActions) { if (action.missionItemId == item.id) { ParticipantManagement::MissionAction msa; msa.actionType(action.missionActionTypeId); msa.duration(action.duration); msa.fulfilled(action.fulfilled.toMSecsSinceEpoch()); msa.properties(action.properties.toStdString()); msa.name(action.name.toStdString()); msa.actionNumber(action.elementNumber); msa.planId(item.missionPlanId); msi.actions().push_back(msa); actionsVec.push_back(action); } } m_mapMissionItems.insert(item.id, msi); m_dbMissionActions.push_back(actionsVec); } } const MissionPlan &ObjectMissionPlan::missionPlan() const { return m_missionplan; } Core::FunctionReplyObject ObjectMissionPlan::createMissionPlan(Database::PpmMissionPlan newMissionPlan, const std::vector &missionItems) { /// 1- insert in DB Mission plan /// 2- insert in DB Mission Items /// 3- insert in DB Mission Actions DBTransaction trans(m_db->database()); newMissionPlan.aborted = false; if (!m_db->insert(newMissionPlan)) { QString error = QStringLiteral("Could not insert mission plan into database"); ERROR_LOG(m_logger)<< error; return Core::FunctionReplyObject(error.toStdString().c_str()); } std::vector itemVec = missionItems; m_mapMissionItems.clear(); m_mapMissionItems.reserve(itemVec.size()); std::vector>itemsVec; m_dbMissionActions.clear(); for ( auto &item : itemVec) { Database::PpmMissionItem dbItem; dbItem.missionPlanId = newMissionPlan.id; dbItem.name = QString::fromStdString(item.name()); dbItem.elementNumber = item.itemNumber(); dbItem.location = LtsUtils::QPoint3D(item.location().lon(),item.location().lat(), item.location().z()); if (!m_db->insert(dbItem)) return Core::FunctionReplyObject(0, tr_lts("dds", "Error adding 'Mission Item' to database")); std::vector actionsVec; actionsVec.reserve(item.actions().size()); for (auto &action : item.actions()) { action.planId(newMissionPlan.id); Database::PpmMissionAction dbAction; dbAction.missionActionTypeId = action.actionType(); dbAction.missionItemId = dbItem.id; dbAction.duration = action.duration(); dbAction.name = QString::fromStdString(action.name()); dbAction.properties = QString::fromStdString(action.properties()); dbAction.fulfilled = QDateTime::fromMSecsSinceEpoch(action.fulfilled()); dbAction.elementNumber = action.actionNumber(); if (!m_db->insert(dbAction)) return Core::FunctionReplyObject(0, tr_lts("dds", "Error adding 'Mission Action' to database")); actionsVec.push_back(dbAction); }//loop mission actions m_mapMissionItems.insert(dbItem.id, item); m_dbMissionActions.push_back(actionsVec); // [elNumber][actionNumber] }//loop mission items m_missionplan.id(newMissionPlan.id); m_missionplan.name(newMissionPlan.name.toStdString()); m_missionplan.missionStart(newMissionPlan.missionStart.toMSecsSinceEpoch()); m_missionplan.participantId(newMissionPlan.participantId); m_missionplan.jumpToStart(newMissionPlan.jumpToStart); m_missionplan.repeat(newMissionPlan.repeat); m_missionplan.items(itemVec); m_missionplan.fulfilled(0); m_missionplan.itemsFulfilled(0); for (auto &item : m_missionplan.items()) { for (auto &action : item.actions()) DEBUG_LOG(m_logger)<<"[CREATE] itemIdx: "<> [NEW] mission plan with id( "< &missionItems) { if (missionItems.size() == 0) return Core::FunctionReplyObject(newMissionPlan.id, tr_lts("dds", "Could not modify MissionPlan without segments.")); /// 1- update missipn plan table /// 2- remove items and their actions /// 3- insert new items and their actions DBTransaction trans(m_db->database()); const auto tmpDbMissionItems = m_mapMissionItems; newMissionPlan.aborted = false; /// update mission plan table if (!m_db->update(newMissionPlan)) { QString error = QStringLiteral("Could not update mission plan! "); ERROR_LOG(m_logger)<< error; return Core::FunctionReplyObject(error.toStdString().c_str()); } /// remove all items and their actions from the database for (const auto &itemId : tmpDbMissionItems.keys()) { if (!m_db->removePpmMissionItem(itemId)) { QString error = QStringLiteral("Could not remove mission plan from database"); ERROR_LOG(m_logger)<< error; return Core::FunctionReplyObject(0, tr_lts("dds", "Could not update mission plan into!")); } } /// insert new items with their actions in the data base; m_mapMissionItems.clear(); m_mapMissionItems.reserve(missionItems.size()); m_dbMissionActions.clear(); std::vector itemVec = missionItems; for (auto &item : itemVec) { Database::PpmMissionItem dbItem; dbItem.missionPlanId = newMissionPlan.id; dbItem.name = QString::fromStdString(item.name()); dbItem.elementNumber = item.itemNumber(); dbItem.location = LtsUtils::QPoint3D(item.location().lon(),item.location().lat(), item.location().z()); if (!m_db->insert(dbItem)) return Core::FunctionReplyObject(0, tr_lts("dds", "Error adding 'Mission Item' to database")); std::vector actionsVec; actionsVec.reserve(item.actions().size()); for (auto &action : item.actions()) { action.planId(newMissionPlan.id); Database::PpmMissionAction dbAction; dbAction.missionActionTypeId = action.actionType(); dbAction.missionItemId = dbItem.id; dbAction.duration = action.duration(); dbAction.name = QString::fromStdString(action.name()); dbAction.properties = QString::fromStdString(action.properties()); dbAction.fulfilled = QDateTime::fromMSecsSinceEpoch(action.fulfilled()); dbAction.elementNumber = action.actionNumber(); if (!m_db->insert(dbAction)) return Core::FunctionReplyObject(0, tr_lts("dds", "Error adding 'Mission Action' to database")); actionsVec.push_back(dbAction); }//loop mission actions m_mapMissionItems.insert(dbItem.id, item); m_dbMissionActions.push_back(actionsVec); // [elNumber][actionNumber] }//loop mission items trans.commit(); m_missionplan.id(newMissionPlan.id); m_missionplan.name(newMissionPlan.name.toStdString()); m_missionplan.missionStart(newMissionPlan.missionStart.toMSecsSinceEpoch()); m_missionplan.participantId(newMissionPlan.participantId); m_missionplan.jumpToStart(newMissionPlan.jumpToStart); m_missionplan.repeat(newMissionPlan.repeat); m_missionplan.items(itemVec); m_missionplan.itemsFulfilled(0); // on update items and action entries will be cleared m_missionplan.fulfilled(0); DEBUG_LOG(m_logger)<< ">> [UPDATE] mission plan with id( "<database()); if (!m_db->removePpmMissionPlan(id)) { QString error = QStringLiteral("Could not remove mission plan ! "); ERROR_LOG(m_logger)<< error; return Core::FunctionReplyObject(error.toStdString().c_str()); } trans.commit(); m_dbMissionActions.clear(); m_mapMissionItems.clear(); DEBUG_LOG(m_logger)<< ">> [REMOVE] mission Action with id( "< missionplan is aborted. only update missionPlan table with status aborted = true //1- get db mission action from actionNumber //2- set mission action as fulfilled //3- set mission action save in db //4- update cache data if (!m_db) { ERROR_LOG(m_logger) << "no init yet...."; return Core::FunctionReplyObject(""); } if (req.missionId() != m_missionplan.id()) { QString error = QStringLiteral("Wrong missionPlan Object caught Request: %1 / currPlanId: %2").arg(req.missionId()).arg(m_missionplan.id()); ERROR_LOG(m_logger)<< error; return Core::FunctionReplyObject(error.toStdString().c_str()); } // Abort in case itemNumb=-1 && actionNumb=-1 if (req.actionNumber() < 0 && req.itemNumber() < 0) { m_missionplan.aborted(true); return setMissionPlanAborted(true); } auto &dbActions = m_dbMissionActions[req.itemNumber()]; //[elemNum][actionNum] if (dbActions.empty() || req.actionNumber() >= static_cast(dbActions.size()) || req.actionNumber() < 0 || req.itemNumber() < 0) // actionNumber start by 0 { QString error = QStringLiteral("Could not set mission action with id: %1 ! ").arg(req.actionNumber()); ERROR_LOG(m_logger)<< error; return Core::FunctionReplyObject(error.toStdString().c_str()); } Database::PpmMissionAction &dbAction = dbActions[req.actionNumber()]; dbAction.fulfilled = QDateTime::fromMSecsSinceEpoch(currentTimeMSec); if (!m_db->update(dbAction)) { QString error = QStringLiteral("Could not update mission action! "); ERROR_LOG(m_logger)<< error; return Core::FunctionReplyObject(error.toStdString().c_str()); } //update item in case actions fulfilled //1- actions count //2- number of actions fulfilled //3- check if action count == item.actions.size() //4- if yes update missioPlan & missionItem fulfilled MissionItem &msi = m_mapMissionItems[dbAction.missionItemId]; msi.fulfilled(dbAction.fulfilled.toMSecsSinceEpoch()); msi.actionsFulfilled(msi.actionsFulfilled() + 1); MissionAction &msa = m_mapMissionItems[dbAction.missionItemId].actions()[dbAction.elementNumber]; msa.fulfilled(dbAction.fulfilled.toMSecsSinceEpoch()); m_missionplan.items()[req.itemNumber()] = m_mapMissionItems[dbAction.missionItemId]; // item in MissionPlan updated through elementNumber /// update fulfilled time for items and mission plan /// update fulfilled items count int numbItemFulfilled = 0; for(const auto &item : m_mapMissionItems) { if (item.actionsFulfilled() == static_cast(item.actions().size())) numbItemFulfilled++; } m_missionplan.itemsFulfilled(numbItemFulfilled); m_missionplan.fulfilled(dbAction.fulfilled.toMSecsSinceEpoch()); return Core::FunctionReplyObject(m_missionplan.id()); } Core::FunctionReplyObject ObjectMissionPlan::setMissionPlanAborted(bool state) { DEBUG_LOG(m_logger)<<" -- [setMissionPlanAborted] abort mission plan: "<selectPpmMissionPlan(m_missionplan.id(),dbMissionPlan); dbMissionPlan.missionStart = QDateTime::fromMSecsSinceEpoch(m_missionplan.missionStart()); dbMissionPlan.jumpToStart = m_missionplan.jumpToStart(); dbMissionPlan.id = m_missionplan.id(); dbMissionPlan.name = QString::fromStdString(m_missionplan.name()); dbMissionPlan.participantId = m_missionplan.participantId(); dbMissionPlan.repeat = m_missionplan.repeat(); dbMissionPlan.aborted = state; /// update mission plan table if (!m_db->update(dbMissionPlan)) { QString error = QStringLiteral("Could not update mission plan! "); ERROR_LOG(m_logger)<< error; return Core::FunctionReplyObject(error.toStdString().c_str()); } return Core::FunctionReplyObject(m_missionplan.id()); } } // namespace UasHandling } // namespace ParticipantManagement