diff --git a/src/PlugIn.cpp b/src/PlugIn.cpp index 65da5d9..1ea3023 100644 --- a/src/PlugIn.cpp +++ b/src/PlugIn.cpp @@ -11,6 +11,9 @@ #include "stdafx.h" +#include +#include + #include #include #include @@ -50,9 +53,8 @@ PlugIn::PlugIn() : m_screen(), m_updateQueueLock(), m_updateQueue(), - m_compatible(false), - m_airportsLock(), - m_airports() { + m_forcedToBackendCallsigns(), + m_compatible(false) { GOOGLE_PROTOBUF_VERIFY_VERSION; this->DisplayUserMessage(PLUGIN_NAME, "INFO", (std::string("Loaded ") + PLUGIN_NAME + " " + PLUGIN_VERSION).c_str(), true, true, false, false, false); @@ -114,8 +116,6 @@ void PlugIn::validateBackendData() { __receivedAmanData.clear(); result = curl_easy_perform(curl); - std::lock_guard guard(this->m_airportsLock); - this->m_airports.clear(); this->m_compatible = false; if (CURLE_OK != result) { @@ -142,7 +142,7 @@ void PlugIn::validateBackendData() { auto airportArray = *it; airports.reserve(airportArray.size()); - for (auto i = 0; i < airportArray.size(); ++i) + for (Json::Value::ArrayIndex i = 0; i < airportArray.size(); ++i) airports.push_back(airportArray[i].asString()); } } @@ -160,7 +160,10 @@ void PlugIn::validateBackendData() { return; } - this->m_airports = airports; + std::lock_guard guard(this->m_updateQueueLock); + this->m_updateQueue.clear(); + for (const auto& airport : std::as_const(airports)) + this->m_updateQueue.insert({ airport, {} }); this->m_compatible = true; } @@ -354,15 +357,67 @@ void PlugIn::generateAircraftReportMessage(const EuroScopePlugIn::CRadarTarget& report->set_reporttime(String::splitString(stream.str(), ".")[0]); } + +void PlugIn::OnFunctionCall(int functionId, const char* itemString, POINT pt, RECT area) { + std::ignore = itemString; + std::ignore = pt; + std::ignore = area; + + auto radarTarget = this->RadarTargetSelectASEL(); + if (false == radarTarget.IsValid() || false == radarTarget.GetCorrelatedFlightPlan().IsValid()) + return; + + std::string callsign(radarTarget.GetCallsign()); + + switch (static_cast(functionId)) { + case PlugIn::TagItemFunction::ForceToBackend: + { + std::string destination(radarTarget.GetCorrelatedFlightPlan().GetFlightPlanData().GetDestination()); + std::transform(destination.begin(), destination.end(), destination.begin(), ::toupper); + + std::lock_guard guard(this->m_updateQueueLock); + auto it = this->m_updateQueue.find(destination); + if (this->m_updateQueue.end() != it) { + auto cIt = std::find(this->m_forcedToBackendCallsigns.cbegin(), this->m_forcedToBackendCallsigns.cend(), callsign); + if (this->m_forcedToBackendCallsigns.cend() == cIt) + this->m_forcedToBackendCallsigns.push_back(callsign); + } + + break; + } + default: + break; + } +} + void PlugIn::OnRadarTargetPositionUpdate(EuroScopePlugIn::CRadarTarget radarTarget) { /* do nothing if the reporter is not initialized and ignore invalid targets */ if (false == this->m_compatible || false == Backend::instance().initialized() || false == radarTarget.IsValid()) return; - if (false == radarTarget.GetCorrelatedFlightPlan().GetTrackingControllerIsMe()) - return; std::lock_guard guard(this->m_updateQueueLock); - this->m_updateQueue.push_back(radarTarget.GetCallsign()); + + auto forcedIt = std::find(this->m_forcedToBackendCallsigns.cbegin(), this->m_forcedToBackendCallsigns.cend(), radarTarget.GetCallsign()); + if (false == radarTarget.GetCorrelatedFlightPlan().GetTrackingControllerIsMe() && this->m_forcedToBackendCallsigns.cend() == forcedIt) + return; + + std::string destination(radarTarget.GetCorrelatedFlightPlan().GetFlightPlanData().GetDestination()); +#pragma warning(disable: 4244) + std::transform(destination.begin(), destination.end(), destination.begin(), ::toupper); +#pragma warning(default: 4244) + + auto it = this->m_updateQueue.find(destination); + if (this->m_updateQueue.end() != it) + it->second.push_back(radarTarget.GetCallsign()); +} + +void PlugIn::OnFlightPlanDisconnect(EuroScopePlugIn::CFlightPlan flightPlan) { + std::string callsign(flightPlan.GetCorrelatedRadarTarget().GetCallsign()); + std::lock_guard guard(this->m_updateQueueLock); + + auto it = std::find(this->m_forcedToBackendCallsigns.begin(), this->m_forcedToBackendCallsigns.end(), callsign); + if (this->m_forcedToBackendCallsigns.end() != it) + this->m_forcedToBackendCallsigns.erase(it); } void PlugIn::OnTimer(int counter) { @@ -370,22 +425,28 @@ void PlugIn::OnTimer(int counter) { return; this->m_updateQueueLock.lock(); - aman::AircraftUpdate update; - bool inserted = false; - for (auto target = this->RadarTargetSelectFirst(); true == target.IsValid(); target = this->RadarTargetSelectNext(target)) { - auto it = std::find(this->m_updateQueue.cbegin(), this->m_updateQueue.cend(), target.GetCallsign()); - if (this->m_updateQueue.cend() != it) { - auto report = update.add_reports(); - this->generateAircraftReportMessage(target, report); - inserted = true; + for (auto& airport : this->m_updateQueue) { + aman::AircraftUpdate update; + bool inserted = false; + + for (auto target = this->RadarTargetSelectFirst(); true == target.IsValid(); target = this->RadarTargetSelectNext(target)) { + auto it = std::find(airport.second.begin(), airport.second.end(), target.GetCallsign()); + if (airport.second.end() != it) { + auto report = update.add_reports(); + this->generateAircraftReportMessage(target, report); + inserted = true; + } } + + /* send the report */ + auto sequence = Backend::instance().update(update); + if (true == inserted && nullptr != sequence) + this->DisplayUserMessage(PLUGIN_NAME, "ERROR", "Unable to send a new aircraft report update", true, true, true, true, true); + + airport.second.clear(); } this->m_updateQueue.clear(); this->m_updateQueueLock.unlock(); - - /* send the report */ - if (true == inserted && nullptr != Backend::instance().update(update)) - this->DisplayUserMessage(PLUGIN_NAME, "ERROR", "Unable to send a new aircraft report update", true, true, true, true, true); } diff --git a/src/PlugIn.h b/src/PlugIn.h index c94ab19..d4621ab 100644 --- a/src/PlugIn.h +++ b/src/PlugIn.h @@ -35,6 +35,7 @@ namespace aman { * @brief Defines the different internal and external tag functions */ enum class TagItemFunction { + ForceToBackend = 0, }; private: @@ -45,13 +46,12 @@ namespace aman { aman::Aircraft* generateAircraftMessage(const EuroScopePlugIn::CRadarTarget& target); void generateAircraftReportMessage(const EuroScopePlugIn::CRadarTarget& radarTarget, aman::AircraftReport* report); - Communication m_configuration; - std::shared_ptr m_screen; - std::mutex m_updateQueueLock; - std::list m_updateQueue; - bool m_compatible; - std::mutex m_airportsLock; - std::vector m_airports; + Communication m_configuration; + std::shared_ptr m_screen; + std::mutex m_updateQueueLock; + std::map> m_updateQueue; + std::list m_forcedToBackendCallsigns; + bool m_compatible; public: /** @@ -79,6 +79,14 @@ namespace aman { */ EuroScopePlugIn::CRadarScreen* OnRadarScreenCreated(const char* displayName, bool needsRadarContent, bool geoReferenced, bool canBeSaved, bool canBeCreated) override; + /** + * @brief Called as soon as a function is triggered + * @param[in] functionId The triggered ID + * @param[in] itemString The content of the message + * @param[in] pt The click position + * @param[in] area The clicked area + */ + void OnFunctionCall(int functionId, const char* itemString, POINT pt, RECT area) override; /** * @brief Called every second * @param[in] counter The counter that indicates the seconds @@ -89,5 +97,10 @@ namespace aman { * @param[in] radarTarget The updated radar target */ void OnRadarTargetPositionUpdate(EuroScopePlugIn::CRadarTarget radarTarget) override; + /** + * @brief Called as soon as a flight plan is offline + * @param[in] flightPlan The disconnected flight plan + */ + void OnFlightPlanDisconnect(EuroScopePlugIn::CFlightPlan flightPlan) override; }; }