summaryrefslogtreecommitdiffstats
path: root/kweather/weatherlib.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kweather/weatherlib.cpp')
-rw-r--r--kweather/weatherlib.cpp355
1 files changed, 355 insertions, 0 deletions
diff --git a/kweather/weatherlib.cpp b/kweather/weatherlib.cpp
new file mode 100644
index 0000000..cb79a05
--- /dev/null
+++ b/kweather/weatherlib.cpp
@@ -0,0 +1,355 @@
+/***************************************************************************
+ weatherlib.cpp - description
+ -------------------
+begin : Wed Jul 5 2000
+copyright : (C) 2000 by Ian Reinhart Geiser
+email : geiseri@msoe.edu
+***************************************************************************/
+
+/***************************************************************************
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+***************************************************************************/
+
+#include "config.h"
+#include <qfile.h>
+#include <qdatetime.h>
+#include <qtextstream.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <math.h>
+#include <krfcdate.h>
+#include <kio/job.h>
+#include <kurl.h>
+#include <knotifyclient.h>
+#include <ktempfile.h>
+#include <unistd.h>
+#include <kapplication.h>
+#include <kpassivepopup.h>
+
+#include "metar_parser.h"
+#include "stationdatabase.h"
+#include "sun.h"
+#include "weatherlib.h"
+
+#include "weatherlib.moc"
+
+
+class WeatherLib::Data
+{
+ public:
+ Data();
+ ~Data(){ if ( target ) delete target; }
+
+ void clear();
+
+ /** The current weather state outside */
+ struct WeatherInfo wi;
+ QDateTime age;
+ KTempFile *target;
+ bool downloading;
+ bool updated;
+ KIO::Job *job;
+};
+
+WeatherLib::Data::Data()
+ : target( 0 ), job( 0 )
+{
+ clear();
+}
+
+void WeatherLib::Data::clear()
+{
+ age = QDateTime::currentDateTime();
+ downloading = false;
+ updated = false;
+ job = 0;
+
+ if ( target )
+ {
+ delete target;
+ target = 0;
+ }
+}
+
+WeatherLib::WeatherLib(StationDatabase *stationDB, QObject *parent, const char *name)
+ : QObject (parent, name)
+{
+ KGlobal::locale()->insertCatalogue("kweather");
+
+ m_StationDb = stationDB;
+
+ data.setAutoDelete( true );
+}
+
+WeatherLib::~WeatherLib()
+{
+}
+
+void WeatherLib::slotCopyDone(KIO::Job* job)
+{
+ kdDebug(12006) << "Copy done..." << endl;
+ if( job->error())
+ {
+ kdDebug(12006) << "Error code: " << job->error() << endl;
+ //job->showErrorDialog(0L);
+ if ((job->error() == KIO::ERR_COULD_NOT_CONNECT || job->error() == KIO::ERR_UNKNOWN_HOST)
+ && !hostDown)
+ {
+ hostDown= true;
+ // no need to show a passive popup here, as below all stations will show "dunno" icon
+ }
+ }
+ // Find the job
+ QDictIterator<Data> it( data );
+ Data *d = 0L;
+ for( ; it.current(); ++it )
+ {
+ kdDebug(12006) << "Searching for job..." << endl;
+ if(it.current()->job == job)
+ {
+ d = it.current();
+ d->downloading = false;
+ if( !job->error() )
+ {
+ kdDebug( 12006) << "Reading: " << d->target->name() << endl;
+ QFile file( d->target->name() );
+ file.open( IO_ReadOnly );
+ QTextStream *t = new QTextStream( &file );
+ //QTextStream *t = d->target->textStream();
+ if( t )
+ {
+ QString s = QString::null;
+ while ( !t->eof() )
+ {
+ s += " " + t->readLine();
+ }
+
+ if ( !s.isEmpty() )
+ {
+ kdDebug( 12006 ) << "Parse: " << s << endl;
+ MetarParser parser(m_StationDb, KGlobal::locale()->measureSystem());
+ d->wi = parser.processData(d->wi.reportLocation, s);
+ d->age = QDateTime::currentDateTime().addSecs(1800);
+ emit fileUpdate(d->wi.reportLocation);
+ d->updated = true;
+ }
+ else
+ {
+ // File error
+ kdDebug( 12006 ) << "File empty error..." << endl;
+ KPassivePopup::message( i18n("KWeather Error!"),
+ i18n("The temp file %1 was empty.").arg(d->target->name()), 0L,"error" );
+ d->updated = false;
+ }
+ }
+ else
+ {
+ // File error
+ kdDebug( 12006 ) << "File read error..." << endl;
+ KPassivePopup::message( i18n("KWeather Error!"),
+ i18n("Could not read the temp file %1.").arg(d->target->name()), 0L,"error" );
+ d->updated = false;
+ }
+ delete d->target;
+ d->target = 0L;
+ d->job = 0L;
+
+ }
+ else if( job->error() == KIO::ERR_DOES_NOT_EXIST)
+ {
+ data.remove(d->wi.reportLocation);
+ kdDebug( 12006 ) << "Bad station data so i am going to remove it" << endl;
+ KPassivePopup::message( i18n("KWeather Error!"),
+ i18n("The requested station does not exist."), 0L,"error" );
+ }
+ else if(job->error() == KIO::ERR_COULD_NOT_CONNECT ||
+ job->error() == KIO::ERR_UNKNOWN_HOST)
+ {
+ kdDebug( 12006 ) << "Offline now..." << endl;
+ d->clear();
+ d->wi.theWeather = "dunno";
+ d->wi.qsCurrentList.append(i18n("The network is currently offline..."));
+ d->wi.qsCurrentList.append(i18n("Please update later."));
+ emit fileUpdate(d->wi.reportLocation);
+ }
+ else
+ {
+ kdDebug( 12006 ) << "Duh?..." << endl;
+ }
+
+ }
+ }
+}
+
+void WeatherLib::getData(Data *d, bool force /* try even if host was down last time*/)
+{
+ if(!d->downloading && (force || !hostDown) )
+ {
+ d->downloading = true;
+ d->updated = false;
+ QString u = "http://weather.noaa.gov/pub/data/observations/metar/stations/";
+ u += d->wi.reportLocation.upper().stripWhiteSpace();
+ u += ".TXT";
+
+ d->target = new KTempFile(QString::null, "-weather");
+ d->target->setAutoDelete(true);
+ d->target->file();
+
+ KURL url(u);
+ KURL local(d->target->name());
+
+ d->job = KIO::file_copy( url, local, -1, true, false, false);
+ d->job->addMetaData("cache", "reload"); // Make sure to get fresh info
+ connect( d->job, SIGNAL( result( KIO::Job *)),
+ SLOT(slotCopyDone(KIO::Job *)));
+ kdDebug( 12006 ) << "Copying " << url.prettyURL() << " to "
+ << local.prettyURL() << endl;
+ emit fileUpdating(d->wi.reportLocation);
+ }
+}
+
+WeatherLib::Data* WeatherLib::findData(const QString &stationID)
+{
+ Data *d = data[stationID];
+ if (!d)
+ {
+ d = new Data();
+ d->wi.reportLocation = stationID;
+ d->wi.theWeather = "dunno";
+ d->wi.qsCurrentList.append( i18n( "Retrieving weather data..." ) );
+ data.insert(stationID, d);
+ getData(d);
+ }
+
+ return d;
+}
+
+QString WeatherLib::temperature(const QString &stationID){
+ Data *d = findData(stationID);
+ return d->wi.qsTemperature;
+}
+
+QString WeatherLib::pressure(const QString &stationID){
+ Data *d = findData(stationID);
+ return d->wi.qsPressure;
+}
+
+QString WeatherLib::wind(const QString &stationID){
+ Data *d = findData(stationID);
+ return (d->wi.qsWindSpeed + " " + d->wi.qsWindDirection);
+}
+
+/** */
+QString WeatherLib::dewPoint(const QString &stationID){
+ Data *d = findData(stationID);
+ return d->wi.qsDewPoint;
+}
+
+QString WeatherLib::relHumidity(const QString &stationID){
+ Data *d = findData(stationID);
+ return d->wi.qsRelHumidity;
+}
+
+QString WeatherLib::heatIndex(const QString &stationID){
+ Data *d = findData(stationID);
+ return d->wi.qsHeatIndex;
+}
+
+QString WeatherLib::windChill(const QString &stationID){
+ Data *d = findData(stationID);
+ return d->wi.qsWindChill;
+}
+
+QString WeatherLib::iconName(const QString &stationID){
+
+ QString result("dunno");
+
+ // isEmpty is true for null or 0 length strings
+ if ( !stationID.isEmpty() )
+ {
+ Data *d = findData(stationID);
+ result = d->wi.theWeather;
+ }
+
+ return result;
+}
+
+QString WeatherLib::date(const QString &stationID){
+ Data *d = findData(stationID);
+
+ if ( ! d->wi.qsDate.isValid() )
+ return "";
+ else
+ {
+ QDateTime gmtDateTime(d->wi.qsDate, d->wi.qsTime);
+ QDateTime localDateTime = gmtDateTime.addSecs(KRFCDate::localUTCOffset() * 60);
+ return KGlobal::locale()->formatDateTime(localDateTime, false, false);
+ }
+}
+
+/** Returns the current cover */
+QStringList WeatherLib::cover(const QString &stationID){
+ Data *d = findData(stationID);
+ return d->wi.qsCoverList;
+}
+
+/** return the visibility */
+QString WeatherLib::visibility(const QString &stationID){
+ Data *d = findData(stationID);
+ return d->wi.qsVisibility;
+}
+
+/** return the weather text */
+QStringList WeatherLib::weather(const QString &stationID){
+ Data *d = findData(stationID);
+ return d->wi.qsCurrentList;
+}
+
+bool WeatherLib::stationNeedsMaintenance(const QString &stationID)
+{
+ Data *d = findData(stationID);
+ return d->wi.stationNeedsMaintenance;
+}
+
+void WeatherLib::update(const QString &stationID)
+{
+ // Only grab new data if its more than 50 minutes old
+ Data *d = findData(stationID);
+
+ QDateTime timeout = QDateTime::currentDateTime();
+
+ kdDebug (12006) << "Current Time: " << KGlobal::locale()->formatDateTime(timeout, false, false) <<
+ " Update at: " << KGlobal::locale()->formatDateTime(d->age, false, false) << endl;
+ if( timeout >= d->age || !d->updated)
+ getData(d, true /* try even if host was down last time */);
+ else
+ emit fileUpdate(d->wi.reportLocation);
+}
+
+QStringList WeatherLib::stations()
+{
+ QStringList l;
+ QDictIterator<Data> it( data );
+ for( ; it.current(); ++it )
+ l += it.currentKey();
+ return l;
+}
+
+void WeatherLib::forceUpdate(const QString &stationID)
+{
+ hostDown = false; // we want to show error message if host is still down
+ Data *d = findData(stationID);
+ getData( d );
+}
+
+void WeatherLib::remove(const QString &stationID)
+{
+ data.remove(stationID);
+ emit stationRemoved(stationID);
+}