#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_); class TextEventManager::Impl { public: explicit Impl(TextEventManager* self) : self_ {self}, textEventMap_ {}, textEventMutex_ {} { } ~Impl() {} void HandleMessage(std::shared_ptr message); TextEventManager* self_; std::unordered_map>, types::TextEventHash> textEventMap_; std::shared_mutex textEventMutex_; }; TextEventManager::TextEventManager() : p(std::make_unique(this)) {} TextEventManager::~TextEventManager() = default; size_t TextEventManager::message_count(const types::TextEventKey& key) const { size_t messageCount = 0u; std::shared_lock lock(p->textEventMutex_); auto it = p->textEventMap_.find(key); if (it != p->textEventMap_.cend()) { messageCount = it->second.size(); } return messageCount; } std::vector> TextEventManager::message_list(const types::TextEventKey& key) const { std::vector> messageList {}; std::shared_lock lock(p->textEventMutex_); auto it = p->textEventMap_.find(key); if (it != p->textEventMap_.cend()) { messageList.assign(it->second.begin(), it->second.end()); } return messageList; } 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, skip this message if (segments.empty()) { return; } for (auto& segment : segments) { // If a segment has no header, or if there is no VTEC string, skip this // message. A segmented message corresponding to a text event should have // this information. if (!segment->header_.has_value() || segment->header_->vtecString_.empty()) { return; } } std::unique_lock lock(textEventMutex_); // Find a matching event in the event map auto& vtecString = segments[0]->header_->vtecString_; types::TextEventKey key {vtecString[0].pVtec_}; size_t messageIndex = 0; auto it = textEventMap_.find(key); bool updated = false; if (it == textEventMap_.cend()) { // If there was no matching event, add the message to a new event textEventMap_.emplace(key, std::vector {message}); messageIndex = 0; updated = true; } else if (std::find_if(it->second.cbegin(), it->second.cend(), [=](auto& storedMessage) { return *message->wmo_header().get() == *storedMessage->wmo_header().get(); }) == 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 messageIndex = it->second.size(); it->second.push_back(message); updated = true; }; lock.unlock(); if (updated) { emit self_->AlertUpdated(key, messageIndex); } } TextEventManager& TextEventManager::Instance() { static TextEventManager textEventManager_ {}; return textEventManager_; } } // namespace manager } // namespace qt } // namespace scwx