#include #include #include #include #include #include #include #include namespace scwx { namespace qt { namespace settings { static const std::string logPrefix_ = "scwx::qt::settings::map_settings"; static const auto logger_ = scwx::util::Logger::Create(logPrefix_); static constexpr std::size_t kCount_ = 4u; static const std::string kDefaultRadarSite_ = "KLSX"; static const std::string kMapStyleName_ {"map_style"}; static const std::string kRadarSiteName_ {"radar_site"}; static const std::string kRadarProductGroupName_ {"radar_product_group"}; static const std::string kRadarProductName_ {"radar_product"}; static const std::string kSmoothingEnabledName_ {"smoothing_enabled"}; static const std::string kDefaultMapStyle_ {"?"}; static const std::string kDefaultRadarProductGroupString_ = "L3"; static const std::array kDefaultRadarProduct_ { "N0B", "N0G", "N0C", "N0X"}; static constexpr bool kDefaultSmoothingEnabled_ {false}; class MapSettings::Impl { public: struct MapData { SettingsVariable mapStyle_ {kMapStyleName_}; SettingsVariable radarSite_ {kRadarSiteName_}; SettingsVariable radarProductGroup_ { kRadarProductGroupName_}; SettingsVariable radarProduct_ {kRadarProductName_}; SettingsVariable smoothingEnabled_ {kSmoothingEnabledName_}; }; explicit Impl() { for (std::size_t i = 0; i < kCount_; i++) { map_.at(i).mapStyle_.SetDefault(kDefaultMapStyle_); map_.at(i).radarSite_.SetDefault(kDefaultRadarSite_); map_.at(i).radarProductGroup_.SetDefault( kDefaultRadarProductGroupString_); map_.at(i).radarProduct_.SetDefault(kDefaultRadarProduct_.at(i)); map_.at(i).smoothingEnabled_.SetDefault(kDefaultSmoothingEnabled_); map_.at(i).radarSite_.SetValidator( [](const std::string& value) { // Radar site must exist return config::RadarSite::Get(value) != nullptr; }); map_.at(i).radarProductGroup_.SetValidator( [](const std::string& value) { // Radar product group must be valid common::RadarProductGroup radarProductGroup = common::GetRadarProductGroup(value); return radarProductGroup != common::RadarProductGroup::Unknown; }); map_.at(i).radarProduct_.SetValidator( [this, i](const std::string& value) { common::RadarProductGroup radarProductGroup = common::GetRadarProductGroup( map_.at(i).radarProductGroup_.GetValue()); if (radarProductGroup == common::RadarProductGroup::Level2) { // Radar product must be valid return common::GetLevel2Product(value) != common::Level2Product::Unknown; } else { // TODO: Validate level 3 product return true; } }); variables_.insert(variables_.cend(), {&map_.at(i).mapStyle_, &map_.at(i).radarSite_, &map_.at(i).radarProductGroup_, &map_.at(i).radarProduct_, &map_.at(i).smoothingEnabled_}); } } ~Impl() {} void SetDefaults(std::size_t i) { map_.at(i).mapStyle_.SetValueToDefault(); map_.at(i).radarSite_.SetValueToDefault(); map_.at(i).radarProductGroup_.SetValueToDefault(); map_.at(i).radarProduct_.SetValueToDefault(); map_.at(i).smoothingEnabled_.SetValueToDefault(); } friend void tag_invoke(boost::json::value_from_tag, boost::json::value& jv, const MapData& data) { jv = {{kMapStyleName_, data.mapStyle_.GetValue()}, {kRadarSiteName_, data.radarSite_.GetValue()}, {kRadarProductGroupName_, data.radarProductGroup_.GetValue()}, {kRadarProductName_, data.radarProduct_.GetValue()}, {kSmoothingEnabledName_, data.smoothingEnabled_.GetValue()}}; } friend bool operator==(const MapData& lhs, const MapData& rhs) { return (lhs.mapStyle_ == rhs.mapStyle_ && // lhs.radarSite_ == rhs.radarSite_ && lhs.radarProductGroup_ == rhs.radarProductGroup_ && lhs.radarProduct_ == rhs.radarProduct_ && lhs.smoothingEnabled_ == rhs.smoothingEnabled_); } std::array map_ {}; std::vector variables_ {}; }; MapSettings::MapSettings() : SettingsCategory("maps"), p(std::make_unique()) { RegisterVariables(p->variables_); SetDefaults(); p->variables_.clear(); } MapSettings::~MapSettings() = default; MapSettings::MapSettings(MapSettings&&) noexcept = default; MapSettings& MapSettings::operator=(MapSettings&&) noexcept = default; std::size_t MapSettings::count() const { return kCount_; } SettingsVariable& MapSettings::map_style(std::size_t i) { return p->map_.at(i).mapStyle_; } SettingsVariable& MapSettings::radar_site(std::size_t i) { return p->map_.at(i).radarSite_; } SettingsVariable& MapSettings::radar_product_group(std::size_t i) { return p->map_.at(i).radarProductGroup_; } SettingsVariable& MapSettings::radar_product(std::size_t i) { return p->map_.at(i).radarProduct_; } SettingsVariable& MapSettings::smoothing_enabled(std::size_t i) { return p->map_.at(i).smoothingEnabled_; } bool MapSettings::Shutdown() { bool dataChanged = false; // Commit settings that are managed separate from the settings dialog for (std::size_t i = 0; i < kCount_; ++i) { Impl::MapData& mapRecordSettings = p->map_.at(i); dataChanged |= mapRecordSettings.mapStyle_.Commit(); dataChanged |= mapRecordSettings.smoothingEnabled_.Commit(); } return dataChanged; } bool MapSettings::ReadJson(const boost::json::object& json) { bool validated = true; const boost::json::value* value = json.if_contains(name()); if (value != nullptr && value->is_array()) { const boost::json::array& mapArray = value->as_array(); for (std::size_t i = 0; i < kCount_; ++i) { if (i < mapArray.size() && mapArray.at(i).is_object()) { const boost::json::object& mapRecord = mapArray.at(i).as_object(); Impl::MapData& mapRecordSettings = p->map_.at(i); // Load JSON Elements validated &= mapRecordSettings.mapStyle_.ReadValue(mapRecord); validated &= mapRecordSettings.radarSite_.ReadValue(mapRecord); validated &= mapRecordSettings.radarProductGroup_.ReadValue(mapRecord); validated &= mapRecordSettings.smoothingEnabled_.ReadValue(mapRecord); bool productValidated = mapRecordSettings.radarProduct_.ReadValue(mapRecord); if (!productValidated) { // Product was set to default, reset group to default to match mapRecordSettings.radarProductGroup_.SetValueToDefault(); validated = false; } } else { logger_->warn( "Too few array entries, resetting record {} to defaults", i + 1); validated = false; p->SetDefaults(i); } } } else { if (value == nullptr) { logger_->warn("Key is not present, resetting to defaults"); } else if (!value->is_array()) { logger_->warn("Invalid json, resetting to defaults"); } SetDefaults(); validated = false; } return validated; } void MapSettings::WriteJson(boost::json::object& json) const { boost::json::value object = boost::json::value_from(p->map_); json.insert_or_assign(name(), object); } MapSettings& MapSettings::Instance() { static MapSettings mapSettings_; return mapSettings_; } bool operator==(const MapSettings& lhs, const MapSettings& rhs) { return (lhs.p->map_ == rhs.p->map_); } } // namespace settings } // namespace qt } // namespace scwx