#include "object_charge_effect.h" #include "object_base.h" #include #include #include "main_handler.h" namespace AreaEffectSimulation { qint32 ObjectChargeEffect::s_afterglowMsecs = 0; //----------------------------------------------------------------------------- ObjectChargeEffect::ObjectChargeEffect(const Database::AesChargeEffect &data, MainHandler *mainHandler, QObject *parent) : ObjectChargeEffect(mainHandler, parent) { m_data = data; } //----------------------------------------------------------------------------- ObjectChargeEffect::ObjectChargeEffect(MainHandler *mainHandler, QObject *parent) : QObject(parent) , m_mainHandler(mainHandler) , m_trajectoryId(-1) , m_state(AesEffectState::inner_enum::EsUnknown) , m_stateChanged(false) , m_stateTimer(new QTimer(this)) , m_logger(getLogger(QStringLiteral("ObjectChargeEffect"))) { m_stateTimer->setSingleShot(true); connect(m_stateTimer, &QTimer::timeout, this, &ObjectChargeEffect::onStateTimerTimeout); } //----------------------------------------------------------------------------- Core::FunctionReplyObject ObjectChargeEffect::create(const ChargeEffectModifyRequest &data) { Core::FunctionReplyObject reply(data.id()); Database::AesChargeEffect dbData = functionTopicToDatabase(data); if (!m_mainHandler) reply.setStr("Not possible to create ChargeEffect --> No MainHandler present."); else if (data.effectStart() < QDateTime::currentMSecsSinceEpoch()) reply.setStr("Not possible to create ChargeEffect --> EffectStart has to be in the future."); else if (data.effectDuration() < 1000) reply.setStr("Not possible to create ChargeEffect --> EffectDuration must be at least 1000ms."); else if (data.name().empty()) reply.setStr("Not possible to create ChargeEffect --> Name must not be empty."); else if (!m_mainHandler->db()->insert(dbData)) reply.setStr("Not possible to create ChargeEffect --> Database insert failed."); else { // everything is fine m_data = dbData; } if (reply.error()) ERROR_LOG(m_logger) << reply.str(); if (reply.id() == 0) reply.setId(m_data.id); return reply; } //----------------------------------------------------------------------------- Core::FunctionReplyObject ObjectChargeEffect::update(const ChargeEffectModifyRequest &data) { Core::FunctionReplyObject reply(data.id()); Database::AesChargeEffect dbData = functionTopicToDatabase(data); if (!m_mainHandler) reply.setStr("Not possible to update ChargeEffect --> No MainHandler present."); else if (data.id() != m_data.id) reply.setStr("Not possible to update ChargeEffect --> Id mismatch."); else if (m_state != AesEffectState::inner_enum::EsPrepared) { // properties update is allowed!!! if (dbData.properties != m_data.properties) updatedProperties(dbData); else reply.setStr("Not possible to update ChargeEffect --> It is not allowed to make changes EsState doesn't allow it."); } else if (data.name().empty()) reply.setStr("Not possible to update ChargeEffect --> Name must not be empty."); else if (!hasChanges(dbData)) reply.setStr("Not possible to update ChargeEffect --> There are no changes."); else if (!m_mainHandler->db()->update(dbData)) reply.setStr("Not possible to update ChargeEffect --> Database update failed."); else // everything is fine { m_data = dbData; init(); } if (reply.error()) ERROR_LOG(m_logger) << reply.str(); return reply; } /*! * \brief ObjectChargeEffect::updateOnEsActivated * This method is call to update some parameter of charge effect * The effect state is not EsPrepared * \param dbData * \return */ void ObjectChargeEffect::updatedProperties(const Database::AesChargeEffect &dbData) { // update properties // "used": true/false DEBUG_LOG(m_logger)<<" !!! update charge effect when not EsPrepared !!! "; const QString tmpProps = m_data.properties; m_data.properties = dbData.properties; // update properties is allowed!! if (!m_mainHandler->db()->update(m_data)) { m_data.properties = tmpProps; ERROR_LOG(m_logger)<<" Couldn't update charge effect when not EsPrepared!!!"; } } //----------------------------------------------------------------------------- bool ObjectChargeEffect::remove() { if (!m_mainHandler) { ERROR_LOG(m_logger) << "Not possible to remove ChargeEffect --> No MainHandler present."; return false; } if (!m_mainHandler->dds()->dts()->removeChargeEffectByKey(m_data.id)) { ERROR_LOG(m_logger) << "Not possible to remove ChargeEffect --> Could not remove from DDS."; return false; } // TODO Remove trajectory return true; } //----------------------------------------------------------------------------- Database::AesChargeEffect ObjectChargeEffect::functionTopicToDatabase(const ChargeEffectModifyRequest &data) { Database::AesChargeEffect dbData; dbData.id = data.id(); dbData.name = QString::fromStdString(data.name()); dbData.chargeTypeId = data.chargeTypeId(); dbData.igniterTypeId = data.igniterTypeId(); dbData.effectDuration = data.effectDuration(); dbData.effectStart = QDateTime::fromMSecsSinceEpoch(data.effectStart()); dbData.gearTypeId = data.gearTypeId(); dbData.originatorId = data.originatorId(); dbData.originatorTypeId = static_cast(data.originatorTypeId().underlying()); dbData.position.setX(data.position().lon()); dbData.position.setY(data.position().lat()); dbData.position.setZ(data.position().z()); dbData.properties = QString::fromStdString(data.properties()); return dbData; } //----------------------------------------------------------------------------- ChargeEffect ObjectChargeEffect::dataBaseToDataTopic(const Database::AesChargeEffect &data) { ChargeEffect dataTopic; dataTopic.id(data.id); dataTopic.name(data.name.toStdString()); dataTopic.chargeTypeId(data.chargeTypeId); dataTopic.effectDuration(data.effectDuration); dataTopic.effectStart(data.effectStart.toMSecsSinceEpoch()); dataTopic.igniterTypeId(data.igniterTypeId); dataTopic.gearTypeId(data.gearTypeId); dataTopic.originatorId(data.originatorId); dataTopic.originatorTypeId(static_cast(data.originatorTypeId)); dataTopic.position().lon(data.position.x()); dataTopic.position().lat(data.position.y()); dataTopic.position().z(data.position.z()); dataTopic.state(m_state); dataTopic.properties(data.properties.toStdString()); dataTopic.sampleTime(m_mainHandler->dds()->currentPartitionTimeMSec()); return dataTopic; } //----------------------------------------------------------------------------- void ObjectChargeEffect::publish() { if (!m_mainHandler) { ERROR_LOG(m_logger) << QStringLiteral("Not possible to publish ChargeEffect --> Could not remove from DDS."); return; } if (!m_mainHandler->dds()->dts()->publish(dataBaseToDataTopic(m_data))) { ERROR_LOG(m_logger) << QStringLiteral("Not possible to publish ChargeEffect --> DDS publish failed."); return; } if (m_stateChanged) { emit chargeEffectStateChanged(m_data.id, m_state); m_stateChanged = false; } } //----------------------------------------------------------------------------- void ObjectChargeEffect::init() { calculateInitEffectState(); publish(); startStateTimer(); } QDateTime ObjectChargeEffect::getEffectStart() const { return m_data.effectStart; } //----------------------------------------------------------------------------- qint32 ObjectChargeEffect::id() const { return m_data.id; } //----------------------------------------------------------------------------- bool ObjectChargeEffect::isFinished() const { return (m_data.effectStart.toMSecsSinceEpoch() + m_data.effectDuration + s_afterglowMsecs) < QDateTime::currentMSecsSinceEpoch(); } //----------------------------------------------------------------------------- void ObjectChargeEffect::onStateTimerTimeout() { switch (m_state.underlying()) { case AesEffectState::inner_enum::EsPrepared: case AesEffectState::inner_enum::EsActivated: setNextState(); startStateTimer(); publish(); return; case AesEffectState::inner_enum::EsExpired: emit finished(m_data.id); return; case AesEffectState::inner_enum::EsUnknown: case AesEffectState::inner_enum::EsError: case AesEffectState::inner_enum::EsRemoved: case AesEffectState::inner_enum::EsCreated: case AesEffectState::inner_enum::EsPaused: default: return; } } //----------------------------------------------------------------------------- void ObjectChargeEffect::setNextState() { AesEffectState oldState = m_state; m_stateChanged = false; switch (m_state.underlying()) { case AesEffectState::inner_enum::EsPrepared: m_state = AesEffectState::EsActivated; break; case AesEffectState::inner_enum::EsActivated: m_state = AesEffectState::EsExpired; break; case AesEffectState::inner_enum::EsExpired: case AesEffectState::inner_enum::EsUnknown: case AesEffectState::inner_enum::EsError: case AesEffectState::inner_enum::EsRemoved: case AesEffectState::inner_enum::EsCreated: case AesEffectState::inner_enum::EsPaused: default: m_state = AesEffectState::EsUnknown; break; } if (oldState != m_state) m_stateChanged = true; DEBUG_LOG(m_logger) << "Switching from " << oldState << "to " << m_state; } //----------------------------------------------------------------------------- void ObjectChargeEffect::calculateInitEffectState() { const qint64 effectStartMsecs = m_data.effectStart.toMSecsSinceEpoch(); const qint64 durationEndMsecs = effectStartMsecs + m_data.effectDuration; AesEffectState oldState = m_state; m_stateChanged = false; if (QDateTime::currentMSecsSinceEpoch() < effectStartMsecs) m_state = AesEffectState::inner_enum::EsPrepared; else if (QDateTime::currentMSecsSinceEpoch() >= effectStartMsecs && QDateTime::currentMSecsSinceEpoch() < durationEndMsecs) m_state = AesEffectState::inner_enum::EsActivated; else // expired m_state = AesEffectState::inner_enum::EsExpired; if (oldState != m_state) m_stateChanged = true; DEBUG_LOG(m_logger) << "Setting init state: " << m_state; } //----------------------------------------------------------------------------- void ObjectChargeEffect::startStateTimer() { switch (m_state.underlying()) { case AesEffectState::inner_enum::EsPrepared: { qint64 timeToActivatedMsecs = m_data.effectStart.toMSecsSinceEpoch() - QDateTime::currentMSecsSinceEpoch(); DEBUG_LOG(m_logger) << "Time to Avtivated [ms]: " << timeToActivatedMsecs; m_stateTimer->start(timeToActivatedMsecs); return; } case AesEffectState::inner_enum::EsActivated: { qint64 timeToExpiredMsecs = m_data.effectStart.toMSecsSinceEpoch() + m_data.effectDuration - QDateTime::currentMSecsSinceEpoch(); DEBUG_LOG(m_logger) << "Time to Expired [ms]: " << timeToExpiredMsecs; m_stateTimer->start(timeToExpiredMsecs); return; } case AesEffectState::inner_enum::EsExpired: { qint64 timeToFinishMsecs = m_data.effectStart.toMSecsSinceEpoch() + m_data.effectDuration + s_afterglowMsecs - QDateTime::currentMSecsSinceEpoch(); DEBUG_LOG(m_logger) << "Time to finish/deletion [ms]: " << timeToFinishMsecs; m_stateTimer->start(timeToFinishMsecs); return; } case AesEffectState::inner_enum::EsUnknown: case AesEffectState::inner_enum::EsError: case AesEffectState::inner_enum::EsRemoved: case AesEffectState::inner_enum::EsCreated: case AesEffectState::inner_enum::EsPaused: default: return; } } //----------------------------------------------------------------------------- bool ObjectChargeEffect::hasChanges(const Database::AesChargeEffect newData) const { return m_data.id != newData.id || m_data.name != newData.name || m_data.chargeTypeId != newData.chargeTypeId || m_data.effectDuration != newData.effectDuration || m_data.effectStart != newData.effectStart || m_data.igniterTypeId != newData.igniterTypeId || m_data.gearTypeId != newData.gearTypeId || m_data.originatorId != newData.originatorId || m_data.originatorTypeId != newData.originatorTypeId || m_data.position != newData.position; } } // namespace AreaEffectSimulation