/** * 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 #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 QMultiMap &dbActions) { m_mapMissionItems.clear(); m_dbMissionActions.clear(); for (const ParticipantManagement::Database::PpmMissionItem &item : std::as_const(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