summaryrefslogtreecommitdiffstats
path: root/weather/src/networkforecastsource.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'weather/src/networkforecastsource.cpp')
-rw-r--r--weather/src/networkforecastsource.cpp234
1 files changed, 234 insertions, 0 deletions
diff --git a/weather/src/networkforecastsource.cpp b/weather/src/networkforecastsource.cpp
new file mode 100644
index 0000000..98456c8
--- /dev/null
+++ b/weather/src/networkforecastsource.cpp
@@ -0,0 +1,234 @@
+#include "networkforecastsource.h"
+#include "yahooweatherresponse.h"
+#include "xoapweatherresponse.h"
+
+#include <QUrl>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QDebug>
+#include <QBuffer>
+#include <QDomDocument>
+#include <QDateTime>
+#include <QTime>
+
+#define CITY_NAME_HOST "xoap.weather.com"
+#define CITY_NAME_TO_LOCATION_ID_URL "http://" CITY_NAME_HOST "/search/search"
+#define CITY_NAME_TO_LOCATION_ID_PARAM "where"
+
+#define FORECAST_HOST "weather.yahooapis.com"
+#define FORECAST_URL "http://" FORECAST_HOST "/forecastrss"
+#define FORECAST_LOCATION_PARAM "p"
+#define FORECAST_UNIT_PARAM "u"
+#define FORECAST_CELSIUS_UNIT "c"
+
+#define YWEATHER_NS_URI "http://xml.weather.yahoo.com/ns/rss/1.0"
+#define YWEATHER_NS_NAME "yweather"
+
+static int getId()
+{
+ static int id(0);
+ return ++id;
+}
+
+// LocationRequestManager
+
+LocationRequestManager::LocationRequestManager(QObject *parent)
+ : QObject(parent)
+{
+ connect(&m_network, SIGNAL(finished(QNetworkReply*)),
+ this, SLOT(receiveResponse(QNetworkReply*)));
+}
+
+int LocationRequestManager::addRequest(const QString &query)
+{
+ if (m_requests.contains(query))
+ return m_requests[query];
+ QUrl url(CITY_NAME_TO_LOCATION_ID_URL);
+ url.addQueryItem(CITY_NAME_TO_LOCATION_ID_PARAM, query);
+ m_network.get(QNetworkRequest(url));
+
+ int result = getId();
+ m_requests[query] = result;
+ return result;
+}
+
+QString LocationRequestManager::readResponse(const QString &query, QNetworkReply *reply)
+{
+
+ if (reply->error() != QNetworkReply::NoError) {
+ qWarning() << "location id query error: " << query;
+ return QString();
+ }
+
+ QDomDocument doc;
+
+ if (!doc.setContent(reply)) {
+ qWarning() << "location id parse error: " << query;
+ return QString();
+ }
+ XoapWeatherResponse reader;
+ reader.read(doc.documentElement());
+
+ if (reader.items().count() == 0) {
+ qWarning() << "empty location id response: " << query;
+ return QString();
+ }
+
+ return reader.items()[0].id();
+
+}
+
+void LocationRequestManager::receiveResponse(QNetworkReply *reply)
+{
+ const QString query = reply->request().url().queryItemValue(CITY_NAME_TO_LOCATION_ID_PARAM);
+
+ if (query.isNull() || !m_requests.contains(query)) {
+ qWarning() << "Unexpected location id query response. (query = " << query << ")";
+ return;
+ }
+ const int reqId = m_requests[query];
+ m_requests.remove(query);
+
+ QString locId = readResponse(query, reply);
+
+ if (locId.isEmpty())
+ emit locationIdQueryError(reqId, query);
+ else
+ emit newLocationId(reqId, locId);
+}
+
+// ForecastRequestmanager
+
+ForecastRequestmanager::ForecastRequestmanager(QObject *parent)
+ : QObject(parent)
+{
+ connect(&m_network, SIGNAL(finished(QNetworkReply*)),
+ this, SLOT(receiveResponse(QNetworkReply*)));
+}
+
+int ForecastRequestmanager::addRequest(const QString &locId)
+{
+ if (m_requests.contains(locId))
+ return m_requests[locId][0];
+ int result = getId();
+ doAddRequest(result, locId);
+ return result;
+}
+
+void ForecastRequestmanager::addRequest(int reqId, const QString &locId)
+{
+ if (m_requests.contains(locId)) {
+ m_requests[locId].append(reqId);
+ return;
+ }
+ doAddRequest(reqId, locId);
+}
+
+void ForecastRequestmanager::doAddRequest(int reqId, const QString &locId)
+{
+ QUrl url(FORECAST_URL);
+ url.addQueryItem(FORECAST_LOCATION_PARAM, locId);
+ url.addQueryItem(FORECAST_UNIT_PARAM, FORECAST_CELSIUS_UNIT);
+ m_network.get(QNetworkRequest (url));
+ QList<int> list;
+ list.append(reqId);
+ m_requests[locId] = list;
+}
+
+YahooWeatherResponse *ForecastRequestmanager::readResponse(const QString &locId,
+ QNetworkReply *reply)
+{
+ if (reply->error() != QNetworkReply::NoError) {
+ qWarning() << "forecast query error: " << locId;
+ return 0;
+ }
+
+ QDomDocument doc;
+
+ if (!doc.setContent(reply)) {
+ qWarning() << "forecast parse error: " << locId;
+ return 0;
+ }
+
+ bool ok = doc.documentElement().childNodes().count() > 0
+ && doc.documentElement().childNodes().at(0).isElement();
+ if (ok) {
+ QDomElement element = doc.documentElement().childNodes().at(0).toElement();
+ ok = element.elementsByTagName("lastBuildDate").count() == 1;
+ }
+
+ if (!ok) {
+ qWarning() << "invalid forecast response: " << locId;
+ return 0;
+ }
+
+ return new YahooWeatherResponse(locId, doc.documentElement());
+}
+
+void ForecastRequestmanager::receiveResponse(QNetworkReply *reply)
+{
+ const QString locId = reply->request().url().queryItemValue(FORECAST_LOCATION_PARAM);
+
+ if (locId.isNull() || !m_requests.contains(locId)) {
+ qWarning() << "Unexpected forecast query response. (locId = " << locId << ")";
+ return;
+ }
+
+ const QList<int> list = m_requests[locId];
+ m_requests.remove(locId);
+
+ YahooWeatherResponse *result = readResponse(locId, reply);
+ if (result)
+ foreach (int reqId, list) {
+ emit newForecastResponse(reqId, result);
+ }
+ else
+ foreach (int reqId, list)
+ emit forecastResponseError(reqId);
+}
+
+// NetworkForecastSource
+
+NetworkForecastSource::NetworkForecastSource(QObject *parent)
+ : ForecastSource(parent)
+{
+ connect(&m_locationManager, SIGNAL(newLocationId(int, QString)),
+ &m_forecastManager, SLOT(addRequest(int, QString)));
+
+ connect(&m_locationManager, SIGNAL(locationIdQueryError(int, QString)),
+ &m_forecastManager, SLOT(addRequest(int, QString)));
+
+ connect(&m_forecastManager, SIGNAL(forecastResponseError(int)),
+ this, SLOT(forecastResponseError(int)));
+
+ connect(&m_forecastManager, SIGNAL(newForecastResponse(int, YahooWeatherResponse*)),
+ this, SLOT(newForecastResponse(int, YahooWeatherResponse*)));
+}
+
+NetworkForecastSource::~NetworkForecastSource()
+{
+}
+
+int NetworkForecastSource::getForecast(const QString &key, bool locationId)
+{
+ if (locationId)
+ return m_forecastManager.addRequest(key);
+ else
+ return m_locationManager.addRequest(key);
+}
+
+void NetworkForecastSource::newForecastResponse(int reqId, YahooWeatherResponse *forecast)
+{
+ forecast->print();
+ emit forecastReceived(reqId, ForecastData(forecast));
+}
+
+void NetworkForecastSource::forecastResponseError(int reqId)
+{
+ emit forecastReceived(reqId, ForecastData(0));
+}
+
+
+
+
+