From cc82c5b10233d6ce3512dc4a59dea4270aef8e01 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Wed, 12 Oct 2022 00:13:41 -0500 Subject: [PATCH] Adding initial text event manager --- scwx-qt/scwx-qt.cmake | 6 +- .../scwx/qt/manager/text_event_manager.cpp | 154 ++++++++++++++++++ .../scwx/qt/manager/text_event_manager.hpp | 34 ++++ 3 files changed, 192 insertions(+), 2 deletions(-) create mode 100644 scwx-qt/source/scwx/qt/manager/text_event_manager.cpp create mode 100644 scwx-qt/source/scwx/qt/manager/text_event_manager.hpp diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index 58583a06..bec14b1f 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -58,11 +58,13 @@ set(SRC_GL_DRAW source/scwx/qt/gl/draw/draw_item.cpp set(HDR_MANAGER source/scwx/qt/manager/radar_product_manager.hpp source/scwx/qt/manager/radar_product_manager_notifier.hpp source/scwx/qt/manager/resource_manager.hpp - source/scwx/qt/manager/settings_manager.hpp) + source/scwx/qt/manager/settings_manager.hpp + source/scwx/qt/manager/text_event_manager.hpp) set(SRC_MANAGER source/scwx/qt/manager/radar_product_manager.cpp source/scwx/qt/manager/radar_product_manager_notifier.cpp source/scwx/qt/manager/resource_manager.cpp - source/scwx/qt/manager/settings_manager.cpp) + source/scwx/qt/manager/settings_manager.cpp + source/scwx/qt/manager/text_event_manager.cpp) set(HDR_MAP source/scwx/qt/map/color_table_layer.hpp source/scwx/qt/map/draw_layer.hpp source/scwx/qt/map/generic_layer.hpp diff --git a/scwx-qt/source/scwx/qt/manager/text_event_manager.cpp b/scwx-qt/source/scwx/qt/manager/text_event_manager.cpp new file mode 100644 index 00000000..8311c233 --- /dev/null +++ b/scwx-qt/source/scwx/qt/manager/text_event_manager.cpp @@ -0,0 +1,154 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include + +namespace scwx +{ +namespace qt +{ +namespace manager +{ + +static const std::string logPrefix_ = "scwx::qt::manager::text_event_manager"; +static const auto logger_ = scwx::util::Logger::Create(logPrefix_); + +struct TextEventKey +{ + TextEventKey(const awips::PVtec& pvtec) : + officeId_ {pvtec.office_id()}, + phenomenon_ {pvtec.phenomenon()}, + significance_ {pvtec.significance()}, + etn_ {pvtec.event_tracking_number()} + { + } + + bool operator==(const TextEventKey& o) const; + + std::string officeId_; + awips::Phenomenon phenomenon_; + awips::Significance significance_; + int16_t etn_; +}; + +template +struct TextEventHash; + +template<> +struct TextEventHash +{ + size_t operator()(const TextEventKey& x) const + { + size_t seed = 0; + boost::hash_combine(seed, x.officeId_); + boost::hash_combine(seed, x.phenomenon_); + boost::hash_combine(seed, x.significance_); + boost::hash_combine(seed, x.etn_); + return seed; + } +}; + +class TextEventManager::Impl +{ +public: + explicit Impl() : textEventMap_ {}, textEventMutex_ {} {} + + ~Impl() {} + + void HandleMessage(std::shared_ptr message); + + std::unordered_map>, + TextEventHash> + textEventMap_; + std::shared_mutex textEventMutex_; +}; + +TextEventManager::TextEventManager() : p(std::make_unique()) {} +TextEventManager::~TextEventManager() = default; + +void TextEventManager::LoadFile(const std::string& filename) +{ + logger_->debug("LoadFile: {}", filename); + + util::async( + [=]() + { + awips::TextProductFile file; + + // Load file + bool fileLoaded = file.LoadFile(filename); + if (!fileLoaded) + { + return; + } + + // Process messages + auto messages = file.messages(); + for (auto& message : messages) + { + p->HandleMessage(message); + } + }); +} + +void TextEventManager::Impl::HandleMessage( + std::shared_ptr message) +{ + auto segments = message->segments(); + + // If there are no segments, if the first segment has no header, or if there + // is no VTEC string, skip this message + if (segments.empty() || !segments[0]->header_.has_value() || + segments[0]->header_->vtecString_.empty()) + { + return; + } + + std::unique_lock lock(textEventMutex_); + + // Find a matching event in the event map + auto& vtecString = segments[0]->header_->vtecString_; + TextEventKey key {vtecString[0].pVtec_}; + auto it = textEventMap_.find(key); + + if (it == textEventMap_.cend()) + { + // If there was no matching event, add the message to a new event + textEventMap_.emplace(key, std::list {message}); + } + else if (std::find_if(it->second.cbegin(), + it->second.cend(), + [=](auto& storedMessage) { + return message->wmo_header() == + storedMessage->wmo_header(); + }) == it->second.cend()) + { + // If there was a matching event, and this message has not been stored + // (WMO header equivalence check), add the updated message to the existing + // event + it->second.push_back(message); + }; +} + +TextEventManager& TextEventManager::Instance() +{ + static TextEventManager textEventManager_ {}; + return textEventManager_; +} + +bool TextEventKey::operator==(const TextEventKey& o) const +{ + return (officeId_ == o.officeId_ && phenomenon_ == o.phenomenon_ && + significance_ == o.significance_ && etn_ == o.etn_); +} + +} // namespace manager +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/manager/text_event_manager.hpp b/scwx-qt/source/scwx/qt/manager/text_event_manager.hpp new file mode 100644 index 00000000..91e52f68 --- /dev/null +++ b/scwx-qt/source/scwx/qt/manager/text_event_manager.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include +#include + +#include + +namespace scwx +{ +namespace qt +{ +namespace manager +{ + +class TextEventManager : public QObject +{ + Q_OBJECT + +public: + explicit TextEventManager(); + ~TextEventManager(); + + void LoadFile(const std::string& filename); + + static TextEventManager& Instance(); + +private: + class Impl; + std::unique_ptr p; +}; + +} // namespace manager +} // namespace qt +} // namespace scwx