File indexing completed on 2024-05-05 16:49:21

0001 /*
0002  * SPDX-FileCopyrightText: 2020-2021 Han Young <hanyoung@protonmail.com>
0003  * SPDX-FileCopyrightText: 2020 Devin Lin <espidev@gmail.com>
0004  *
0005  * SPDX-License-Identifier: LGPL-2.0-or-later
0006  */
0007 #include "dailyweatherforecast.h"
0008 #include "kweathercore_p.h"
0009 #include "pendingweatherforecast_p.h"
0010 #include <QJsonArray>
0011 namespace KWeatherCore
0012 {
0013 class DailyWeatherForecast::DailyWeatherForecastPrivate
0014 {
0015 public:
0016     bool isValid = true;
0017 
0018     double maxTemp = std::numeric_limits<double>::lowest();
0019     double minTemp = std::numeric_limits<double>::max();
0020     double precipitation = 0; // mm
0021     double uvIndex = 0; // 0-1
0022     double humidity = 0; // %
0023     double pressure = 0; // hPa
0024     QString weatherIcon = QStringLiteral("weather-none-available");
0025     QString weatherDescription = QStringLiteral("Unknown");
0026     QDate date;
0027 
0028     Sunrise sunrise;
0029     std::vector<HourlyWeatherForecast> hourlyWeatherForecast;
0030 };
0031 DailyWeatherForecast::~DailyWeatherForecast() = default;
0032 DailyWeatherForecast::DailyWeatherForecast(DailyWeatherForecast &&other) =
0033     default;
0034 DailyWeatherForecast &
0035 DailyWeatherForecast::operator=(DailyWeatherForecast &&other) = default;
0036 DailyWeatherForecast::DailyWeatherForecast()
0037     : d(std::make_unique<DailyWeatherForecastPrivate>())
0038 {
0039 }
0040 DailyWeatherForecast::DailyWeatherForecast(const QDate &date)
0041     : d(std::make_unique<DailyWeatherForecastPrivate>())
0042 {
0043     d->date = date;
0044     d->isValid = false;
0045 }
0046 DailyWeatherForecast::DailyWeatherForecast(const DailyWeatherForecast &other)
0047     : d(std::make_unique<DailyWeatherForecastPrivate>())
0048 {
0049     *d = *other.d;
0050 }
0051 
0052 QJsonObject DailyWeatherForecast::toJson()
0053 {
0054     QJsonObject obj;
0055     QJsonArray hourlyArray;
0056     obj[QStringLiteral("maxTemp")] = maxTemp();
0057     obj[QStringLiteral("minTemp")] = minTemp();
0058     obj[QStringLiteral("precipitation")] = precipitation();
0059     obj[QStringLiteral("uvIndex")] = uvIndex();
0060     obj[QStringLiteral("humidity")] = humidity();
0061     obj[QStringLiteral("pressure")] = pressure();
0062     obj[QStringLiteral("weatherIcon")] = weatherIcon();
0063     obj[QStringLiteral("weatherDescription")] = weatherDescription();
0064     obj[QStringLiteral("date")] = date().toString(Qt::ISODate);
0065     for (const auto &h : hourlyWeatherForecast()) {
0066         hourlyArray.append(h.toJson());
0067     }
0068     obj[QStringLiteral("hourly")] = hourlyArray;
0069     obj[QStringLiteral("sunrise")] = sunrise().toJson();
0070     return obj;
0071 }
0072 DailyWeatherForecast DailyWeatherForecast::fromJson(QJsonObject obj)
0073 {
0074     DailyWeatherForecast ret(
0075         QDate::fromString(obj[QStringLiteral("date")].toString(), Qt::ISODate));
0076     ret.setMaxTemp(obj[QStringLiteral("maxTemp")].toDouble());
0077     ret.setMinTemp(obj[QStringLiteral("minTemp")].toDouble());
0078     ret.setPrecipitation(obj[QStringLiteral("precipitation")].toDouble());
0079     ret.setUvIndex(obj[QStringLiteral("uvIndex")].toDouble());
0080     ret.setHumidity(obj[QStringLiteral("humidity")].toDouble());
0081     ret.setPressure(obj[QStringLiteral("pressure")].toDouble());
0082     ret.setWeatherIcon(obj[QStringLiteral("weatherIcon")].toString());
0083     ret.setWeatherDescription(
0084         obj[QStringLiteral("weatherDescription")].toString());
0085     ret.setSunrise(Sunrise::fromJson(obj[QStringLiteral("sunrise")].toObject()));
0086     std::vector<HourlyWeatherForecast> hourlyVec;
0087     auto array = obj[QStringLiteral("hourly")].toArray();
0088     for (int i = 0; i < array.size(); i++) {
0089         hourlyVec.push_back(
0090             HourlyWeatherForecast::fromJson(array.at(i).toObject()));
0091     }
0092     ret.setHourlyWeatherForecast(hourlyVec);
0093     return ret;
0094 }
0095 bool DailyWeatherForecast::isValid() const
0096 {
0097     return d->isValid;
0098 }
0099 void DailyWeatherForecast::setMaxTemp(double maxTemp)
0100 {
0101     d->maxTemp = maxTemp;
0102 }
0103 void DailyWeatherForecast::setMinTemp(double minTemp)
0104 {
0105     d->minTemp = minTemp;
0106 }
0107 void DailyWeatherForecast::setPrecipitation(double precipitation)
0108 {
0109     d->precipitation = precipitation;
0110 }
0111 void DailyWeatherForecast::setUvIndex(double uvIndex)
0112 {
0113     d->uvIndex = uvIndex;
0114 }
0115 void DailyWeatherForecast::setHumidity(double humidity)
0116 {
0117     d->humidity = humidity;
0118 }
0119 void DailyWeatherForecast::setPressure(double pressure)
0120 {
0121     d->pressure = pressure;
0122 }
0123 void DailyWeatherForecast::setWeatherIcon(const QString &icon)
0124 {
0125     d->weatherIcon = icon;
0126 }
0127 void DailyWeatherForecast::setWeatherDescription(const QString &description)
0128 {
0129     d->weatherDescription = std::move(description);
0130 }
0131 void DailyWeatherForecast::setDate(const QDate &date)
0132 {
0133     d->date = date;
0134 }
0135 void DailyWeatherForecast::setDate(const QDateTime &date)
0136 {
0137     d->date = date.date();
0138 }
0139 double DailyWeatherForecast::maxTemp() const
0140 {
0141     return d->maxTemp;
0142 }
0143 double DailyWeatherForecast::minTemp() const
0144 {
0145     return d->minTemp;
0146 }
0147 double DailyWeatherForecast::precipitation() const
0148 {
0149     return d->precipitation;
0150 }
0151 double DailyWeatherForecast::uvIndex() const
0152 {
0153     return d->uvIndex;
0154 }
0155 double DailyWeatherForecast::humidity() const
0156 {
0157     return d->humidity;
0158 }
0159 double DailyWeatherForecast::pressure() const
0160 {
0161     return d->pressure;
0162 }
0163 const QString &DailyWeatherForecast::weatherIcon() const
0164 {
0165     return d->weatherIcon;
0166 }
0167 const QString &DailyWeatherForecast::weatherDescription() const
0168 {
0169     return d->weatherDescription;
0170 }
0171 const QDate &DailyWeatherForecast::date() const
0172 {
0173     return d->date;
0174 }
0175 QDateTime DailyWeatherForecast::dateTime() const
0176 {
0177     return d->date.startOfDay();
0178 }
0179 const Sunrise &DailyWeatherForecast::sunrise() const
0180 {
0181     return d->sunrise;
0182 }
0183 const std::vector<HourlyWeatherForecast> &
0184 DailyWeatherForecast::hourlyWeatherForecast() const
0185 {
0186     return d->hourlyWeatherForecast;
0187 }
0188 void DailyWeatherForecast::setSunrise(Sunrise sunrise)
0189 {
0190     d->sunrise = std::move(sunrise);
0191 }
0192 void DailyWeatherForecast::setHourlyWeatherForecast(
0193     const std::vector<HourlyWeatherForecast> &forecast)
0194 {
0195     d->hourlyWeatherForecast = forecast;
0196 }
0197 void DailyWeatherForecast::setHourlyWeatherForecast(
0198     std::vector<HourlyWeatherForecast> &&forecast)
0199 {
0200     d->hourlyWeatherForecast = std::move(forecast);
0201 }
0202 DailyWeatherForecast &
0203 DailyWeatherForecast::operator+(const DailyWeatherForecast &forecast)
0204 {
0205     if (date().isNull()) {
0206         setDate(forecast.date());
0207         setWeatherDescription(forecast.weatherDescription());
0208         setWeatherIcon(forecast.weatherIcon());
0209         d->isValid = false;
0210     }
0211 
0212     if (*this == forecast) {
0213         setPrecipitation(precipitation() + forecast.precipitation());
0214         setUvIndex(std::max(uvIndex(), forecast.uvIndex()));
0215         setHumidity(std::max(humidity(), forecast.humidity()));
0216         setPressure(std::max(pressure(), forecast.pressure()));
0217         setMaxTemp(std::max(maxTemp(), forecast.maxTemp()));
0218         setMinTemp(std::min(minTemp(), forecast.minTemp()));
0219     }
0220 
0221     return *this;
0222 }
0223 
0224 DailyWeatherForecast &
0225 DailyWeatherForecast::operator+=(const DailyWeatherForecast &forecast)
0226 {
0227     return *this + forecast;
0228 }
0229 
0230 DailyWeatherForecast &
0231 DailyWeatherForecast::operator+=(const HourlyWeatherForecast &forecast)
0232 {
0233     if (isValid()) {
0234         setDate(forecast.date().date());
0235         setWeatherDescription(forecast.weatherDescription());
0236         setWeatherIcon(forecast.weatherIcon());
0237         d->isValid = false;
0238     }
0239     if (date().daysTo(forecast.date().date()) == 0) {
0240         // set description and icon if it is higher ranked
0241         if (rank[forecast.neutralWeatherIcon()] >= rank[weatherIcon()]) {
0242             setWeatherDescription(
0243                 apiDescMap[forecast.symbolCode() + QStringLiteral("_neutral")]
0244                     .desc);
0245             setWeatherIcon(forecast.neutralWeatherIcon());
0246         }
0247         setPrecipitation(precipitation() + forecast.precipitationAmount());
0248         setUvIndex(std::max(uvIndex(), forecast.uvIndex()));
0249         setHumidity(std::max(humidity(), forecast.humidity()));
0250         setPressure(std::max(pressure(), forecast.pressure()));
0251         setMaxTemp(std::max(maxTemp(), forecast.temperature()));
0252         setMinTemp(std::min(minTemp(), forecast.temperature()));
0253     }
0254 
0255     d->hourlyWeatherForecast.push_back(forecast);
0256     return *this;
0257 }
0258 
0259 bool DailyWeatherForecast::operator==(
0260     const DailyWeatherForecast &forecast) const
0261 {
0262     return (date() == forecast.date());
0263 }
0264 
0265 bool DailyWeatherForecast::operator<(const DailyWeatherForecast &forecast) const
0266 {
0267     return date() < forecast.date();
0268 }
0269 DailyWeatherForecast &
0270 DailyWeatherForecast::operator=(const DailyWeatherForecast &other)
0271 {
0272     *d = *other.d;
0273     return *this;
0274 }
0275 }