#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::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::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); 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) { case AesEffectState::EsPrepared: case AesEffectState::EsActivated: setNextState(); startStateTimer(); publish(); return; case AesEffectState::EsExpired: emit finished(m_data.id); return; case AesEffectState::EsUnknown: case AesEffectState::EsError: case AesEffectState::EsRemoved: case AesEffectState::EsCreated: case AesEffectState::EsPaused: default: return; } } //----------------------------------------------------------------------------- void ObjectChargeEffect::setNextState() { AesEffectState oldState = m_state; m_stateChanged = false; switch (m_state) { case AesEffectState::EsPrepared: m_state = AesEffectState::EsActivated; break; case AesEffectState::EsActivated: m_state = AesEffectState::EsExpired; break; case AesEffectState::EsExpired: case AesEffectState::EsUnknown: case AesEffectState::EsError: case AesEffectState::EsRemoved: case AesEffectState::EsCreated: case AesEffectState::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::EsPrepared; else if (QDateTime::currentMSecsSinceEpoch() >= effectStartMsecs && QDateTime::currentMSecsSinceEpoch() < durationEndMsecs) m_state = AesEffectState::EsActivated; else // expired m_state = AesEffectState::EsExpired; if (oldState != m_state) m_stateChanged = true; DEBUG_LOG(m_logger) << "Setting init state: " << m_state; } //----------------------------------------------------------------------------- void ObjectChargeEffect::startStateTimer() { switch (m_state) { case AesEffectState::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::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::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::EsUnknown: case AesEffectState::EsError: case AesEffectState::EsRemoved: case AesEffectState::EsCreated: case AesEffectState::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