File indexing completed on 2025-01-12 05:01:50

0001 /*
0002     SPDX-FileCopyrightText: 2007-2009, 2019 Shawn Starr <shawn.starr@rogers.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 /* Ion for Environment Canada XML data */
0008 
0009 #pragma once
0010 
0011 #include "../ion.h"
0012 
0013 #include <Plasma5Support/DataEngineConsumer>
0014 
0015 #include <QDateTime>
0016 #include <QXmlStreamReader>
0017 
0018 class KJob;
0019 namespace KIO
0020 {
0021 class Job;
0022 } // namespace KIO
0023 
0024 class WeatherData
0025 {
0026 public:
0027     WeatherData();
0028 
0029     // WeatherEvent can have more than one, especially in Canada, eh? :)
0030     struct WeatherEvent {
0031         QString url;
0032         int priority;
0033         QString description;
0034         QString timestamp;
0035     };
0036 
0037     // Five day forecast
0038     struct ForecastInfo {
0039         ForecastInfo();
0040 
0041         QString forecastPeriod;
0042         QString forecastSummary;
0043         QString iconName;
0044         QString shortForecast;
0045 
0046         float tempHigh;
0047         float tempLow;
0048         float popPrecent;
0049         QString windForecast;
0050 
0051         QString precipForecast;
0052         QString precipType;
0053         QString precipTotalExpected;
0054         int forecastHumidity;
0055     };
0056 
0057     QString creditUrl;
0058     QString countryName;
0059     QString longTerritoryName;
0060     QString shortTerritoryName;
0061     QString cityName;
0062     QString regionName;
0063     QString stationID;
0064     double stationLatitude;
0065     double stationLongitude;
0066 
0067     // Current observation information.
0068     QString obsTimestamp;
0069     QDateTime observationDateTime;
0070 
0071     QString condition;
0072     float temperature;
0073     float dewpoint;
0074 
0075     // In winter windchill, in summer, humidex
0076     QString humidex;
0077     float windchill;
0078 
0079     float pressure;
0080     QString pressureTendency;
0081 
0082     float visibility;
0083     float humidity;
0084 
0085     float windSpeed;
0086     float windGust;
0087     QString windDirection;
0088     QString windDegrees;
0089 
0090     QList<WeatherData::WeatherEvent *> warnings;
0091 
0092     float normalHigh;
0093     float normalLow;
0094 
0095     QString forecastTimestamp;
0096 
0097     QString UVIndex;
0098     QString UVRating;
0099 
0100     // 5 day Forecast
0101     QList<WeatherData::ForecastInfo *> forecasts;
0102 
0103     // Historical data from previous day.
0104     float prevHigh;
0105     float prevLow;
0106     QString prevPrecipType;
0107     QString prevPrecipTotal;
0108 
0109     // Almanac info
0110     QString sunriseTimestamp;
0111     QString sunsetTimestamp;
0112     QString moonriseTimestamp;
0113     QString moonsetTimestamp;
0114 
0115     // Historical Records
0116     float recordHigh;
0117     float recordLow;
0118     float recordRain;
0119     float recordSnow;
0120 
0121     QString solarDataTimeEngineSourceName;
0122     bool isNight = false;
0123 };
0124 
0125 Q_DECLARE_TYPEINFO(WeatherData::WeatherEvent, Q_RELOCATABLE_TYPE);
0126 Q_DECLARE_TYPEINFO(WeatherData::ForecastInfo, Q_RELOCATABLE_TYPE);
0127 Q_DECLARE_TYPEINFO(WeatherData, Q_RELOCATABLE_TYPE);
0128 
0129 /**
0130  * https://weather.gc.ca/mainmenu/disclaimer_e.html
0131  */
0132 class Q_DECL_EXPORT EnvCanadaIon : public IonInterface, public Plasma5Support::DataEngineConsumer
0133 {
0134     Q_OBJECT
0135 
0136 public:
0137     EnvCanadaIon(QObject *parent);
0138     ~EnvCanadaIon() override;
0139 
0140 public: // IonInterface API
0141     bool updateIonSource(const QString &source) override;
0142 
0143 public Q_SLOTS:
0144     // for solar data pushes from the time engine
0145     void dataUpdated(const QString &sourceName, const Plasma5Support::DataEngine::Data &data);
0146 
0147 protected: // IonInterface API
0148     void reset() override;
0149 
0150 private Q_SLOTS:
0151     void setup_slotDataArrived(KIO::Job *, const QByteArray &);
0152     void setup_slotJobFinished(KJob *);
0153 
0154     void slotDataArrived(KIO::Job *, const QByteArray &);
0155     void slotJobFinished(KJob *);
0156 
0157 private:
0158     void updateWeather(const QString &source);
0159 
0160     /* Environment Canada Methods - Internal for Ion */
0161     void deleteForecasts();
0162 
0163     QMap<QString, ConditionIcons> setupConditionIconMappings() const;
0164     QMap<QString, ConditionIcons> setupForecastIconMappings() const;
0165 
0166     QMap<QString, ConditionIcons> const &conditionIcons() const;
0167     QMap<QString, ConditionIcons> const &forecastIcons() const;
0168 
0169     // Load and Parse the place XML listing
0170     void getXMLSetup();
0171     bool readXMLSetup();
0172 
0173     // Load and parse the specific place(s)
0174     void getXMLData(const QString &source);
0175     bool readXMLData(const QString &source, QXmlStreamReader &xml);
0176 
0177     // Check if place specified is valid or not
0178     QStringList validate(const QString &source) const;
0179 
0180     // Catchall for unknown XML tags
0181     void parseUnknownElement(QXmlStreamReader &xml) const;
0182 
0183     // Parse weather XML data
0184     void parseWeatherSite(WeatherData &data, QXmlStreamReader &xml);
0185     void parseDateTime(WeatherData &data, QXmlStreamReader &xml, WeatherData::WeatherEvent *event = nullptr);
0186     void parseLocations(WeatherData &data, QXmlStreamReader &xml);
0187     void parseConditions(WeatherData &data, QXmlStreamReader &xml);
0188     void parseWarnings(WeatherData &data, QXmlStreamReader &xml);
0189     void parseWindInfo(WeatherData &data, QXmlStreamReader &xml);
0190     void parseWeatherForecast(WeatherData &data, QXmlStreamReader &xml);
0191     void parseRegionalNormals(WeatherData &data, QXmlStreamReader &xml);
0192     void parseForecast(WeatherData &data, QXmlStreamReader &xml, WeatherData::ForecastInfo *forecast);
0193     void parseShortForecast(WeatherData::ForecastInfo *forecast, QXmlStreamReader &xml);
0194     void parseForecastTemperatures(WeatherData::ForecastInfo *forecast, QXmlStreamReader &xml);
0195     void parseWindForecast(WeatherData::ForecastInfo *forecast, QXmlStreamReader &xml);
0196     void parsePrecipitationForecast(WeatherData::ForecastInfo *forecast, QXmlStreamReader &xml);
0197     void parsePrecipTotals(WeatherData::ForecastInfo *forecast, QXmlStreamReader &xml);
0198     void parseUVIndex(WeatherData &data, QXmlStreamReader &xml);
0199     void parseYesterdayWeather(WeatherData &data, QXmlStreamReader &xml);
0200     void parseAstronomicals(WeatherData &data, QXmlStreamReader &xml);
0201     void parseWeatherRecords(WeatherData &data, QXmlStreamReader &xml);
0202 
0203     void parseFloat(float &value, QXmlStreamReader &xml);
0204 
0205 private:
0206     struct XMLMapInfo {
0207         QString cityName;
0208         QString territoryName;
0209         QString cityCode;
0210     };
0211 
0212     // Key dicts
0213     QHash<QString, EnvCanadaIon::XMLMapInfo> m_places;
0214 
0215     // Weather information
0216     QHash<QString, WeatherData> m_weatherData;
0217 
0218     // Store KIO jobs
0219     QHash<KJob *, QXmlStreamReader *> m_jobXml;
0220     QHash<KJob *, QString> m_jobList;
0221     QStringList m_sourcesToReset;
0222     QXmlStreamReader m_xmlSetup;
0223 
0224     bool emitWhenSetup;
0225 };