2027 lines
86 KiB
C++
Executable File
2027 lines
86 KiB
C++
Executable File
/**
|
|
* The ParticipantHandler class manages all participant related function topics and holds classes for
|
|
* further participant data.
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
* Created by Hannes Baeuerle, SLSE, 2016-05-12
|
|
*/
|
|
#include "participant_handler_for_exercise.h"
|
|
|
|
#include "convert_db_to_dds.h"
|
|
#include "firing_unit_validator.h"
|
|
#include "main_handler.h"
|
|
#include "participant_for_exercise.h"
|
|
#include "proxy_listener.h"
|
|
#include "settings.h"
|
|
#include "unit_position_calculator.h"
|
|
|
|
#include <AreaEffectSimulation/handler_charge_administration.h>
|
|
#include <LtsCoordTrans/lts_coord_trans.h>
|
|
#include <ParticipantManagement/ppm_record_replay_plugin.h>
|
|
#include <ngldb/dbtransaction.h>
|
|
|
|
#include <QJsonArray>
|
|
#include <QJsonDocument>
|
|
#include <QJsonObject>
|
|
#include <QTimer>
|
|
#include <QVector>
|
|
#include <QtGui/QTransform>
|
|
|
|
namespace ParticipantManagement
|
|
{
|
|
namespace ParticipantHandling
|
|
{
|
|
static int s_tabRequestId = 1;
|
|
|
|
static inline Database::PpmParticipant toDbParticipant(const ParticipantData ¤tData, bool withId = false)
|
|
{
|
|
// create db participant
|
|
Database::PpmParticipant newDbParticipant;
|
|
|
|
if (withId)
|
|
newDbParticipant.id = currentData.id();
|
|
newDbParticipant.partyId = currentData.partyId();
|
|
newDbParticipant.typeId = currentData.typeId();
|
|
newDbParticipant.externalId = currentData.externalId();
|
|
newDbParticipant.name = QString::fromStdString(currentData.name());
|
|
newDbParticipant.identification = QString::fromStdString(currentData.identification());
|
|
newDbParticipant.symbol = QString::fromStdString(currentData.symbol());
|
|
newDbParticipant.info = QString::fromStdString(currentData.info());
|
|
newDbParticipant.designator = QString::fromStdString(currentData.designator());
|
|
newDbParticipant.tacticalIdentifier = QString::fromStdString(currentData.tacticalIdentifier());
|
|
newDbParticipant.isDeleted = currentData.isDeleted();
|
|
newDbParticipant.isSimulated = currentData.isSimulated();
|
|
newDbParticipant.assignState = currentData.assignState();
|
|
if (currentData.equipmentNumber().is_set())
|
|
newDbParticipant.equipmentNumber = currentData.equipmentNumber().get();
|
|
newDbParticipant.hierarchyNumber = currentData.hierarchyNumber();
|
|
newDbParticipant.properties = QString::fromStdString(currentData.properties());
|
|
|
|
return newDbParticipant;
|
|
}
|
|
|
|
static inline ParticipantOrganisationEx toDds(const Database::PpmParticipantOrganisation &db)
|
|
{
|
|
ParticipantOrganisationEx ret;
|
|
ret.dbId = db.id;
|
|
ret.participantId(db.participantId);
|
|
ret.originPartyId(db.originPartyId);
|
|
ret.currentPartyId(db.currentPartyId);
|
|
ret.isAttached(db.isAttached);
|
|
ret.isCooperate(db.isCooperate);
|
|
return ret;
|
|
}
|
|
|
|
static inline Database::PpmParticipantOrganisation toDb(const ParticipantOrganisationEx &dds)
|
|
{
|
|
Database::PpmParticipantOrganisation ret;
|
|
ret.id = dds.dbId;
|
|
ret.participantId = dds.participantId();
|
|
ret.originPartyId = dds.originPartyId();
|
|
ret.currentPartyId = dds.currentPartyId();
|
|
ret.isAttached = dds.isAttached();
|
|
ret.isCooperate = dds.isCooperate();
|
|
return ret;
|
|
}
|
|
|
|
//
|
|
// ParticipantHandlerForExercise
|
|
//
|
|
ParticipantHandlerForExercise::ParticipantHandlerForExercise(MainHandler *mainHandler)
|
|
: ParticipantHandler(mainHandler, "ParticipantHandler")
|
|
, Interface::Fts::ModifyStateRequestHandler(mainHandler->fts())
|
|
, Interface::Fts::ModifyParticipantDataRequestHandler(mainHandler->fts())
|
|
, Interface::Fts::InitParticipantRequestHandler(mainHandler->fts())
|
|
, Interface::Fts::SetParticipantModeRequestHandler(mainHandler->fts())
|
|
, Interface::Fts::SendMessageRequestHandler(mainHandler->fts())
|
|
, Interface::Fts::RegisterParticipantRequestHandler(mainHandler->fts())
|
|
, Interface::Fts::SetSimulatedPositionRequestHandler(mainHandler->fts())
|
|
, Interface::Fts::SetSimulatedPositionRelativeRequestHandler(mainHandler->fts())
|
|
, Interface::Fts::SetSimulatedParticipantFormationRequestHandler(mainHandler->fts())
|
|
, Interface::Fts::SetSanitationRequestHandler(mainHandler->fts())
|
|
, Interface::Fts::SelectiveReammunitionRequestHandler(mainHandler->fts())
|
|
, Interface::Fts::SetAsSimulatedRequestHandler(mainHandler->fts())
|
|
, Interface::Fts::OcCommandRequestHandler(mainHandler->fts())
|
|
, Interface::Fts::ModifyUasStateRequestHandler(mainHandler->fts())
|
|
, m_mainHandler(mainHandler)
|
|
, m_hitLineInfoTimer(new QTimer(this))
|
|
, m_publishEquipmentExerciseMappingsTimer(new QTimer(this))
|
|
, m_publishEquipmentExerciseMappings(true)
|
|
{
|
|
m_publishEquipmentExerciseMappingsTimer->setSingleShot(true);
|
|
connect(m_publishEquipmentExerciseMappingsTimer, &QTimer::timeout, this, &ParticipantHandlerForExercise::publishEquipmentExerciseMapping);
|
|
}
|
|
|
|
ParticipantHandlerForExercise::~ParticipantHandlerForExercise()
|
|
{
|
|
m_mainHandler->exAnyDts()->removeEquipmentExerciseMappingByKey(m_mainHandler->exerciseId());
|
|
m_proxyListener = nullptr;
|
|
delete m_hitLineInfoTimer;
|
|
}
|
|
|
|
bool ParticipantHandlerForExercise::init()
|
|
{
|
|
ParticipantHandler::init();
|
|
|
|
if (m_firingUnitValidator)
|
|
{
|
|
delete m_firingUnitValidator;
|
|
m_firingUnitValidator = nullptr;
|
|
}
|
|
|
|
if (m_mainHandler)
|
|
m_firingUnitValidator = new FiringUnitValidator(m_mainHandler->participantHandler(), m_mainHandler->typeHandler(), this);
|
|
|
|
std::shared_ptr<DatabaseInterface> dbEx0 = m_mainHandler->dbEx0();
|
|
auto cbEem = [this](const Database::EquipmentExerciseMapping &eem) { m_equipmentExerciseMappings[eem.equipmentNumber] = eem; };
|
|
dbEx0->selectByExerciseId(cbEem, m_mainHandler->exerciseId());
|
|
|
|
auto localEquipmentExerciseMappings = m_equipmentExerciseMappings;
|
|
m_publishEquipmentExerciseMappings = !m_equipmentExerciseMappings.isEmpty();
|
|
|
|
m_proxyListener.reset(new ProxyListener(m_mainHandler));
|
|
if (!m_proxyListener->init())
|
|
{
|
|
ERROR_LOG(m_logger) << "Could not initialise ProxyListener";
|
|
return false;
|
|
}
|
|
|
|
auto cbOrga = [this](const Database::PpmParticipantOrganisation &partOrga) { m_participantOrganisations.insert(partOrga.participantId, toDds(partOrga)); };
|
|
m_mainHandler->db()->select(cbOrga);
|
|
|
|
DEBUG_LOG(m_logger) << "Reading participants from database";
|
|
// get participants from database / insert participant data into m_participants
|
|
m_participants.reserve(100);
|
|
auto cbParticipants = [this, &localEquipmentExerciseMappings](const Database::PpmParticipant ¤tParticipant)
|
|
{
|
|
ParticipantForExercise *newParticipant = new ParticipantForExercise(m_mainHandler, this, m_unitPositionCalculator.get(), currentParticipant);
|
|
// update db only needed when not yet in there
|
|
localEquipmentExerciseMappings.remove(newParticipant->equipmentNumber());
|
|
|
|
m_participants.insert(newParticipant->id(), newParticipant);
|
|
};
|
|
if (!m_mainHandler->db()->select(cbParticipants))
|
|
{
|
|
ERROR_LOG(m_logger) << "Error while reading participants from database";
|
|
return false;
|
|
}
|
|
|
|
// remove the 'unused' EquipmentExerciseMappings (for whatever reason there are some...)
|
|
for (const auto &eem : qAsConst(localEquipmentExerciseMappings))
|
|
dbEx0->removeEquipmentExerciseMapping(eem);
|
|
|
|
// after m_publishEquipmentExerciseMappings has been set and participants are created
|
|
m_exmDtc = ExerciseManagement::Interface::Dtc::create(m_mainHandler->dds());
|
|
connect(m_exmDtc.get(), &ExerciseManagement::Interface::Dtc::exerciseChanged, this, &ParticipantHandlerForExercise::onExerciseChanged);
|
|
if (!m_exmDtc->enableExercise())
|
|
{
|
|
ERROR_LOG(m_logger) << "Could not enable Topic 'Exercise' of EXM DTC";
|
|
return false;
|
|
}
|
|
m_ppmDtc = ParticipantManagement::Interface::Dtc::create(m_mainHandler->dds());
|
|
if (!m_ppmDtc->enableSetAsSimulated())
|
|
{
|
|
ERROR_LOG(m_logger) << "Could not enable Topic 'Exercise' of PPM DTC";
|
|
return false;
|
|
}
|
|
|
|
bool isOwnPositionParticipant = false;
|
|
|
|
// publish participants in dds
|
|
for (Participant *p : qAsConst(m_participants))
|
|
{
|
|
if (p->equipmentNumber() == 1)
|
|
isOwnPositionParticipant = true;
|
|
|
|
p->hasNewInferiorStructure(inferiorIdsForParticipant(p->id()));
|
|
p->publishParticipant();
|
|
}
|
|
auto dtc = m_mainHandler->ddsHandler()->dtc();
|
|
|
|
if (strcmp(PROJECTBUILD, "commaster") == 0)
|
|
{
|
|
if ((isOwnPositionParticipant == false) && (m_mainHandler->exerciseId() != 0)
|
|
&& (!m_equipmentExerciseMappings.contains(1))) // !m_equipmentExerciseMappings.keys().contains(1)
|
|
// .keys() allocating an unneeded temporary container ^^^^^^
|
|
{
|
|
ModifyParticipantDataRequest ownPositionParticipant;
|
|
std::vector<ParticipantData> dataArray;
|
|
ParticipantData data;
|
|
data.assignState(ParticipantAssignState::HandoutExcon);
|
|
data.partyId(1);
|
|
data.hierarchyNumber(1);
|
|
data.equipmentNumber(1);
|
|
// data.info(QString(QStringLiteral("")).toStdString()); // a string is empty be default!
|
|
// data.identification(QString(QStringLiteral("")).toStdString()); // a string is empty be default!
|
|
data.typeId(60);
|
|
data.symbol(QString(QStringLiteral("NONE|CVLX|227")).toStdString());
|
|
data.designator(QString(QStringLiteral("OC")).toStdString());
|
|
data.isSimulated(false);
|
|
data.isDeleted(false);
|
|
data.superiorModId(-1);
|
|
dataArray.push_back(data);
|
|
ownPositionParticipant.data(dataArray);
|
|
ownPositionParticipant.forceAddWithId(false);
|
|
modifyParticipantDataRequest(ownPositionParticipant);
|
|
}
|
|
}
|
|
|
|
if (m_mainHandler->exerciseId() > 0)
|
|
{
|
|
// Initialize RecordReplay to get initial participantPosition
|
|
RecordReplayPlugin recordReplay;
|
|
// no ddsconnector - we don't want to publish data here
|
|
recordReplay.initDtc(nullptr, m_mainHandler->exerciseId());
|
|
|
|
NSqlQuery q(m_mainHandler->db()->database());
|
|
recordReplay.readParticipantPositionAt(q, QDateTime::currentMSecsSinceEpoch());
|
|
|
|
// key is sampleTime -> multiMap
|
|
const auto &latestPositions = recordReplay.getParticipantPositionMap();
|
|
DEBUG_LOG(m_logger) << "Starting to read participant positions from record replay. Size: " << latestPositions.size();
|
|
|
|
for (const auto &pos : latestPositions)
|
|
{
|
|
Participant *currentParticipant = m_participants.value(pos.participantId());
|
|
if (currentParticipant == nullptr)
|
|
{
|
|
INFO_LOG(m_logger) << "Got position for non existing participantId: " << pos.participantId();
|
|
continue;
|
|
}
|
|
|
|
DEBUG_LOG(m_logger) << "Setting position for participantId " << pos.participantId() << ": " << pos;
|
|
currentParticipant->setPosition(pos, true);
|
|
currentParticipant->publishPosition();
|
|
}
|
|
|
|
recordReplay.readDynamicParticipantDataAt(q, QDateTime::currentMSecsSinceEpoch());
|
|
// key is sampleTime -> multiMap
|
|
const auto &latestStates = recordReplay.getDynamicParticipantDataMap();
|
|
|
|
DEBUG_LOG(m_logger) << "Starting to read dynamic participant data from record replay. Size: " << latestStates.size();
|
|
|
|
for (const auto &dynData : latestStates)
|
|
{
|
|
Participant *currentParticipant = m_participants.value(dynData.participantId());
|
|
if (currentParticipant == nullptr)
|
|
{
|
|
INFO_LOG(m_logger) << "Got dynamic data for non existing participantId: " << dynData.participantId();
|
|
continue;
|
|
}
|
|
|
|
DEBUG_LOG(m_logger) << "Dynamic data for participantId " << dynData.participantId() << ": " << dynData;
|
|
currentParticipant->setDynamicData(dynData);
|
|
currentParticipant->publishDynamicData();
|
|
}
|
|
|
|
recordReplay.readParticipantModeAt(q, QDateTime::currentMSecsSinceEpoch());
|
|
// key is sampleTime -> multiMap
|
|
const auto &latestModes = recordReplay.getParticipantModeMap();
|
|
|
|
DEBUG_LOG(m_logger) << "Starting to read mode data from record replay. Size: " << latestStates.size();
|
|
|
|
for (const auto &mode : latestModes)
|
|
{
|
|
Participant *currentParticipant = m_participants.value(mode.participantId());
|
|
if (currentParticipant == nullptr)
|
|
{
|
|
INFO_LOG(m_logger) << "Got mode data for non existing participantId: " << mode.participantId();
|
|
continue;
|
|
}
|
|
|
|
DEBUG_LOG(m_logger) << "Mode data for participantId " << mode.participantId() << ": " << mode;
|
|
currentParticipant->setMode(mode);
|
|
currentParticipant->publishMode();
|
|
}
|
|
|
|
recordReplay.readUASAt(q, QDateTime::currentMSecsSinceEpoch());
|
|
// key is sampleTime -> multiMap
|
|
const auto &uasData = recordReplay.getUASMap();
|
|
|
|
DEBUG_LOG(m_logger) << "Starting to read uas data from record replay. Size: " << uasData.size();
|
|
|
|
for (const auto &uas : uasData)
|
|
dts()->publish(uas);
|
|
}
|
|
|
|
connect(dtc.get(), &Interface::Dtc::equipmentExerciseMappingChanged, this, &ParticipantHandlerForExercise::onEquipmentExerciseMappingChanged);
|
|
dtc->equipmentExerciseMappings([this](const EquipmentExerciseMapping &data) { onEquipmentExerciseMappingChanged(data, DataModification::eAdded); });
|
|
|
|
auto pub = dts();
|
|
for (const ParticipantOrganisation &partOrga : qAsConst(m_participantOrganisations))
|
|
pub->publish(partOrga);
|
|
|
|
if (m_mainHandler->exerciseId() > 0)
|
|
m_unitPositionCalculator->startCalculation();
|
|
|
|
connect(m_proxyListener.get(), &ProxyListener::newPosition, this, &ParticipantHandler::onNewPositionFromProxy);
|
|
connect(m_proxyListener.get(), &ProxyListener::newState, this, &ParticipantHandler::onNewStateFromProxy);
|
|
connect(m_proxyListener.get(), &ProxyListener::newGearAssignment, this, &ParticipantHandler::onNewGearAssignmentFromProxy);
|
|
connect(m_proxyListener.get(), &ProxyListener::newGearChargeState, this, &ParticipantHandler::onNewGearChargeStateFromProxy);
|
|
connect(m_proxyListener.get(), &ProxyListener::newGearEvent, this, &ParticipantHandler::onNewGearEvent);
|
|
connect(m_proxyListener.get(), &ProxyListener::newEquipmentOperationalState, this, &ParticipantHandler::onNewEquipmentOperationalStateFromProxy);
|
|
connect(m_proxyListener.get(), &ProxyListener::newEquipmentBite, this, &ParticipantHandler::onNewBiteFromProxy);
|
|
connect(m_proxyListener.get(), &ProxyListener::newCtaDataError, this, &ParticipantHandler::onNewCtaDataErrorFromProxy);
|
|
connect(m_proxyListener.get(), &ProxyListener::newParticipantModeReport, this, &ParticipantHandler::onNewParticipantModeReport);
|
|
connect(m_proxyListener.get(), &ProxyListener::newSpecialSensorData, this, &ParticipantHandler::onNewSpecialSensorData);
|
|
connect(m_proxyListener.get(), &ProxyListener::newFunctionalAreaEntryChanged, this, &ParticipantHandler::onNewFunctionalAreaEntryChanged);
|
|
connect(m_hitLineInfoTimer, &QTimer::timeout, this, &ParticipantHandler::onHitLineInfoTimeout);
|
|
connect(m_proxyListener.get(), &ProxyListener::newLaserDesignationData, this, &ParticipantHandlerForExercise::onNewLaserDesignation);
|
|
connect(m_proxyListener.get(), &ProxyListener::laserDesignationRemoved, this, &ParticipantHandlerForExercise::onLaserDesignationRemoved);
|
|
// PVSan
|
|
connect(m_proxyListener.get(), &ProxyListener::newSanitaryMaterialStockReport, this, &ParticipantHandler::onSanitaryMaterialStockReport);
|
|
connect(m_proxyListener.get(), &ProxyListener::newParticipantSanitation, this, &ParticipantHandler::onParticipantSanitation);
|
|
connect(m_proxyListener.get(), &ProxyListener::newOperatorAction, this, &ParticipantHandler::onOperatorAction);
|
|
connect(m_proxyListener.get(), &ProxyListener::newEquipmentEvent, this, &ParticipantHandler::onEquipmentEvent);
|
|
|
|
// Vulcano / Building Laser Designation
|
|
connect(m_proxyListener.get(), &ProxyListener::newBuildingHitLineInfo, this, &ParticipantHandler::onBuildingHitLineInfo);
|
|
|
|
// for counting charges
|
|
connect(m_mainHandler->participantHandler().get(), &ParticipantHandler::gearChargeChanged, this, &ParticipantHandlerForExercise::onGearChargeChanged);
|
|
|
|
m_hitLineInfoTimer->setSingleShot(false);
|
|
m_hitLineInfoTimer->start(15000);
|
|
|
|
if (!m_pdmDtc)
|
|
{
|
|
m_pdmDtc = m_mainHandler->ddsHandler()->pdmDtc();
|
|
m_pdmDtc->waitForHistoricalDataGearType();
|
|
m_pdmDtc->waitForHistoricalDataGearTypeChargeType();
|
|
}
|
|
|
|
// for(const auto &participant : qAsConst(m_participants))
|
|
// customedSetGearCharges(participant);
|
|
|
|
return true;
|
|
}
|
|
|
|
void ParticipantHandlerForExercise::setEquipmentNumberForParticipant(int oldEqNo, int newEqNo, int participantId)
|
|
{
|
|
ParticipantHandler::setEquipmentNumberForParticipant(oldEqNo, newEqNo, participantId);
|
|
if (m_publishEquipmentExerciseMappings && !m_publishEquipmentExerciseMappingsTimer->isActive())
|
|
m_publishEquipmentExerciseMappingsTimer->start(1000);
|
|
}
|
|
|
|
bool ParticipantHandlerForExercise::isUnitType(int typeId) const { return m_mainHandler->typeHandler()->isUnitType(typeId); }
|
|
|
|
void ParticipantHandlerForExercise::createHitlineInfo(int originatorId,
|
|
Participant *originParticipant,
|
|
Participant *participantToBeChanged,
|
|
const TrainingAreaBase::EquipmentPosition &pos,
|
|
int originatorChargeTypeId,
|
|
qint64 sampleTime)
|
|
{
|
|
if (!originParticipant)
|
|
return;
|
|
|
|
if (!m_pdmDtc)
|
|
m_pdmDtc = m_mainHandler->ddsHandler()->pdmDtc();
|
|
// NOTE: igniterType/IgniterFunciton = 0 as long as HitLineInfo does not contain values
|
|
if (!m_pdmDtc->showHitline(originatorChargeTypeId, 0, 0))
|
|
return;
|
|
|
|
INFO_LOG(m_logger) << "createHitlineInfo: originParticipant " << originParticipant->position();
|
|
INFO_LOG(m_logger) << "createHitlineInfo: pos" << pos;
|
|
|
|
// publish HitLineInfo
|
|
HitLineInfo hli;
|
|
hli.originatorParticipantId(originatorId);
|
|
hli.originatorPartyId(originParticipant->partyId());
|
|
hli.originatorPos(originParticipant->position().pos());
|
|
hli.originatorBuildingId(originParticipant->position().buildingId());
|
|
hli.originatorRoomId(originParticipant->position().roomId());
|
|
hli.id(m_hitLineId);
|
|
hli.injuryParticipantId(participantToBeChanged->id());
|
|
hli.injuryPos(pos.position().position());
|
|
hli.chargeTypeId(originatorChargeTypeId);
|
|
hli.sampleTime(sampleTime);
|
|
hli.injuryBuildingId(pos.position().moutObjectId().is_set() ? pos.position().moutObjectId().get() : 0);
|
|
hli.injuryRoomId(pos.position().moutRoomId().is_set() ? pos.position().moutRoomId().get() : 0);
|
|
if (!dts()->publish(hli))
|
|
return;
|
|
|
|
m_hitLineInfoMap.insert(hli.id(), hli);
|
|
m_hitLineId++;
|
|
}
|
|
|
|
void ParticipantHandlerForExercise::onModifyParticipantDataRequest(const rti::core::SampleIdentity &cookie,
|
|
const ParticipantManagement::ModifyParticipantDataRequest &request)
|
|
{
|
|
DEBUG_LOG(m_logger) << "onModifyParticipantDataRequest: " << request;
|
|
const auto ret = modifyParticipantDataRequest(request);
|
|
if (ret.error())
|
|
WARNING_LOG(m_logger) << ret();
|
|
|
|
m_mainHandler->fts()->modifyParticipantDataReply(cookie, ret);
|
|
}
|
|
|
|
Core::FunctionReplyObject ParticipantHandlerForExercise::modifyParticipantDataRequest(const ModifyParticipantDataRequest &request)
|
|
{
|
|
startLongAction();
|
|
QSet<Participant *> participantsWithChanges;
|
|
ValidateParticipantData validateData;
|
|
QSet<int> partiesUsed;
|
|
QSet<int> partiesWithDeletedOrMovedOutParticipants;
|
|
|
|
validateData.forceAddWithId = request.forceAddWithId();
|
|
|
|
validateData.participantsToBeCreatedOrModified.reserve(request.data().size());
|
|
|
|
bool permanentRemoveParticipants
|
|
= !m_mainHandler->exerciseId() || m_exmDtc->exercise(m_mainHandler->exerciseId()).state() == ExerciseManagement::ExerciseState::Created;
|
|
|
|
// check assign state - we can't remove participants handled by warehouse
|
|
for (const ParticipantData ¤tParticipant : request.data())
|
|
{
|
|
if (!currentParticipant.isDeleted())
|
|
{
|
|
validateData.participantsToBeCreatedOrModified.append(currentParticipant);
|
|
continue;
|
|
}
|
|
if (currentParticipant.id() == 0)
|
|
return Core::FunctionReplyObject(request.requestId(),
|
|
tr_lts("dds", "Not possible to remove participantData with modId %1, because it does not have participantId set"))
|
|
.arg(currentParticipant.modId());
|
|
auto ret = checkDeleteParticipant(currentParticipant.id());
|
|
if (ret.error())
|
|
{
|
|
ret.setId(request.requestId());
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
checkLongActionBreak();
|
|
|
|
for (const ParticipantManagement::ParticipantData ¤tParticipant : qAsConst(validateData.participantsToBeCreatedOrModified))
|
|
{
|
|
auto ret = validateParticipantData(validateData, currentParticipant);
|
|
if (ret.error())
|
|
{
|
|
ret.setId(request.requestId());
|
|
return ret;
|
|
}
|
|
}
|
|
DEBUG_LOG(m_logger) << " >>>>> ModifyParticipantDataRequest has valid data";
|
|
|
|
if (m_firingUnitValidator)
|
|
{
|
|
auto ret = m_firingUnitValidator->firingUnitError(validateData.modIdToParticipantId, validateData.participantsToBeCreatedOrModified);
|
|
|
|
if (ret.error())
|
|
{
|
|
ret.setId(request.requestId());
|
|
return ret;
|
|
}
|
|
|
|
DEBUG_LOG(m_logger) << "There are no firing unit errors.";
|
|
}
|
|
else
|
|
WARNING_LOG(m_logger) << "There is no valid FiringUnitValidator";
|
|
|
|
checkLongActionBreak();
|
|
|
|
// first sort out participants to be marked as deleted
|
|
DBTransaction removeTransaction(m_mainHandler->db()->database());
|
|
for (const ParticipantData ¤tParticipant : request.data())
|
|
{
|
|
if (currentParticipant.isDeleted())
|
|
{
|
|
if (currentParticipant.id() == 0)
|
|
return Core::FunctionReplyObject(request.requestId(),
|
|
tr_lts("dds", "Not possible to remove participantData with modId %1, because it does not have participantId set"))
|
|
.arg(currentParticipant.modId());
|
|
|
|
auto ret = deleteParticipant(currentParticipant.id(), permanentRemoveParticipants, true);
|
|
|
|
// only a real error if the participant exists (deleting an already deleted participant is fine
|
|
if (ret.error() && m_participants.contains(currentParticipant.id()))
|
|
{
|
|
ret.setId(request.requestId());
|
|
return ret;
|
|
}
|
|
|
|
partiesWithDeletedOrMovedOutParticipants.insert(currentParticipant.partyId());
|
|
}
|
|
}
|
|
removeTransaction.commit();
|
|
|
|
checkLongActionBreak();
|
|
|
|
for (int i = 0; i < validateData.participantsToBeCreatedOrModified.size() && !validateData.participantsToResetEquipmentNumber.isEmpty(); ++i)
|
|
{
|
|
ParticipantData &pd = validateData.participantsToBeCreatedOrModified[i];
|
|
for (int j = 0; j < validateData.participantsToResetEquipmentNumber.size(); ++j)
|
|
{
|
|
if (pd.modId() == validateData.participantsToResetEquipmentNumber.at(j))
|
|
{
|
|
pd.equipmentNumber().reset();
|
|
pd.assignState(ParticipantAssignState::NotAssigned);
|
|
validateData.participantsToResetEquipmentNumber.removeAt(j);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
DBTransaction trans(m_mainHandler->db()->database());
|
|
std::vector<Database::PpmParticipant> dbParticipantsToBeCreated;
|
|
std::vector<int> dbParticipantsToBeCreatedIndexes;
|
|
dbParticipantsToBeCreated.reserve(validateData.participantsToBeCreatedOrModified.size());
|
|
dbParticipantsToBeCreatedIndexes.reserve(validateData.participantsToBeCreatedOrModified.size());
|
|
// create new and update existing participants
|
|
DEBUG_LOG(m_logger) << "Creating new and updating existing participants ...";
|
|
for (int i = 0; i < validateData.participantsToBeCreatedOrModified.size(); ++i)
|
|
{
|
|
const ParticipantData ¤tData = validateData.participantsToBeCreatedOrModified.at(i);
|
|
auto modIdIt = validateData.modIdToParticipantId.constFind(currentData.modId());
|
|
if (modIdIt == validateData.modIdToParticipantId.constEnd())
|
|
{
|
|
auto part = toDbParticipant(currentData, request.forceAddWithId());
|
|
if (Settings::markVehiclesAsReservedFromExcon())
|
|
{
|
|
if (part.assignState == ParticipantAssignState::NotAssigned && part.equipmentNumber == 0 && !isUnitType(part.typeId))
|
|
{
|
|
const auto *type = m_mainHandler->typeHandler()->typeById(part.typeId);
|
|
if (type && type->typeClass() != TypeClass::Human)
|
|
{
|
|
// reserve participants for excon since otherwise the guez warehouse will automatically
|
|
// assign an equipment number for this participant... *argh*
|
|
part.assignState = ParticipantAssignState::HandoutExcon;
|
|
}
|
|
}
|
|
}
|
|
dbParticipantsToBeCreated.push_back(std::move(part));
|
|
dbParticipantsToBeCreatedIndexes.push_back(i);
|
|
DEBUG_LOG(m_logger) << "new participant, index: " << i << ", data: " << currentData;
|
|
}
|
|
else
|
|
{
|
|
// update existing participant
|
|
Participant *participantToUpdate = participantById(modIdIt.value());
|
|
if (!participantToUpdate)
|
|
{
|
|
ERROR_LOG(m_logger) << "Could not find participant to update with modId " << modIdIt.value() << ", request: " << request;
|
|
continue;
|
|
}
|
|
const int oldPartyId = participantToUpdate->partyId();
|
|
// check for nullptr not necessary. If the participant does not exist, modIdToParticipantId would not include the Id
|
|
|
|
if (participantToUpdate->hasToBeChanged(currentData))
|
|
{
|
|
const int newPartyId = participantToUpdate->partyId();
|
|
participantsWithChanges.insert(participantToUpdate);
|
|
if (oldPartyId != newPartyId)
|
|
partiesWithDeletedOrMovedOutParticipants.insert(oldPartyId);
|
|
}
|
|
|
|
participantToUpdate = nullptr;
|
|
}
|
|
}
|
|
checkLongActionBreak();
|
|
|
|
// insert new participants
|
|
|
|
auto ret = createNewParticipants(dbParticipantsToBeCreated,
|
|
dbParticipantsToBeCreatedIndexes,
|
|
validateData.participantsToBeCreatedOrModified,
|
|
validateData.modIdToParticipantId,
|
|
participantsWithChanges);
|
|
if (ret.error())
|
|
{
|
|
ret.setId(request.requestId());
|
|
return ret;
|
|
}
|
|
|
|
DEBUG_LOG(m_logger) << "New participants created and existing participants updated";
|
|
|
|
// build hierarchy
|
|
for (const ParticipantData ¤tData : qAsConst(validateData.participantsToBeCreatedOrModified)) // first set superiorIds
|
|
{
|
|
Participant *participantToUpdate = participantById(validateData.modIdToParticipantId.value(currentData.modId()));
|
|
if (currentData.superiorModId() >= 0) // superiorModId < 0 -> no change in superior
|
|
{
|
|
const int superiorId = validateData.modIdToParticipantId.value(currentData.superiorModId());
|
|
|
|
if (participantToUpdate->hasNewSuperiorId(superiorId))
|
|
participantsWithChanges.insert(participantToUpdate);
|
|
}
|
|
}
|
|
|
|
// update inferiorIds, do not iterator over m_participants and use inferiorIdsForParticipant because its O²
|
|
QHash<int, std::vector<int32_t>> inferiors;
|
|
inferiors.reserve(m_participants.size() / 2);
|
|
// first collect all inferiors per superior
|
|
for (const Participant *currentParticipant : qAsConst(m_participants))
|
|
{
|
|
int superiorId = currentParticipant->superiorId();
|
|
inferiors[superiorId].push_back(currentParticipant->id());
|
|
if (!partiesWithDeletedOrMovedOutParticipants.isEmpty())
|
|
{
|
|
// remove party ids which may be empty now since we found a participant with this party id
|
|
auto it = partiesWithDeletedOrMovedOutParticipants.find(currentParticipant->partyId());
|
|
if (it != partiesWithDeletedOrMovedOutParticipants.end())
|
|
partiesWithDeletedOrMovedOutParticipants.erase(it);
|
|
}
|
|
}
|
|
// now update all participants with newly collected inferiors
|
|
for (Participant *currentParticipant : qAsConst(m_participants))
|
|
{
|
|
if (currentParticipant->hasNewInferiorStructure(inferiors.value(currentParticipant->id())))
|
|
participantsWithChanges.insert(currentParticipant);
|
|
}
|
|
checkLongActionBreak();
|
|
|
|
// update in Database
|
|
std::vector<Database::PpmParticipant> dbParticipantsToUpdate;
|
|
dbParticipantsToUpdate.reserve(participantsWithChanges.size());
|
|
for (Participant *currentParticipant : qAsConst(participantsWithChanges))
|
|
{
|
|
dbParticipantsToUpdate.push_back(currentParticipant->toDbParticipant());
|
|
partiesUsed.insert(currentParticipant->partyId());
|
|
}
|
|
|
|
if (!m_mainHandler->db()->update(dbParticipantsToUpdate))
|
|
return Core::FunctionReplyObject(request.requestId(), tr_lts("dds", "Could not update participant data in database, participant data may be inconsistent"));
|
|
|
|
trans.commit();
|
|
checkLongActionBreak();
|
|
|
|
DDSConnector::CoherentSet cs(m_mainHandler->dds());
|
|
|
|
// mark parties in use
|
|
ChangePartyUsedStateRequest req;
|
|
for (int partyId : qAsConst(partiesUsed))
|
|
{
|
|
req.partyId(partyId);
|
|
req.isUsedBy(true);
|
|
m_mainHandler->partyHandler()->changePartyUsedStateRequest(req);
|
|
}
|
|
for (int partyId : qAsConst(partiesWithDeletedOrMovedOutParticipants))
|
|
{
|
|
req.partyId(partyId);
|
|
req.isUsedBy(false);
|
|
m_mainHandler->partyHandler()->changePartyUsedStateRequest(req);
|
|
}
|
|
|
|
if (request.data().size() == 1 && request.data().at(0).isDeleted())
|
|
{
|
|
// make sure to not save a participant orga for this participant
|
|
const int removedParticipantId = request.data().at(0).id();
|
|
auto it = m_participantOrganisations.find(removedParticipantId);
|
|
if (it != m_participantOrganisations.end())
|
|
{
|
|
const int dbId = it.value().dbId;
|
|
m_mainHandler->db()->removePpmParticipantOrganisation(dbId);
|
|
dts()->removeParticipantOrganisationByKey(removedParticipantId);
|
|
m_participantOrganisations.erase(it);
|
|
}
|
|
}
|
|
if (request.participantOrganisation().is_set())
|
|
{
|
|
const ParticipantOrganisation &newOrga = request.participantOrganisation().get();
|
|
auto it = m_participantOrganisations.find(newOrga.participantId());
|
|
|
|
const int originPartyId = (it == m_participantOrganisations.end() ? -1 : it.value().originPartyId());
|
|
|
|
// same party? -> returned to 'home' -> we can remove this
|
|
if (newOrga.currentPartyId() == originPartyId)
|
|
{
|
|
if (it == m_participantOrganisations.end())
|
|
WARNING_LOG(m_logger) << "Could suprious party organisation - ignoring: " << newOrga;
|
|
else
|
|
{
|
|
const int dbId = it.value().dbId;
|
|
m_mainHandler->db()->removePpmParticipantOrganisation(dbId);
|
|
dts()->removeParticipantOrganisationByKey(newOrga.participantId());
|
|
m_participantOrganisations.erase(it);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ParticipantOrganisationEx orga;
|
|
orga.copy(newOrga);
|
|
if (it == m_participantOrganisations.end())
|
|
{
|
|
// new
|
|
Database::PpmParticipantOrganisation dbOrga(toDb(orga));
|
|
m_mainHandler->db()->insert(dbOrga);
|
|
orga.dbId = dbOrga.id;
|
|
m_participantOrganisations.insert(orga.participantId(), orga);
|
|
}
|
|
else
|
|
{
|
|
// modified
|
|
orga.dbId = it.value().dbId;
|
|
// the origin party id must not be overwritten
|
|
// (but is unknown in some usecases on the client - therefore overwrite here)
|
|
orga.originPartyId(originPartyId);
|
|
m_mainHandler->db()->update(toDb(orga));
|
|
*it = orga;
|
|
}
|
|
dts()->publish(orga);
|
|
}
|
|
}
|
|
checkLongActionBreak();
|
|
QJsonArray jsonArray;
|
|
|
|
// finally ... publish participant data via dds if no error occured
|
|
for (Participant *currentParticipant : qAsConst(participantsWithChanges))
|
|
{
|
|
currentParticipant->publishParticipant();
|
|
NOTICE_LOG(m_logger) << "publishParticipant id=" << currentParticipant->id();
|
|
jsonArray.append(currentParticipant->id());
|
|
|
|
// QTimer::singleShot(500, this, [=](){ customedSetGearCharges(currentParticipant);});
|
|
}
|
|
QJsonObject jsonObj;
|
|
jsonObj[QStringLiteral("participants")] = jsonArray;
|
|
QJsonDocument doc(jsonObj);
|
|
QByteArray bytes = doc.toJson(QJsonDocument::Compact);
|
|
|
|
// 4. In const char* wandeln
|
|
const char *errStr = "";
|
|
const std::vector<std::string> errArgs = {};
|
|
const char *additionalInfo = bytes.constData();
|
|
return Core::FunctionReplyObject(request.requestId(), errStr, errArgs, additionalInfo);
|
|
}
|
|
|
|
void ParticipantHandlerForExercise::onModifyStateRequest(const rti::core::SampleIdentity &cookie, const ParticipantManagement::ModifyStateRequest &request)
|
|
{
|
|
DEBUG_LOG(m_logger) << "onModifyStateRequest: " << request;
|
|
auto ret = modifyStateRequest(cookie, request);
|
|
if (ret.error())
|
|
{
|
|
WARNING_LOG(m_logger) << ret();
|
|
m_mainHandler->fts()->modifyStateReply(cookie, ret);
|
|
}
|
|
// delayed answer in non-error case
|
|
}
|
|
|
|
Core::FunctionReplyObject ParticipantHandlerForExercise::modifyStateRequest(const rti::core::SampleIdentity &cookie,
|
|
const ParticipantManagement::ModifyStateRequest &request)
|
|
{
|
|
TrainingAreaBase::DemandVulnerabilityStateChangeRequest req;
|
|
|
|
int failedParticipantId = 0;
|
|
if (!participantIds2EquipmentNumbers(request.participantIds(), req.equipmentNumbers(), &failedParticipantId))
|
|
return Core::FunctionReplyObject(0, tr_lts("dds", "Got invalid participant id %1 in modify state request")).arg(failedParticipantId);
|
|
req.requestId(s_tabRequestId++);
|
|
req.workstationId(request.workstationId());
|
|
req.vulnerabilityState(request.vulnerabilityState());
|
|
req.vulnerabilityKind(request.vulnerabilityKind()); // Pv San
|
|
req.vitality(request.vitality()); // Pv San
|
|
|
|
return m_proxyListener->demandVulnerabilityStateChange(cookie, req);
|
|
}
|
|
|
|
void ParticipantHandlerForExercise::onInitParticipantRequest(const rti::core::SampleIdentity &cookie, const ParticipantManagement::InitParticipantRequest &request)
|
|
{
|
|
DEBUG_LOG(m_logger) << "onInitParticipantRequest: " << request;
|
|
auto ret = initParticipantRequest(cookie, request);
|
|
if (ret.error())
|
|
{
|
|
WARNING_LOG(m_logger) << ret();
|
|
m_mainHandler->fts()->initParticipantReply(cookie, ret);
|
|
}
|
|
// delayed answer in non-error case
|
|
}
|
|
|
|
Core::FunctionReplyObject ParticipantHandlerForExercise::initParticipantRequest(const rti::core::SampleIdentity &cookie,
|
|
const ParticipantManagement::InitParticipantRequest &request)
|
|
{
|
|
TrainingAreaBase::DemandInitRequest req;
|
|
int failedParticipantId = 0;
|
|
if (!participantIds2EquipmentNumbers(request.participantIds(), req.equipmentNumbers(), &failedParticipantId))
|
|
return Core::FunctionReplyObject(0, tr_lts("dds", "Got invalid participant id %1 in init request")).arg(failedParticipantId);
|
|
|
|
req.requestId(s_tabRequestId++);
|
|
req.workstationId(request.workstationId());
|
|
req.restockCharges(request.restockCharges());
|
|
req.resetManipulation(request.resetManipulation());
|
|
req.resetVulnerabilityState(request.resetVulnerabilityState());
|
|
req.restockSanitationMaterial(request.restockSanitationMaterial());
|
|
|
|
return m_proxyListener->demandInitRequest(cookie, req);
|
|
}
|
|
|
|
void ParticipantHandlerForExercise::onSetParticipantModeRequest(const rti::core::SampleIdentity &cookie, const ParticipantManagement::SetParticipantModeRequest &request)
|
|
{
|
|
DEBUG_LOG(m_logger) << "onSetParticipantModeRequest: " << request;
|
|
auto ret = setParticipantModeRequest(cookie, request);
|
|
if (ret.error())
|
|
{
|
|
WARNING_LOG(m_logger) << ret();
|
|
m_mainHandler->fts()->setParticipantModeReply(cookie, ret);
|
|
}
|
|
// delayed answer in non-error case
|
|
}
|
|
|
|
Core::FunctionReplyObject ParticipantHandlerForExercise::setParticipantModeRequest(const rti::core::SampleIdentity &cookie,
|
|
const ParticipantManagement::SetParticipantModeRequest &request)
|
|
{
|
|
const Participant *participant = request.participantId() ? participantById(request.participantId()) : nullptr;
|
|
if (participant == nullptr && request.participantId() != 0)
|
|
return Core::FunctionReplyObject(request.participantId(), tr_lts("dds", "Got SetParticipantModeRequest for unknown participant id %1")).arg(request.participantId());
|
|
|
|
TrainingAreaBase::SendParticipantModeRequest tabRequest;
|
|
|
|
tabRequest.requestId(s_tabRequestId++);
|
|
tabRequest.equipmentNumber(participant ? participant->equipmentNumber() : 0);
|
|
tabRequest.participantId(request.participantId());
|
|
tabRequest.language(request.language());
|
|
tabRequest.operationMode(request.opMode());
|
|
tabRequest.reactivationDetoxication(request.reactivationDecontamination());
|
|
tabRequest.reactivationMaintenance(request.reactivationMaintenance());
|
|
tabRequest.reactivationMedic(request.reactivationMedic());
|
|
tabRequest.protectionModeVest(request.modeVest());
|
|
tabRequest.protectionModeHelmet(request.modeHelmet());
|
|
tabRequest.personellProtection(request.modePersonalProtection());
|
|
tabRequest.protectionLevel(request.protectionLevel());
|
|
tabRequest.handgrenadeSearchMode(request.handgrenadeSearchMode());
|
|
tabRequest.internationalMode(request.internationalMode());
|
|
tabRequest.abcProtectionMode(request.abcProtectionMode());
|
|
|
|
return m_proxyListener->sendParticipantModeRequest(cookie, tabRequest);
|
|
}
|
|
|
|
void ParticipantHandlerForExercise::onSendMessageRequest(const rti::core::SampleIdentity &cookie, const ParticipantManagement::SendMessageRequest &request)
|
|
{
|
|
DEBUG_LOG(m_logger) << "onSendMessageRequest: " << request;
|
|
auto ret = sendMessageRequest(cookie, request);
|
|
if (ret.error())
|
|
{
|
|
WARNING_LOG(m_logger) << ret();
|
|
m_mainHandler->fts()->sendMessageReply(cookie, ret);
|
|
}
|
|
// delayed answer in non-error case
|
|
}
|
|
|
|
Core::FunctionReplyObject ParticipantHandlerForExercise::sendMessageRequest(const rti::core::SampleIdentity &cookie,
|
|
const ParticipantManagement::SendMessageRequest &request)
|
|
{
|
|
TrainingAreaBase::SendEquipmentMessageRequest req;
|
|
|
|
int failedParticipantId = 0;
|
|
if (!participantIds2EquipmentNumbers(request.participantIds(), req.equipmentNumbers(), &failedParticipantId))
|
|
return Core::FunctionReplyObject(0, tr_lts("dds", "Got invalid participant id %1 in send message request")).arg(failedParticipantId);
|
|
|
|
req.requestId(s_tabRequestId++);
|
|
req.message().set(request.message());
|
|
|
|
return m_proxyListener->sendEquipmentMessage(cookie, req);
|
|
}
|
|
|
|
void ParticipantHandlerForExercise::onRegisterParticipantRequest(const rti::core::SampleIdentity &cookie,
|
|
const ParticipantManagement::RegisterParticipantRequest &request)
|
|
{
|
|
DEBUG_LOG(m_logger) << "onRegisterParticipantRequest: " << request;
|
|
RegisterReturnValue retVal;
|
|
const auto ret = registerParticipantRequest(request, retVal);
|
|
if (ret.error())
|
|
WARNING_LOG(m_logger) << ret();
|
|
|
|
RegisterReply rRep(request.participantId(), ret.str(), ret.args(), ret.additionalInfo(), retVal, m_mainHandler->exerciseId());
|
|
m_mainHandler->fts()->registerParticipantReply(cookie, rRep);
|
|
}
|
|
|
|
Core::FunctionReplyObject ParticipantHandlerForExercise::registerParticipantRequest(const RegisterParticipantRequest &request_, RegisterReturnValue &retVal)
|
|
{
|
|
RegisterParticipantRequest request(request_);
|
|
Participant *participantToRegister = m_participants.value(request.participantId(), nullptr);
|
|
|
|
if (participantToRegister == nullptr) // check if participant exists
|
|
{
|
|
retVal = RegisterReturnValue::PlayerNotFound;
|
|
return Core::FunctionReplyObject(request.participantId(), tr_lts("dds", "Could not register participant - participant id %1 is invalid"))
|
|
.arg(request.participantId());
|
|
}
|
|
|
|
const EquipmentType *equipmentType = m_mainHandler->typeHandler()->equipmentTypeByTypeId(participantToRegister->typeId());
|
|
if (equipmentType == nullptr) // check if the participant has a valid equipment type
|
|
{
|
|
retVal = RegisterReturnValue::PlayerNotFound;
|
|
return Core::FunctionReplyObject(request.participantId(), tr_lts("dds", "Could not register participant - participant with id %1 has invalid equipmentType"))
|
|
.arg(request.participantId());
|
|
}
|
|
|
|
// special case: warehouse doesn't like the equipment number set (ICD23, State C2)
|
|
// but we want to use this equipment number -> set ExconOverrule
|
|
if (participantToRegister->equipmentNumber() != 0 && participantToRegister->assignState() == ParticipantAssignState::HandoutExcon
|
|
&& request.assignState() == ParticipantAssignState::AssignedWms && request.equipmentNumber() == -1)
|
|
{
|
|
NOTICE_LOG(m_logger) << "WMS doesn't know equipment number " << participantToRegister->equipmentNumber() << " - we have to override the assignment";
|
|
request.assignState(ParticipantAssignState::ExconWmsOverruled);
|
|
request.equipmentNumber(participantToRegister->equipmentNumber());
|
|
}
|
|
|
|
if (!participantToRegister->isNewAssignStateValid(request.assignState(), request.equipmentNumber())) // check if assign state is valid
|
|
{
|
|
retVal = RegisterReturnValue::AssignmentIncorrect;
|
|
return Core::FunctionReplyObject(request.participantId(),
|
|
tr_lts("dds", "Could not register participant - combination of equipment number and assign state is invalid"));
|
|
}
|
|
|
|
if (participantToRegister->isDeleted()) // check if participant is marked as deleted
|
|
{
|
|
// the warehouse is allowed to set to NotAssigned (== free the equipment number) even when the participant is already deleted
|
|
if (request.assignState() != ParticipantAssignState::NotAssigned)
|
|
{
|
|
retVal = RegisterReturnValue::PlayerDeleted;
|
|
return Core::FunctionReplyObject(request.participantId(), tr_lts("dds", "Could not register participant - participant is deleted"));
|
|
}
|
|
}
|
|
|
|
// only identification and info has changed
|
|
if (participantToRegister->equipmentNumber() == request.equipmentNumber() && participantToRegister->assignState() == request.assignState())
|
|
{
|
|
RegisterParticipantRequest oldData = participantToRegister->toRegisterParticipantRequest();
|
|
auto *pfe = static_cast<ParticipantForExercise *>(participantToRegister);
|
|
pfe->registerInfoFromFt(request);
|
|
|
|
if (!m_mainHandler->db()->update(participantToRegister->toDbParticipant()))
|
|
{
|
|
// rollback
|
|
pfe->registerFromFt(oldData);
|
|
|
|
retVal = RegisterReturnValue::RegistrationFailed;
|
|
return Core::FunctionReplyObject(request.participantId(), tr_lts("dds", "Could not register participant - failed to update info/identification in database"));
|
|
}
|
|
|
|
participantToRegister->publishParticipant();
|
|
retVal = RegisterReturnValue::RegistrationOk;
|
|
|
|
return Core::FunctionReplyObject(request.participantId());
|
|
}
|
|
|
|
if (participantByEquipmentNumber(request.equipmentNumber()) != nullptr && participantByEquipmentNumber(request.equipmentNumber()) != participantToRegister
|
|
&& request.equipmentNumber() > 0) // check if equipment number is already in use
|
|
{
|
|
retVal = RegisterReturnValue::EquipNoAlreadyAssigned;
|
|
return Core::FunctionReplyObject(request.participantId(), tr_lts("dds", "Could not register participant - equipment number %1 is already assigned"))
|
|
.arg(request.equipmentNumber());
|
|
}
|
|
|
|
const bool hasToCheckEquipmentNumber = request.assignState() != ParticipantAssignState::HandoutWms && request.assignState() != ParticipantAssignState::ExconWmsOverruled
|
|
&& request.assignState() != ParticipantAssignState::NotAssigned;
|
|
if (participantToRegister->equipmentNumber() > 0 && hasToCheckEquipmentNumber) // check if the participant already has an equipment number
|
|
{
|
|
retVal = RegisterReturnValue::AssignmentIncorrect;
|
|
return Core::FunctionReplyObject(request.participantId(),
|
|
tr_lts("dds", "Could not register participant - participant with id %1 has already an assigned equipment number %2"))
|
|
.arg(request.participantId())
|
|
.arg(request.equipmentNumber());
|
|
}
|
|
|
|
if ((request.equipmentNumber() > equipmentType->maxEquipNo() || request.equipmentNumber() < equipmentType->minEquipNo()) && request.equipmentNumber() > 0)
|
|
{
|
|
// check if the equipment number is in range for the associated equipment type
|
|
retVal = RegisterReturnValue::AssignmentIncorrect;
|
|
return Core::FunctionReplyObject(request.participantId(), tr_lts("dds", "Could not register participant - Equipment number %1 is not in range (%2 - %3)"))
|
|
.arg(request.equipmentNumber())
|
|
.arg(equipmentType->minEquipNo())
|
|
.arg(equipmentType->maxEquipNo());
|
|
}
|
|
|
|
const Type *type = typeById(participantToRegister->typeId());
|
|
if (type == nullptr)
|
|
{
|
|
retVal = RegisterReturnValue::RegistrationFailed;
|
|
return Core::FunctionReplyObject(request.participantId(), tr_lts("dds", "Could not register participant - participant has invalid type id"));
|
|
}
|
|
|
|
RegisterParticipantRequest oldData = participantToRegister->toRegisterParticipantRequest();
|
|
auto *pfe = static_cast<ParticipantForExercise *>(participantToRegister);
|
|
if (!pfe->registerFromFt(request))
|
|
{
|
|
retVal = RegisterReturnValue::EquipNoAlreadyAssigned;
|
|
return Core::FunctionReplyObject(request.participantId(), tr_lts("dds", "Could not register participant - equipment number %1 is already assigned"))
|
|
.arg(request.equipmentNumber());
|
|
}
|
|
|
|
if (!m_mainHandler->db()->update(participantToRegister->toDbParticipant()))
|
|
{
|
|
// rollback
|
|
pfe->registerFromFt(oldData);
|
|
|
|
retVal = RegisterReturnValue::RegistrationFailed;
|
|
return Core::FunctionReplyObject(request.participantId(), tr_lts("dds", "Could not register participant - failed to update in database"));
|
|
}
|
|
|
|
participantToRegister->publishParticipant();
|
|
retVal = RegisterReturnValue::RegistrationOk;
|
|
|
|
return Core::FunctionReplyObject(request.participantId());
|
|
}
|
|
|
|
void ParticipantHandlerForExercise::onSetSimulatedPositionRequest(const rti::core::SampleIdentity &cookie, const SetSimulatedPosition &request)
|
|
{
|
|
ERROR_LOG(m_logger) << "onSetSimulatedPositionRequest: " << request;
|
|
const auto ret = setSimulatedPositionRequest(request);
|
|
if (ret.error())
|
|
WARNING_LOG(m_logger) << ret();
|
|
|
|
m_mainHandler->fts()->setSimulatedPositionReply(cookie, ret);
|
|
}
|
|
|
|
void ParticipantHandlerForExercise::setSimulatedPosition(Participant *participant, const SetSimulatedPosition &request)
|
|
{
|
|
if (!participant)
|
|
return;
|
|
ERROR_LOG(m_logger) << "setSimulatedPosition start.. ";
|
|
|
|
static const qint64 outDated = 10 * 60 * 1000; // 10 min
|
|
const qint64 oldTime = request.onlyOutdatedParticipants() ? (participant->position().sampleTime() + outDated) : 0;
|
|
const qint64 curTime = QDateTime::currentMSecsSinceEpoch();
|
|
if (oldTime < curTime)
|
|
{
|
|
TrainingAreaBase::EquipmentPosition pos;
|
|
pos.equipmentNumber(-participant->id());
|
|
pos.sampleTime(request.onlyOutdatedParticipants() ? participant->position().sampleTime() + 1 : curTime);
|
|
pos.position().position(request.position());
|
|
pos.position().reportingSource(Core::PositionReportingSource::SetByOperator);
|
|
|
|
if (!m_dtsTab)
|
|
{
|
|
m_dtsTab = TrainingAreaBase::Interface::Dts::create(m_mainHandler->dds());
|
|
m_dtsTab->enableEquipmentPosition();
|
|
}
|
|
m_dtsTab->publish(pos);
|
|
}
|
|
for (auto childId : participant->inferiors())
|
|
setSimulatedPosition(m_participants.value(childId), request);
|
|
}
|
|
|
|
void ParticipantHandlerForExercise::onSetSimulatedPositionRelativeRequest(const rti::core::SampleIdentity &cookie, const SetSimulatedPositionRelative &request)
|
|
{
|
|
DEBUG_LOG(m_logger) << "onSetSimulatedPositionRelativeRequest: " << request;
|
|
const auto ret = setSimulatedPositionRelativeRequest(request);
|
|
if (ret.error())
|
|
WARNING_LOG(m_logger) << ret();
|
|
|
|
m_mainHandler->fts()->setSimulatedPositionRelativeReply(cookie, ret);
|
|
}
|
|
|
|
Core::FunctionReplyObject ParticipantHandlerForExercise::setSimulatedPositionRelativeRequest(const SetSimulatedPositionRelative &request)
|
|
{
|
|
if (request.participantId() <= 0)
|
|
return Core::FunctionReplyObject(request.participantId(), tr_lts("dds", "Could not move participant - participant id %1 is invalid")).arg(request.participantId());
|
|
|
|
Participant *participant = m_participants.value(request.participantId(), nullptr);
|
|
|
|
if (participant == nullptr)
|
|
return Core::FunctionReplyObject(request.participantId(), tr_lts("dds", "Could not move participant - participant id %1 is invalid")).arg(request.participantId());
|
|
|
|
setSimulatedPositionRelative(participant, request);
|
|
|
|
return Core::FunctionReplyObject(request.participantId());
|
|
}
|
|
|
|
void ParticipantHandlerForExercise::updateParticipantFormation(Participant *participant, const Core::GeoPosition &position, const QPointF &offset)
|
|
{
|
|
if (!participant)
|
|
return;
|
|
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " id = " << participant->id();
|
|
|
|
Core::GeoPosition tempPos;
|
|
if (qFuzzyIsNull(position.lon()) || qFuzzyIsNull(position.lat()))
|
|
{
|
|
// typical for units:
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " participantId=" << participant->id() << ", skip due to position isFuzzyNull =" << position;
|
|
}
|
|
else
|
|
{
|
|
// add offset in meter:
|
|
const LtsCoordTrans::UtmCoordinate partCoord = LtsCoordTrans::UtmCoordinate::fromGeographic(QPointF(position.lon(), position.lat()));
|
|
const QPointF coordinate = partCoord.geographic(QPointF(offset.x(), offset.y())); // offet in meter
|
|
DEBUG_LOG(m_logger) << "coordinate=" << coordinate.x() << " - " << coordinate.y() << " offset(" << offset.x() << ";" << offset.y() << ")";
|
|
|
|
tempPos.lon(coordinate.x());
|
|
tempPos.lat(coordinate.y());
|
|
|
|
TrainingAreaBase::EquipmentPosition pos;
|
|
pos.equipmentNumber(-participant->id());
|
|
const qint64 curTime = QDateTime::currentMSecsSinceEpoch();
|
|
pos.sampleTime(curTime);
|
|
pos.position().position(tempPos);
|
|
pos.position().reportingSource(Core::PositionReportingSource::SetByOperator);
|
|
|
|
if (!m_dtsTab)
|
|
{
|
|
m_dtsTab = TrainingAreaBase::Interface::Dts::create(m_mainHandler->dds());
|
|
m_dtsTab->enableEquipmentPosition();
|
|
}
|
|
m_dtsTab->publish(pos);
|
|
}
|
|
}
|
|
|
|
void ParticipantHandlerForExercise::setFormationAsLine(Participant *participant,
|
|
const SetSimulatedParticipantFormation &request,
|
|
const double distance,
|
|
const double angleDeg)
|
|
{
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " set formation As line...";
|
|
if (!participant)
|
|
return;
|
|
|
|
DEBUG_LOG(m_logger) << " participant Name: " << participant->participantData().name() << " inferiorCount: " << participant->inferiors().size();
|
|
const std::vector<int> &inferiors = participant->inferiors();
|
|
if (inferiors.empty())
|
|
return;
|
|
else if (inferiors.size() == 1) // in case only one pp
|
|
{
|
|
const SetSimulatedPosition simPosReq(participant->id(), request.position(), false);
|
|
setSimulatedPosition(participant, simPosReq);
|
|
return;
|
|
}
|
|
|
|
// adjust participant positions distance to one another
|
|
QPolygonF ppPoints;
|
|
ppPoints.reserve(inferiors.size());
|
|
for (int i = 0; i < (int)inferiors.size(); ++i)
|
|
ppPoints.push_back(QPointF(i * distance, 0));
|
|
|
|
double rotationAngle = 0;
|
|
// set rotation to 0° North(12h) counter clock wise
|
|
{
|
|
rotationAngle = angleDeg < 360. ? angleDeg : std::fmod(angleDeg, 360.);
|
|
rotationAngle = rotationAngle < 90. ? std::fabs(90 - rotationAngle) : std::fabs(360 - rotationAngle + 90);
|
|
}
|
|
|
|
const double length = (inferiors.size() - 1) * distance;
|
|
QTransform transform = QTransform().translate(-length / 2.0, 0);
|
|
ppPoints = transform.map(ppPoints);
|
|
transform.reset();
|
|
// rotate
|
|
ppPoints = transform.rotate(rotationAngle).map(ppPoints);
|
|
|
|
for (int index = 0; index < (int)inferiors.size(); ++index)
|
|
updateParticipantFormation(m_participants.value(inferiors[index]), request.position(), ppPoints.at(index));
|
|
}
|
|
|
|
void ParticipantHandlerForExercise::setSimulatedPositionRelative(Participant *participant, const SetSimulatedPositionRelative &request)
|
|
{
|
|
if (!participant)
|
|
return;
|
|
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " id = " << participant->id();
|
|
|
|
Core::GeoPosition tempPos = participant->position().pos();
|
|
|
|
if (qFuzzyIsNull(tempPos.lon()) || qFuzzyIsNull(tempPos.lat()))
|
|
{
|
|
// typical for units:
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " participantId=" << participant->id() << ", skip due to position isFuzzyNull =" << tempPos;
|
|
}
|
|
else
|
|
{
|
|
// add offset in meter:
|
|
LtsCoordTrans::UtmCoordinate partCoord = LtsCoordTrans::UtmCoordinate::fromGeographic(QPointF(tempPos.lon(), tempPos.lat()));
|
|
QPointF posWithOffset = partCoord.geographic(QPointF(request.positionOffsetX(), request.positionOffsetY())); // offet in meter
|
|
DEBUG_LOG(m_logger) << LOGFUNCTION << " posWithOffset=" << posWithOffset.x() << " - " << posWithOffset.y();
|
|
|
|
tempPos.lon(posWithOffset.x());
|
|
tempPos.lat(posWithOffset.y());
|
|
|
|
TrainingAreaBase::EquipmentPosition pos;
|
|
pos.equipmentNumber(-participant->id());
|
|
const qint64 curTime = QDateTime::currentMSecsSinceEpoch();
|
|
pos.sampleTime(curTime);
|
|
pos.position().position(tempPos);
|
|
pos.position().reportingSource(Core::PositionReportingSource::SetByOperator);
|
|
|
|
if (!m_dtsTab)
|
|
{
|
|
m_dtsTab = TrainingAreaBase::Interface::Dts::create(m_mainHandler->dds());
|
|
m_dtsTab->enableEquipmentPosition();
|
|
}
|
|
m_dtsTab->publish(pos);
|
|
}
|
|
for (auto childId : participant->inferiors())
|
|
setSimulatedPositionRelative(m_participants.value(childId), request); // recursive
|
|
}
|
|
|
|
void ParticipantHandlerForExercise::onSetSimulatedParticipantFormationRequest(const rti::core::SampleIdentity &cookie, const SetSimulatedParticipantFormation &request)
|
|
{
|
|
DEBUG_LOG(m_logger) << "onSetSimulatedParticipantFormationRequest: " << request;
|
|
const auto ret = setSimulatedParticipantFormationRequest(request);
|
|
if (ret.error())
|
|
WARNING_LOG(m_logger) << ret();
|
|
|
|
m_mainHandler->fts()->setSimulatedParticipantFormationReply(cookie, ret);
|
|
}
|
|
|
|
Core::FunctionReplyObject ParticipantHandlerForExercise::setSimulatedParticipantFormationRequest(const SetSimulatedParticipantFormation &request)
|
|
{
|
|
if (request.participantId() <= 0)
|
|
return Core::FunctionReplyObject(request.participantId(), tr_lts("dds", "Could not move participant - participant id %1 is invalid")).arg(request.participantId());
|
|
|
|
Participant *participant = m_participants.value(request.participantId(), nullptr);
|
|
|
|
if (participant == nullptr)
|
|
return Core::FunctionReplyObject(request.participantId(), tr_lts("dds", "Could not move participant - participant id %1 is invalid")).arg(request.participantId());
|
|
|
|
const ParticipantFormationStruct formation(QString::fromStdString(request.formation()));
|
|
if (formation.hasFormationData())
|
|
{
|
|
DEBUG_LOG(m_logger) << "setSimulatedParticipantFormation type: " << formation.geometry << " | distance: " << formation.distance << " | angle: " << formation.angle;
|
|
setFormationAsLine(participant, request, formation.distance, formation.angle);
|
|
}
|
|
else
|
|
{
|
|
DEBUG_LOG(m_logger) << "setSimulatedPositionRelative WITHOUT FORMATION";
|
|
SetSimulatedPositionRelative relSimRequest(request.participantId(), request.positionOffsetX(), request.positionOffsetY());
|
|
setSimulatedPositionRelative(participant, relSimRequest);
|
|
}
|
|
|
|
return Core::FunctionReplyObject(request.participantId());
|
|
}
|
|
|
|
void ParticipantHandlerForExercise::onSetSanitationRequest(const rti::core::SampleIdentity &cookie, const SetSanitationRequest &request)
|
|
{
|
|
DEBUG_LOG(m_logger) << "onSetSanitationRequest: " << request;
|
|
const auto ret = setSanitationRequest(cookie, request);
|
|
if (ret.error())
|
|
WARNING_LOG(m_logger) << ret();
|
|
|
|
m_mainHandler->fts()->setSanitationReply(cookie, ret);
|
|
}
|
|
|
|
Core::FunctionReplyObject ParticipantHandlerForExercise::setSanitationRequest(const rti::core::SampleIdentity &cookie, const SetSanitationRequest &request)
|
|
{
|
|
Participant *participant = m_participants.value(request.id(), nullptr);
|
|
|
|
if (participant == nullptr)
|
|
return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Could not set participant - participant id %1 is invalid")).arg(request.id());
|
|
|
|
TrainingAreaBase::SendSetSanitationRequest tabRequest;
|
|
tabRequest.equipmentNumber(participant->equipmentNumber());
|
|
tabRequest.originatorEquipmentNumber(request.data().originatorEquipmentNumber());
|
|
tabRequest.participantId(request.id());
|
|
tabRequest.qualification(static_cast<TrainingAreaBase::Qualification::inner_enum>(request.data().qualification().underlying()));
|
|
tabRequest.sanitationProceduresTaken(request.data().sanitationProceduresTaken());
|
|
|
|
return m_proxyListener->sendSetSanitationRequest(cookie, tabRequest);
|
|
}
|
|
|
|
void ParticipantHandlerForExercise::onSelectiveReammunitionRequest(const rti::core::SampleIdentity &cookie, const SelectiveReammunitionRequest &request)
|
|
{
|
|
DEBUG_LOG(m_logger) << "onSelectiveReammunitionRequest: " << request;
|
|
const auto ret = selectiveReammunitionRequest(cookie, request);
|
|
if (ret.error())
|
|
WARNING_LOG(m_logger) << ret();
|
|
|
|
m_mainHandler->fts()->selectiveReammunitionReply(cookie, ret);
|
|
}
|
|
|
|
Core::FunctionReplyObject ParticipantHandlerForExercise::selectiveReammunitionRequest(const rti::core::SampleIdentity &cookie,
|
|
const SelectiveReammunitionRequest &request)
|
|
{
|
|
Participant *participant = m_participants.value(request.id(), nullptr);
|
|
|
|
INFO_LOG(m_logger) << "ParticipantHandlerForExercise::selectiveReammunitionRequest: ";
|
|
|
|
if (participant == nullptr)
|
|
return Core::FunctionReplyObject(request.id(), tr_lts("dds", "Could not set participant - participant id %1 is invalid")).arg(request.id());
|
|
|
|
INFO_LOG(m_logger) << "Participant id = " << request.id();
|
|
|
|
TrainingAreaBase::SendSelectiveReammunitionRequest tabRequest;
|
|
tabRequest.equipmentNumber(participant->equipmentNumber());
|
|
tabRequest.participantId(request.id());
|
|
tabRequest.gearId(request.gearId());
|
|
INFO_LOG(m_logger) << "Gear id = " << request.gearId();
|
|
for (const Reammunition ra : qAsConst(request.reammunition()))
|
|
{
|
|
TrainingAreaBase::Reammunition tabRa;
|
|
tabRa.chargeTypeId(ra.chargeTypeId());
|
|
tabRa.newDefaultStock(ra.newDefaultStock());
|
|
tabRa.newStock(ra.newStock());
|
|
tabRa.tracerRatio(ra.tracerRatio());
|
|
INFO_LOG(m_logger) << "Charge type id = " << ra.chargeTypeId();
|
|
tabRequest.reammunition().push_back(tabRa);
|
|
}
|
|
|
|
return m_proxyListener->selectiveReammunitionRequest(cookie, tabRequest);
|
|
}
|
|
|
|
void ParticipantHandlerForExercise::onSetAsSimulatedRequest(const rti::core::SampleIdentity &cookie, const SetAsSimulated &request)
|
|
{
|
|
DEBUG_LOG(m_logger) << " onSetAsSimulatedRequest: " << request;
|
|
const auto ret = setAsSimulatedRequest(request);
|
|
if (ret.error())
|
|
WARNING_LOG(m_logger) << ret();
|
|
|
|
m_mainHandler->fts()->setAsSimulatedReply(cookie, ret);
|
|
}
|
|
|
|
Core::FunctionReplyObject ParticipantHandlerForExercise::setAsSimulatedRequest(const SetAsSimulated &request)
|
|
{
|
|
DEBUG_LOG(m_logger) << "setAsSimulatedRequest: " << request;
|
|
|
|
ParticipantManagement::Participant participant = m_ppmDtc->participant(request.participantId());
|
|
participant.isSimulated(request.setSimulated());
|
|
const ParticipantManagement::ParticipantData &data = m_ppmDtc->convertParticipantToParticipantData(participant);
|
|
|
|
Database::PpmParticipant dbParticipant = toDbParticipant(data, request.participantId());
|
|
dbParticipant.superiorId = participant.superiorId();
|
|
DEBUG_LOG(m_logger) << "PpmParticipant setted supId: " << dbParticipant.tacticalIdentifier << " superiorId: " << dbParticipant.superiorId;
|
|
|
|
// db update in ppm_participant
|
|
if (!m_mainHandler->db()->update(dbParticipant))
|
|
return Core::FunctionReplyObject(request.participantId(), tr_lts("dds", "Could not update participant data in database, participant data may be inconsistent"));
|
|
|
|
// publishing participant data
|
|
dts()->publish(participant);
|
|
return Core::FunctionReplyObject(request.participantId());
|
|
}
|
|
|
|
void ParticipantHandlerForExercise::onOcCommandRequest(const rti::core::SampleIdentity &cookie, const ParticipantManagement::OcCommandRequest &request)
|
|
{
|
|
DEBUG_LOG(m_logger) << "onOcCommandRequest: " << request;
|
|
auto ret = ocCommandRequest(cookie, request);
|
|
if (ret.error())
|
|
{
|
|
WARNING_LOG(m_logger) << ret();
|
|
m_mainHandler->fts()->ocCommandReply(cookie, ret);
|
|
}
|
|
// delayed answer in non-error case
|
|
}
|
|
|
|
Core::FunctionReplyObject ParticipantHandlerForExercise::ocCommandRequest(const rti::core::SampleIdentity &cookie, const ParticipantManagement::OcCommandRequest &request)
|
|
{
|
|
TrainingAreaBase::SendOcCommandRequest req;
|
|
|
|
int failedParticipantId = 0;
|
|
if (!participantIds2EquipmentNumbers(request.participantIds(), req.equipmentNumbers(), &failedParticipantId))
|
|
return Core::FunctionReplyObject(0, tr_lts("dds", "Got invalid participant id %1 in init request")).arg(failedParticipantId);
|
|
|
|
req.requestId(s_tabRequestId++);
|
|
req.action(request.action());
|
|
|
|
return m_proxyListener->sendOcCommandRequest(cookie, req);
|
|
}
|
|
|
|
Core::FunctionReplyObject ParticipantHandlerForExercise::setSimulatedPositionRequest(const SetSimulatedPosition &request)
|
|
{
|
|
if (request.participantId() <= 0)
|
|
{
|
|
for (Participant *participant : qAsConst(m_participants))
|
|
{
|
|
if (participant->isDeleted() || participant->superiorId() != 0)
|
|
continue;
|
|
setSimulatedPosition(participant, request);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Participant *participant = m_participants.value(request.participantId(), nullptr);
|
|
|
|
if (participant == nullptr)
|
|
return Core::FunctionReplyObject(request.participantId(), tr_lts("dds", "Could not set participant - participant id %1 is invalid")).arg(request.participantId());
|
|
|
|
setSimulatedPosition(participant, request);
|
|
}
|
|
|
|
return Core::FunctionReplyObject(request.participantId());
|
|
}
|
|
|
|
Core::FunctionReplyObject ParticipantHandlerForExercise::createNewParticipants(std::vector<Database::PpmParticipant> &dbParticipantsToBeCreated,
|
|
const std::vector<int> &dbParticipantsToBeCreatedIndexes,
|
|
const QVector<ParticipantData> &participantsToBeCreatedOrModified,
|
|
QHash<int, int> &modIdToParticipantId,
|
|
QSet<Participant *> &participantsWithChanges)
|
|
{
|
|
DEBUG_LOG(m_logger) << "Trying to create " << dbParticipantsToBeCreated.size() << " participants";
|
|
// creating db entries
|
|
if (!m_mainHandler->db()->insert(dbParticipantsToBeCreated))
|
|
return Core::FunctionReplyObject(tr_lts("dds", "Error inserting new participant into database, participant data may be inconsistent"));
|
|
for (size_t i = 0; i < dbParticipantsToBeCreated.size(); ++i)
|
|
{
|
|
const int index = dbParticipantsToBeCreatedIndexes.at(i);
|
|
const auto &ddsParticipant = participantsToBeCreatedOrModified.at(index);
|
|
ParticipantForExercise *newParticipant = new ParticipantForExercise(m_mainHandler, this, m_unitPositionCalculator.get(), dbParticipantsToBeCreated.at(i));
|
|
// add to m_participants
|
|
m_participants.insert(newParticipant->id(), newParticipant);
|
|
|
|
// map mod id
|
|
modIdToParticipantId.insert(ddsParticipant.modId(), newParticipant->id());
|
|
|
|
// register to publish changes
|
|
participantsWithChanges.insert(newParticipant);
|
|
}
|
|
|
|
return Core::FunctionReplyObject();
|
|
}
|
|
|
|
Core::FunctionReplyObject ParticipantHandlerForExercise::validateParticipantData(ValidateParticipantData &data,
|
|
const ParticipantManagement::ParticipantData &participantToValidate)
|
|
{
|
|
DEBUG_LOG(m_logger) << "checking party id";
|
|
if (m_mainHandler->partyHandler()->partyById(participantToValidate.partyId()) == nullptr)
|
|
{
|
|
|
|
return Core::FunctionReplyObject(tr_lts("dds", "Got invalid party id %1")).arg(participantToValidate.partyId());
|
|
}
|
|
if (isSupportType(participantToValidate.typeId()))
|
|
{
|
|
if (participantToValidate.partyId() != 1)
|
|
{
|
|
|
|
return Core::FunctionReplyObject(tr_lts("dds", "Got party id %1 for a support participant. Support participants have to be in party 1"))
|
|
.arg(participantToValidate.partyId());
|
|
}
|
|
}
|
|
else if (participantToValidate.partyId() == 1)
|
|
|
|
return Core::FunctionReplyObject(tr_lts("dds", "Not possible to add a non support participant to party with id 1"));
|
|
DEBUG_LOG(m_logger) << "... ok";
|
|
|
|
const int partId = participantToValidate.id();
|
|
auto *existingParticipant = participantById(partId);
|
|
// participant id valid?
|
|
if (participantToValidate.id() != 0 && (existingParticipant != nullptr)) // got participantData with Id and participant already exits
|
|
{
|
|
// assign state valid?
|
|
DEBUG_LOG(m_logger) << "checking assign state";
|
|
int32_t equipmentNumber = 0;
|
|
if (participantToValidate.equipmentNumber().is_set())
|
|
equipmentNumber = participantToValidate.equipmentNumber().get();
|
|
|
|
bool isAssignStateValid = existingParticipant->isNewAssignStateValid(participantToValidate.assignState(), equipmentNumber);
|
|
if (!isAssignStateValid)
|
|
{
|
|
return Core::FunctionReplyObject(partId, tr_lts("dds", "The combination of equipment number and assign state for particpant '%1' is invalid"))
|
|
.arg(participantInfosFromId(partId));
|
|
}
|
|
DEBUG_LOG(m_logger) << "... ok";
|
|
|
|
// typeId must not be changed when an equipmentNumber is already set
|
|
if (existingParticipant->equipmentNumber() != 0)
|
|
{
|
|
// type id same when participantId is set?
|
|
DEBUG_LOG(m_logger) << "checking if typeId is not modified";
|
|
if (existingParticipant->typeId() != participantToValidate.typeId())
|
|
{
|
|
|
|
return Core::FunctionReplyObject(partId, tr_lts("dds", "It is not allowed to change the type of a participant (%1)")).arg(participantInfosFromId(partId));
|
|
}
|
|
DEBUG_LOG(m_logger) << "... ok";
|
|
}
|
|
data.modIdToParticipantId.insert(participantToValidate.modId(), existingParticipant->id()); /* register participant to indicate that this participant
|
|
should just be modified and not newly created */
|
|
}
|
|
else
|
|
{
|
|
DEBUG_LOG(m_logger) << "New participant to be added: " << participantToValidate;
|
|
|
|
DEBUG_LOG(m_logger) << "checking participant id " << partId;
|
|
if (participantToValidate.id() != 0 && !data.forceAddWithId)
|
|
{
|
|
|
|
return Core::FunctionReplyObject(partId, tr_lts("dds", "An invalid participant '%1' was given")).arg(participantInfosFromId(partId));
|
|
}
|
|
DEBUG_LOG(m_logger) << "... ok";
|
|
|
|
// new participant
|
|
if (participantToValidate.equipmentNumber().is_set())
|
|
{
|
|
if (participantToValidate.assignState() != ParticipantAssignState::HandoutExcon)
|
|
|
|
return Core::FunctionReplyObject(participantToValidate.modId(),
|
|
tr_lts("dds", "Got a new participant with an equipment number (%1) but assign state is not HandoutExcon"))
|
|
.arg(participantToValidate.equipmentNumber().get());
|
|
}
|
|
else
|
|
{
|
|
if (participantToValidate.assignState() != ParticipantAssignState::NotAssigned)
|
|
return Core::FunctionReplyObject(participantToValidate.modId(),
|
|
tr_lts("dds", "Got a new participant with no equipment number set but assign state != NotAssigned"));
|
|
}
|
|
}
|
|
|
|
// superior ids valid?
|
|
if (participantToValidate.superiorModId() > 0)
|
|
{
|
|
DEBUG_LOG(m_logger) << "checking superiorIds";
|
|
// superior exists?
|
|
bool isExistingSuperiorId = false;
|
|
for (const ParticipantData &dat : qAsConst(data.participantsToBeCreatedOrModified))
|
|
{
|
|
if (participantToValidate.superiorModId() == dat.modId())
|
|
{
|
|
isExistingSuperiorId = true;
|
|
break; // for (const ParticipantData &dat : data.dataVec)
|
|
}
|
|
}
|
|
|
|
if (!isExistingSuperiorId)
|
|
{
|
|
return Core::FunctionReplyObject(tr_lts("dds", "Internal Error - the data set with modId %1 has an invalid superiorModId %2"))
|
|
.arg(participantToValidate.modId())
|
|
.arg(participantToValidate.superiorModId());
|
|
}
|
|
DEBUG_LOG(m_logger) << "... ok";
|
|
|
|
if (participantToValidate.hierarchyNumber() <= 0)
|
|
return Core::FunctionReplyObject(tr_lts("dds", "Internal Error - the data has a superior but no valid hierarchyNumber"));
|
|
|
|
// all hierarchy numbers with same superior unique?
|
|
DEBUG_LOG(m_logger) << "checking hierarchyNumbers";
|
|
for (const ParticipantData &dat : qAsConst(data.participantsToBeCreatedOrModified))
|
|
{
|
|
// operator==() on optionals returns false if not set ...
|
|
if (dat.modId() != participantToValidate.modId() && dat.superiorModId() == participantToValidate.superiorModId()
|
|
&& dat.hierarchyNumber() == participantToValidate.hierarchyNumber())
|
|
{
|
|
return Core::FunctionReplyObject(tr_lts("dds", "Internal Error - superiorModId %1 hierarchyNumber %2 is not unique"))
|
|
.arg(dat.superiorModId())
|
|
.arg(dat.hierarchyNumber());
|
|
}
|
|
}
|
|
DEBUG_LOG(m_logger) << "... ok";
|
|
}
|
|
else
|
|
{
|
|
const Participant *curParticipant = m_participants.value(participantToValidate.id());
|
|
bool bOk = curParticipant != nullptr;
|
|
// superiorModId == 0 -> root knot (can be new because of participant organisation)
|
|
if (curParticipant && participantToValidate.superiorModId() != 0)
|
|
{
|
|
// an update of an existing participant, the hierarchy number must not change
|
|
if (participantToValidate.hierarchyNumber() != curParticipant->toDbParticipant().hierarchyNumber)
|
|
{
|
|
WARNING_LOG(m_logger) << "participant: " << curParticipant->toDdsParticipant(curParticipant->toDbParticipant());
|
|
bOk = false;
|
|
}
|
|
// anything else to check here?
|
|
}
|
|
else
|
|
bOk = (participantToValidate.hierarchyNumber() == 1); // root know of a participant tree - the hierarchy number must be 1
|
|
|
|
if (!bOk)
|
|
{
|
|
WARNING_LOG(m_logger) << "participantToValidate: " << participantToValidate;
|
|
return Core::FunctionReplyObject(tr_lts("dds", "Internal Error - the root participant (%1) must have a hierarchy number of '1'")).arg(participantToValidate.id());
|
|
}
|
|
}
|
|
|
|
// typeId valid?
|
|
DEBUG_LOG(m_logger) << "checking typeId";
|
|
const Type *type = typeById(participantToValidate.typeId());
|
|
if (type == nullptr) // type invalid
|
|
return Core::FunctionReplyObject(tr_lts("dds", "Internal Error - data with modId %1 has invalid typeId %2"))
|
|
.arg(participantToValidate.modId())
|
|
.arg(participantToValidate.typeId());
|
|
|
|
DEBUG_LOG(m_logger) << "... ok";
|
|
|
|
DEBUG_LOG(m_logger) << "Check if type is allowed in ex_" << m_mainHandler->exerciseId();
|
|
if (m_mainHandler->exerciseId() < 1 && !isSupportTypeClass(type->typeClass())) // only support types allowed
|
|
return Core::FunctionReplyObject(tr_lts("dds", "Internal Error - got non support participant data in ex_0 --> not allowed"));
|
|
|
|
DEBUG_LOG(m_logger) << "... ok";
|
|
|
|
if (participantToValidate.equipmentNumber().is_set())
|
|
{
|
|
const int equipNo = participantToValidate.equipmentNumber().get();
|
|
const int participantId = participantToValidate.id();
|
|
DEBUG_LOG(m_logger) << "Check if equipment number is globally unique " << equipNo;
|
|
int partIdLookup = m_equipNumber2ParticipantId.value(equipNo);
|
|
if (partIdLookup != 0 && partIdLookup != participantId)
|
|
{
|
|
if (participantToValidate.partyId() == 0) // in pool, participant was moved from template to pool (otherwise the equipment number could not be twice)
|
|
{
|
|
// mod id since it can be new (in fact it must be new here)
|
|
data.participantsToResetEquipmentNumber += participantToValidate.modId();
|
|
INFO_LOG(m_logger) << "Moved a participant from template to pool with an equipment number which already exists - remove equipment number: " << equipNo;
|
|
}
|
|
else
|
|
return Core::FunctionReplyObject(tr_lts("dds", "Another participant already has the same equipment number %1 (%2)"))
|
|
.arg(equipNo)
|
|
.arg(participantInfosFromId(participantId));
|
|
}
|
|
else if (isCurrentExerciseActive())
|
|
{
|
|
auto it = m_equipmentExerciseMappings.find(equipNo);
|
|
if (it != m_equipmentExerciseMappings.end())
|
|
{
|
|
if (it.value().exerciseId != m_mainHandler->exerciseId() || it.value().participantId != participantToValidate.id())
|
|
return Core::FunctionReplyObject(tr_lts("dds", "The equipment number %1 is already used by another participant in another exercise (%2)"))
|
|
.arg(equipNo)
|
|
.arg(participantInfosFromId(participantId));
|
|
}
|
|
}
|
|
|
|
DEBUG_LOG(m_logger) << "... ok";
|
|
}
|
|
|
|
return Core::FunctionReplyObject();
|
|
}
|
|
|
|
std::vector<int32_t> ParticipantHandlerForExercise::inferiorIdsForParticipant(int32_t superiorParticipantId) const
|
|
{
|
|
std::vector<int32_t> result;
|
|
|
|
for (Participant *currentParticipant : m_participants)
|
|
{
|
|
if (currentParticipant->superiorId() == superiorParticipantId)
|
|
result.push_back(currentParticipant->id());
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
Core::FunctionReplyObject ParticipantHandlerForExercise::checkDeleteParticipant(int id)
|
|
{
|
|
Participant *participant = m_participants.value(id);
|
|
if (!participant)
|
|
return Core::FunctionReplyObject(id, "Could not delete participant with id %1, because this ID does not exist").arg(id);
|
|
int eqIdToReset = participant->equipmentNumber();
|
|
if (eqIdToReset != 0)
|
|
{
|
|
// when we are not 'owner' of the equipment number, we are not allowed to remove this participant
|
|
switch (participant->assignState().underlying())
|
|
{
|
|
case ParticipantAssignState::NotAssigned:
|
|
case ParticipantAssignState::HandoutExcon:
|
|
case ParticipantAssignState::ExconWmsOverruled: // really ExconWmsOverruled?
|
|
break;
|
|
case ParticipantAssignState::AssignedWms:
|
|
case ParticipantAssignState::HandoutWms:
|
|
return Core::FunctionReplyObject(id, tr_lts("dds", "Can not remove participant with equipment number %1 - handled by warehouse")).arg(eqIdToReset);
|
|
}
|
|
}
|
|
|
|
for (int32_t inferiorId : participant->inferiors())
|
|
{
|
|
auto ret = checkDeleteParticipant(inferiorId);
|
|
if (ret.error())
|
|
return ret;
|
|
}
|
|
return Core::FunctionReplyObject();
|
|
}
|
|
|
|
Core::FunctionReplyObject ParticipantHandlerForExercise::deleteParticipant(int32_t id, bool permanentRemove, bool isTriggeredFromFtRequest)
|
|
{
|
|
Participant *participant = m_participants.value(id);
|
|
|
|
if (!participant)
|
|
return Core::FunctionReplyObject(id, "Could not delete participant with id %1, because this ID does not exist").arg(id);
|
|
|
|
for (int32_t inferiorId : participant->inferiors())
|
|
{
|
|
auto rep = deleteParticipant(inferiorId, permanentRemove);
|
|
|
|
if (rep.error())
|
|
return rep;
|
|
}
|
|
|
|
int eqIdToReset = participant->equipmentNumber();
|
|
DEBUG_LOG(m_logger) << "RemoveParticipant, eqId: " << eqIdToReset << ", assignState: " << participant->assignState();
|
|
// only remove equipment number when assign state is excon otherwise we will go out of sync with warehouse
|
|
// not assigned and eqid != 0 ? should never happen but who knows
|
|
if (participant->assignState() != ParticipantAssignState::NotAssigned && participant->assignState() != ParticipantAssignState::HandoutExcon
|
|
&& participant->assignState() != ParticipantAssignState::ExconWmsOverruled) // really ExconWmsOverruled?
|
|
return Core::FunctionReplyObject(id, tr_lts("dds", "Can not remove participant with equipment number %1 - handled by warehouse")).arg(eqIdToReset);
|
|
|
|
if (m_mainHandler->ddsHandler()->dtc()->isTypeUas(participant->typeId())
|
|
&& m_mainHandler->ddsHandler()->dtc()->getUasByParticipantId(participant->id(), m_mainHandler->exerciseId()).id() > 0)
|
|
{
|
|
// is in use
|
|
return Core::FunctionReplyObject(id, tr_lts("dds", "Can not remove participant assigned to UAS: %1"))
|
|
.arg(m_mainHandler->ddsHandler()->dtc()->getUasByParticipantId(participant->id(), m_mainHandler->exerciseId()).deviceIdentifier());
|
|
}
|
|
if (permanentRemove)
|
|
{
|
|
if (!dts()->removeParticipantByKey(id))
|
|
return Core::FunctionReplyObject(id, tr_lts("dds", "Error removing participant with id %1 from DDS")).arg(id);
|
|
if (!m_mainHandler->db()->removePpmParticipant(id))
|
|
return Core::FunctionReplyObject(id, tr_lts("dds", "Error removing participant with id %1 from Database")).arg(id);
|
|
auto it = m_participants.find(id);
|
|
if (it != m_participants.end())
|
|
{
|
|
delete it.value();
|
|
m_participants.erase(it);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
if (eqIdToReset != 0)
|
|
{
|
|
auto ftData = participant->toRegisterParticipantRequest();
|
|
ftData.equipmentNumber(0);
|
|
ftData.assignState(ParticipantAssignState::NotAssigned);
|
|
auto *pfe = static_cast<ParticipantForExercise *>(participant);
|
|
pfe->registerFromFt(ftData);
|
|
}
|
|
participant->markAsDeleted();
|
|
|
|
// change in database and publish
|
|
if (!m_mainHandler->db()->update(participant->toDbParticipant()))
|
|
return Core::FunctionReplyObject(id, "Error while updating participant with id %1 in database").arg(id);
|
|
if (!participant->publishParticipant())
|
|
return Core::FunctionReplyObject(id, "Error while publishing participant with id %1 to DDS").arg(id);
|
|
}
|
|
if (eqIdToReset)
|
|
m_equipNumber2ParticipantId.remove(eqIdToReset);
|
|
|
|
// publish superior changes
|
|
if (isTriggeredFromFtRequest && participant->superiorId())
|
|
{
|
|
Participant *superior = m_participants.value(participant->superiorId());
|
|
|
|
if (superior && superior->hasNewInferiorStructure(inferiorIdsForParticipant(superior->id())))
|
|
superior->publishParticipant();
|
|
}
|
|
|
|
return Core::FunctionReplyObject();
|
|
}
|
|
|
|
const Type *ParticipantHandlerForExercise::typeById(int typeId) const { return m_mainHandler->typeHandler()->typeById(typeId); }
|
|
|
|
bool ParticipantHandlerForExercise::isSupportType(int typeId) const { return m_mainHandler->typeHandler()->isSupportType(typeId); }
|
|
|
|
bool ParticipantHandlerForExercise::isParticipantType(int typeId) const { return m_mainHandler->typeHandler()->isParticipantType(typeId); }
|
|
|
|
void ParticipantHandlerForExercise::startLongAction() { m_longActionTimer.start(); }
|
|
|
|
void ParticipantHandlerForExercise::checkLongActionBreak()
|
|
{
|
|
if (m_longActionTimer.elapsed() > 300)
|
|
{
|
|
m_mainHandler->ddsHandler()->longActionBreak();
|
|
m_longActionTimer.start();
|
|
}
|
|
}
|
|
|
|
bool ParticipantHandlerForExercise::participantIds2EquipmentNumbers(const std::vector<int32_t> &participantIds,
|
|
std::vector<int32_t> &equipmentNumbers,
|
|
int *failedParticipantId) const
|
|
{
|
|
*failedParticipantId = 0;
|
|
for (int participantId : participantIds)
|
|
{
|
|
if (participantId == 0)
|
|
{
|
|
if (participantIds.size() != 1)
|
|
{
|
|
WARNING_LOG(m_logger) << "ParticipantId 0 found, but more than on entry - not allowed";
|
|
return false;
|
|
}
|
|
equipmentNumbers.push_back(0);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
const Participant *participant = participantById(participantId);
|
|
if (!participant)
|
|
{
|
|
*failedParticipantId = participantId;
|
|
WARNING_LOG(m_logger) << "Could not find participant for participantId " << participantId;
|
|
return false;
|
|
}
|
|
if (participant->equipmentNumber() == 0)
|
|
{
|
|
*failedParticipantId = participantId;
|
|
WARNING_LOG(m_logger) << "Participant with id " << participantId << " has no equipment number";
|
|
return false;
|
|
}
|
|
equipmentNumbers.push_back(participant->equipmentNumber());
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void ParticipantHandlerForExercise::onEquipmentExerciseMappingChanged(const EquipmentExerciseMapping &data, DataModification mod)
|
|
{
|
|
switch (mod)
|
|
{
|
|
case DataModification::eAdded:
|
|
case DataModification::eModified:
|
|
{
|
|
QSet<int> oldEqIds;
|
|
for (const auto &db : qAsConst(m_equipmentExerciseMappings))
|
|
{
|
|
if (db.exerciseId != data.exerciseId())
|
|
continue;
|
|
oldEqIds.insert(db.equipmentNumber);
|
|
}
|
|
Database::EquipmentExerciseMapping eem;
|
|
eem.exerciseId = data.exerciseId();
|
|
for (const Equipment2ParticipantId &e2p : data.mapping())
|
|
{
|
|
eem.equipmentNumber = e2p.equipmentNumber();
|
|
eem.participantId = e2p.participantId();
|
|
oldEqIds.remove(eem.equipmentNumber);
|
|
m_equipmentExerciseMappings[e2p.equipmentNumber()] = eem;
|
|
}
|
|
for (int oldEqId : oldEqIds)
|
|
{
|
|
auto it = m_equipmentExerciseMappings.find(oldEqId);
|
|
if (it == m_equipmentExerciseMappings.end())
|
|
continue;
|
|
Database::EquipmentExerciseMapping &eemOld = it.value();
|
|
if (eemOld.exerciseId != data.exerciseId())
|
|
continue;
|
|
m_equipmentExerciseMappings.erase(it);
|
|
}
|
|
break;
|
|
}
|
|
case DataModification::eRemoved:
|
|
// exercise stopped or shut down
|
|
if (data.exerciseId() == m_mainHandler->exerciseId())
|
|
return;
|
|
for (const Equipment2ParticipantId &e2p : data.mapping())
|
|
m_equipmentExerciseMappings.remove(e2p.equipmentNumber());
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ParticipantHandlerForExercise::onExerciseChanged(const ExerciseManagement::Exercise &data, DataModification mod)
|
|
{
|
|
if (data.id() != m_mainHandler->exerciseId())
|
|
return;
|
|
|
|
bool bPublishNow = false;
|
|
if (mod == DataModification::eRemoved || data.state() == ExerciseManagement::ExerciseState::Created || data.state() == ExerciseManagement::ExerciseState::Stopped
|
|
|| data.state() == ExerciseManagement::ExerciseState::Terminated)
|
|
bPublishNow = false;
|
|
else
|
|
bPublishNow = true;
|
|
|
|
if (m_publishEquipmentExerciseMappings == bPublishNow)
|
|
return;
|
|
m_publishEquipmentExerciseMappings = bPublishNow;
|
|
publishEquipmentExerciseMapping();
|
|
}
|
|
|
|
void ParticipantHandlerForExercise::publishEquipmentExerciseMapping()
|
|
{
|
|
EquipmentExerciseMapping eem;
|
|
eem.exerciseId(m_mainHandler->exerciseId());
|
|
if (!m_publishEquipmentExerciseMappings)
|
|
{
|
|
m_mainHandler->exAnyDts()->publish(eem); // empty
|
|
return;
|
|
}
|
|
eem.mapping().reserve(m_equipNumber2ParticipantId.size());
|
|
for (auto it = m_equipNumber2ParticipantId.cbegin(); it != m_equipNumber2ParticipantId.cend(); ++it)
|
|
eem.mapping().emplace_back(it.key(), it.value());
|
|
m_mainHandler->exAnyDts()->publish(eem);
|
|
}
|
|
|
|
bool ParticipantHandlerForExercise::isCurrentExerciseActive() const
|
|
{
|
|
const auto exState = m_exmDtc->exercise(m_mainHandler->exerciseId()).state();
|
|
return (exState == ExerciseManagement::ExerciseState::Started || exState == ExerciseManagement::ExerciseState::Paused);
|
|
}
|
|
|
|
// more or less copy from ppm_dtc_impl_custom.cpp
|
|
QString ParticipantHandlerForExercise::lookUpHierachy(int participantId) const
|
|
{
|
|
if (participantId <= 0)
|
|
return QString();
|
|
|
|
const auto participant = m_participants.value(participantId);
|
|
if (!participant)
|
|
return QString();
|
|
|
|
QString ret = QString::fromStdString(participant->participantData().designator());
|
|
// First separator is "./"
|
|
if (participant->superiorId() <= 0)
|
|
return (ret + QLatin1String("./"));
|
|
|
|
QString supStr = lookUpHierachy(participant->superiorId());
|
|
if (supStr.endsWith(QLatin1String("./")))
|
|
return (supStr + ret);
|
|
|
|
return (supStr.isEmpty() ? ret : supStr + QLatin1Char(',') + ret);
|
|
}
|
|
|
|
QString ParticipantHandlerForExercise::participantInfosFromId(int participantId) const
|
|
{
|
|
const auto participant = m_participants.value(participantId);
|
|
if (!participant)
|
|
return QStringLiteral("Unknown participant: %1").arg(participantId);
|
|
const QString hierachy = lookUpHierachy(participantId);
|
|
if (participant->equipmentNumber() <= 0)
|
|
return hierachy;
|
|
return QStringLiteral("%1 (%2)").arg(hierachy).arg(participant->equipmentNumber());
|
|
}
|
|
|
|
void ParticipantHandlerForExercise::customedSetGearCharges(Participant *participant)
|
|
{
|
|
const auto ppType = m_mainHandler->typeHandler()->typeById(participant->typeId());
|
|
|
|
if (!ppType || ppType->typeClass() == TypeClass_def::Unknown || ppType->properties().empty())
|
|
return;
|
|
const QJsonObject &typObj = QJsonDocument::fromJson(QByteArray::fromStdString(ppType->properties())).object();
|
|
if (typObj.isEmpty())
|
|
return;
|
|
|
|
const bool isArtillery = typObj[QStringLiteral("isArtillery")].toBool(false);
|
|
const int gearClassId = typObj[QStringLiteral("gearClassId")].toInt(0);
|
|
const ProjectDataManagement::GearClass_def::type gearClass = static_cast<ProjectDataManagement::GearClass_def::type>(gearClassId);
|
|
static QVector<ProjectDataManagement::GearClass_def::type> validGearTypes{ProjectDataManagement::GearClass_def::Mortar,
|
|
ProjectDataManagement::GearClass_def::Rocket,
|
|
ProjectDataManagement::GearClass_def::Artillery};
|
|
if (!isArtillery || !validGearTypes.contains(gearClass))
|
|
return;
|
|
|
|
if (!m_pdmDtc)
|
|
{
|
|
m_pdmDtc = m_mainHandler->ddsHandler()->pdmDtc();
|
|
m_pdmDtc->waitForHistoricalDataGearType();
|
|
m_pdmDtc->waitForHistoricalDataGearTypeChargeType();
|
|
}
|
|
|
|
const auto &gearTypes = m_pdmDtc->gearTypes();
|
|
const auto >Cts = m_pdmDtc->gearTypeChargeTypes();
|
|
for (const auto > : gearTypes)
|
|
{
|
|
if (gt.gearClassId() != gearClass)
|
|
continue;
|
|
|
|
for (const auto >c : gtCts)
|
|
{
|
|
if (gtc.gearTypeId() != gt.id())
|
|
continue;
|
|
DEBUG_LOG(m_logger) << " >>> dataid: " << participant->id() << " gTypeId: " << gtc.gearTypeId() << " chargeType: " << gtc.chargeTypeId();
|
|
GearInformation gearInfo(gtc.gearTypeId(), gtc.gearTypeId(), gtc.chargeTypeId(), 0, QDateTime::currentMSecsSinceEpoch(), false);
|
|
participant->setGearCharge(gearInfo);
|
|
} // for
|
|
participant->publishDynamicData();
|
|
break;
|
|
} // for
|
|
}
|
|
void ParticipantHandlerForExercise::onModifyUasStateRequest(const rti::core::SampleIdentity &cookie, const ModifyUasStateRequest &request)
|
|
{
|
|
Core::FunctionReplyObject reply = modifyUasStateRequest(cookie, request);
|
|
if (reply.error())
|
|
{
|
|
WARNING_LOG(m_logger) << reply();
|
|
}
|
|
m_mainHandler->fts()->modifyUasStateReply(cookie, reply);
|
|
}
|
|
Core::FunctionReplyObject ParticipantHandlerForExercise::modifyUasStateRequest(const rti::core::SampleIdentity &cookie,
|
|
const ParticipantManagement::ModifyUasStateRequest &request)
|
|
{
|
|
DEBUG_LOG(m_logger) << "-- onModifyUasStateRequest: uasId:" << request.uasId() << " // EquipmentNumber: " << request.equipmentNumber()
|
|
<< " // State: " << request.uasState();
|
|
if (request.uasId() <= 0 || request.equipmentNumber() <= 0)
|
|
return Core::FunctionReplyObject(request.uasId(), tr_lts("dds", "uas id ( %1 ) or equipmentNumber ( %2 ) not found!"))
|
|
.arg(request.uasId())
|
|
.arg(request.equipmentNumber());
|
|
|
|
TrainingAreaBase::SendModifyUasStateRequest req;
|
|
req.requestId(s_tabRequestId++);
|
|
req.uasId(request.uasId());
|
|
req.uasState(request.uasState());
|
|
req.equipmentNumber(request.equipmentNumber());
|
|
return m_proxyListener->sendModifyUasStateRequest(cookie, req);
|
|
}
|
|
|
|
void ParticipantHandlerForExercise::onGearChargeChanged(int participantId, int partyId)
|
|
{
|
|
// Count charges for ADLER participants if one of them has changed data
|
|
if (!m_ppmDtc->isAdlerType(m_participants.value(participantId)->typeId()))
|
|
return;
|
|
|
|
// chargeTypeId, remain
|
|
QMap<qint32, int> chargeTypeGearData;
|
|
for (const Participant *part : m_participants)
|
|
{
|
|
if (!m_ppmDtc->isAdlerType(part->typeId()) || part->partyId() != partyId)
|
|
continue;
|
|
|
|
for (const GearInformation &gi : part->dynamicParticipantData().gear())
|
|
chargeTypeGearData[gi.chargeTypeId()] += gi.remain();
|
|
}
|
|
|
|
DEBUG_LOG(m_logger) << "chargeTypeGearData size: " << chargeTypeGearData.size();
|
|
|
|
QMapIterator<int, int> it(chargeTypeGearData);
|
|
while (it.hasNext())
|
|
{
|
|
it.next();
|
|
DEBUG_LOG(m_logger) << "partyId: " << partyId << ", chargeTypeId: " << it.key() << ", amount: " << it.value();
|
|
if (!m_pdmDtc->isAdlerChargeType(it.key()))
|
|
continue;
|
|
|
|
AreaEffectSimulation::ChargeAdministrationModifyRequest request;
|
|
request.chargeTypeId(it.key());
|
|
request.amount(it.value());
|
|
request.partyId(partyId);
|
|
request.effectSourceId(ProjectDataManagement::EffectSource::ES_ADLER);
|
|
request.amountChangedByOperator(false);
|
|
|
|
m_mainHandler->aesFtc()->chargeAdministrationModifyRequest(request);
|
|
}
|
|
}
|
|
|
|
} // namespace ParticipantHandling
|
|
} // namespace ParticipantManagement
|