libgweather r507 - in trunk: . libgweather



Author: danw
Date: Tue Nov 25 14:44:17 2008
New Revision: 507
URL: http://svn.gnome.org/viewvc/libgweather?rev=507&view=rev

Log:
2008-11-25  Milan Crha <mcrha redhat com>

	** Fix for bug #538787

	* libgweather/weather.h:
	* libgweather/weather.c:
	* libgweather/weather-iwin.c:
	Extending API to be able to get WeatherInfo values as numbers.


Modified:
   trunk/ChangeLog
   trunk/libgweather/weather-iwin.c
   trunk/libgweather/weather-priv.h
   trunk/libgweather/weather.c
   trunk/libgweather/weather.h

Modified: trunk/libgweather/weather-iwin.c
==============================================================================
--- trunk/libgweather/weather-iwin.c	(original)
+++ trunk/libgweather/weather-iwin.c	Tue Nov 25 14:44:17 2008
@@ -24,6 +24,8 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <libxml/parser.h>
+
 #define GWEATHER_I_KNOW_THIS_IS_UNSTABLE
 #include "weather.h"
 #include "weather-priv.h"
@@ -40,8 +42,8 @@
 
     while (0 != *ptr) {
         if (ptr[0] == '\n' && ptr[1] == '.') {
-  	    /* This removes the preamble by shifting the relevant data
-	     * down to the start of the buffer. */
+          /* This removes the preamble by shifting the relevant data
+           * down to the start of the buffer. */
             if (NULL == startLine) {
                 memmove (forecast, ptr, strlen (ptr) + 1);
                 ptr = forecast;
@@ -69,6 +71,310 @@
     return forecast;
 }
 
+static gboolean
+hasAttr (xmlNode *node, const char *attr_name, const char *attr_value)
+{
+    xmlChar *attr;
+    gboolean res = FALSE;
+
+    if (!node)
+        return res;
+
+    attr = xmlGetProp (node, (const xmlChar *) attr_name);
+
+    if (!attr)
+        return res;
+
+    res = g_str_equal ((const char *)attr, attr_value);
+
+    xmlFree (attr);
+
+    return res;
+}
+
+static GSList *
+parseForecastXml (const char *buff, WeatherInfo *master_info)
+{
+    GSList *res = NULL;
+    xmlDocPtr doc;
+    xmlNode *root, *node;
+
+    g_return_val_if_fail (master_info != NULL, NULL);
+
+    if (!buff || !*buff)
+    return NULL;
+
+    #define XC (const xmlChar *)
+    #define isElem(_node,_name) g_str_equal ((const char *)_node->name, _name)
+
+    doc = xmlParseMemory (buff, strlen (buff));
+    if (!doc)
+    return NULL;
+
+    /* Description at http://www.weather.gov/mdl/XML/Design/MDL_XML_Design.pdf */
+    root = xmlDocGetRootElement (doc);
+    for (node = root->xmlChildrenNode; node; node = node->next) {
+        if (node->name == NULL || node->type != XML_ELEMENT_NODE)
+            continue;
+
+        if (isElem (node, "data")) {
+            xmlNode *n;
+            char *time_layout = NULL;
+            time_t update_times[7] = {0};
+
+            for (n = node->children; n; n = n->next) {
+                if (!n->name)
+                    continue;
+
+                if (isElem (n, "time-layout")) {
+                    if (!time_layout && hasAttr (n, "summarization", "24hourly")) {
+                        xmlNode *c;
+                        int count = 0;
+
+                        for (c = n->children; c && (count < 7 || !time_layout); c = c->next) {
+                            if (c->name && !time_layout && isElem (c, "layout-key")) {
+                                xmlChar *val = xmlNodeGetContent (c);
+
+                                if (val) {
+                                    time_layout = g_strdup ((const char *)val);
+                                    xmlFree (val);
+                                }
+                            } else if (c->name && isElem (c, "start-valid-time")) {
+                                xmlChar *val = xmlNodeGetContent (c);
+
+                                if (val) {
+                                    struct tm t;
+                                    char sign;
+                                    int gmt1 = 0, gmt2 = 0;
+
+                                    memset (&t, 0, sizeof (struct tm));
+                                    if (sscanf ((const char *)val, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d", &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec, &sign, &gmt1, &gmt2) == 9) {
+                                        t.tm_mon--;
+                                        t.tm_year -= 1900;
+                                        update_times[count] = mktime (&t) + ((sign == '-' ? -1 : 1) * ((60 * gmt1) + gmt2) * 60);
+                                    } else {
+                                        update_times[count] = 0;
+                                    }
+
+                                    count++;
+
+                                    xmlFree (val);
+                                }
+                            }
+                        }
+
+                        if (count != 7) {
+                            /* There can be more than one time-layout element, the other
+                               with only few children, which is not the one to use. */
+                            g_free (time_layout);
+                            time_layout = NULL;
+                        }
+                    }
+                } else if (isElem (n, "parameters")) {
+                    xmlNode *p;
+
+                    /* time-layout should be always before parameters */
+                    if (!time_layout)
+                        break;
+
+                    if (!res) {
+                        int i;
+
+                        for (i = 0; i < 7;  i++) {
+                            WeatherInfo *nfo = weather_info_clone (master_info);
+
+                            if (nfo) {
+                                nfo->valid = FALSE;
+                                nfo->forecast_type = FORECAST_ZONE;
+                                nfo->update = update_times [i];
+                                nfo->sky = -1;
+                                nfo->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+                                nfo->temp = -1000.0;
+                                nfo->temp_min = -1000.0;
+                                nfo->temp_max = -1000.0;
+                                nfo->tempMinMaxValid = FALSE;
+                                nfo->cond.significant = FALSE;
+                                nfo->cond.phenomenon = PHENOMENON_NONE;
+                                nfo->cond.qualifier = QUALIFIER_NONE;
+                                nfo->dew = -1000.0;
+                                nfo->wind = -1;
+                                nfo->windspeed = -1;
+                                nfo->pressure = -1.0;
+                                nfo->visibility = -1.0;
+                                nfo->sunValid = FALSE;
+                                nfo->sunrise = 0;
+                                nfo->sunset = 0;
+                                g_free (nfo->forecast);
+                                nfo->forecast = NULL;
+                                res = g_slist_append (res, nfo);
+                            }
+                        }
+                    }
+
+                    for (p = n->children; p; p = p->next) {
+                        if (p->name && isElem (p, "temperature") && hasAttr (p, "time-layout", time_layout)) {
+                            xmlNode *c;
+                            GSList *at = res;
+                            gboolean is_max = hasAttr (p, "type", "maximum");
+
+                            if (!is_max && !hasAttr (p, "type", "minimum"))
+                                break;
+
+                            for (c = p->children; c && at; c = c->next) {
+                                if (isElem (c, "value")) {
+                                    WeatherInfo *nfo = (WeatherInfo *)at->data;
+                                    xmlChar *val = xmlNodeGetContent (c);
+
+                                    /* can pass some values as <value xsi:nil="true"/> */
+                                    if (!val) {
+                                        if (is_max)
+                                            nfo->temp_max = nfo->temp_min;
+                                        else
+                                            nfo->temp_min = nfo->temp_max;
+                                    } else {
+                                        if (is_max)
+                                            nfo->temp_max = atof ((const char *)val);
+                                        else
+                                            nfo->temp_min = atof ((const char *)val);
+
+                                        xmlFree (val);
+                                    }
+
+                                    nfo->tempMinMaxValid = nfo->tempMinMaxValid || (nfo->temp_max > -999.0 && nfo->temp_min > -999.0);
+                                    nfo->valid = nfo->tempMinMaxValid;
+
+                                    at = at->next;
+                                }
+                            }
+                        } else if (p->name && isElem (p, "weather") && hasAttr (p, "time-layout", time_layout)) {
+                            xmlNode *c;
+                            GSList *at = res;
+
+                            for (c = p->children; c && at; c = c->next) {
+                                if (c->name && isElem (c, "weather-conditions")) {
+                                    WeatherInfo *nfo = at->data;
+                                    xmlChar *val = xmlGetProp (c, XC "weather-summary");
+
+                                    if (val && nfo) {
+                                        /* Checking from top to bottom, if 'value' contains 'name', then that win,
+                                           thus put longer (more precise) values to the top. */
+                                        int i;
+                                        struct _ph_list {
+                                            const char *name;
+                                            WeatherConditionPhenomenon ph;
+                                        } ph_list[] = {
+                                            { "Ice Crystals", PHENOMENON_ICE_CRYSTALS } ,
+                                            { "Volcanic Ash", PHENOMENON_VOLCANIC_ASH } ,
+                                            { "Blowing Sand", PHENOMENON_SANDSTORM } ,
+                                            { "Blowing Dust", PHENOMENON_DUSTSTORM } ,
+                                            { "Blowing Snow", PHENOMENON_FUNNEL_CLOUD } ,
+                                            { "Drizzle", PHENOMENON_DRIZZLE } ,
+                                            { "Rain", PHENOMENON_RAIN } ,
+                                            { "Snow", PHENOMENON_SNOW } ,
+                                            { "Fog", PHENOMENON_FOG } ,
+                                            { "Smoke", PHENOMENON_SMOKE } ,
+                                            { "Sand", PHENOMENON_SAND } ,
+                                            { "Haze", PHENOMENON_HAZE } ,
+                                            { "Dust", PHENOMENON_DUST } /*,
+                                            { "", PHENOMENON_SNOW_GRAINS } ,
+                                            { "", PHENOMENON_ICE_PELLETS } ,
+                                            { "", PHENOMENON_HAIL } ,
+                                            { "", PHENOMENON_SMALL_HAIL } ,
+                                            { "", PHENOMENON_UNKNOWN_PRECIPITATION } ,
+                                            { "", PHENOMENON_MIST } ,
+                                            { "", PHENOMENON_SPRAY } ,
+                                            { "", PHENOMENON_SQUALL } ,
+                                            { "", PHENOMENON_TORNADO } ,
+                                            { "", PHENOMENON_DUST_WHIRLS } */
+                                        };
+                                        struct _sky_list {
+                                            const char *name;
+                                            WeatherSky sky;
+                                        } sky_list[] = {
+                                            { "Mostly Sunny", SKY_BROKEN } ,
+                                            { "Mostly Clear", SKY_BROKEN } ,
+                                            { "Partly Cloudy", SKY_SCATTERED } ,
+                                            { "Mostly Cloudy", SKY_FEW } ,
+                                            { "Sunny", SKY_CLEAR } ,
+                                            { "Clear", SKY_CLEAR } ,
+                                            { "Cloudy", SKY_OVERCAST } ,
+                                            { "Clouds", SKY_SCATTERED } ,
+                                            { "Rain", SKY_SCATTERED } ,
+                                            { "Snow", SKY_SCATTERED }
+                                        };
+
+                                        nfo->valid = TRUE;
+                                        g_free (nfo->forecast);
+                                        nfo->forecast = g_strdup ((const char *)val);
+
+                                        for (i = 0; i < G_N_ELEMENTS (ph_list); i++) {
+                                            if (strstr ((const char *)val, ph_list [i].name)) {
+                                                nfo->cond.phenomenon = ph_list [i].ph;
+                                                break;
+                                            }
+                                        }
+
+                                        for (i = 0; i < G_N_ELEMENTS (sky_list); i++) {
+                                            if (strstr ((const char *)val, sky_list [i].name)) {
+                                                nfo->sky = sky_list [i].sky;
+                                                break;
+                                            }
+                                        }
+                                    }
+
+                                    at = at->next;
+                                }
+                            }
+                        }
+                    }
+
+                    if (res) {
+                        gboolean have_any = FALSE;
+                        GSList *r;
+
+                        /* Remove invalid forecast data from the list.
+                           They should be all valid or all invalid. */
+                        for (r = res; r; r = r->next) {
+                            WeatherInfo *nfo = r->data;
+
+                            if (!nfo || !nfo->valid) {
+                                if (r->data)
+                                    weather_info_free (r->data);
+
+                                r->data = NULL;
+                            } else {
+                                have_any = TRUE;
+
+                                if (nfo->tempMinMaxValid)
+                                    nfo->temp = (nfo->temp_min + nfo->temp_max) / 2.0;
+                            }
+                        }
+
+                        if (!have_any) {
+                            /* data members are freed already */
+                            g_slist_free (res);
+                            res = NULL;
+                        }
+                    }
+
+                    break;
+                }
+            }
+
+            g_free (time_layout);
+
+            /* stop seeking XML */
+            break;
+        }
+    }
+    xmlFreeDoc (doc);
+
+    #undef XC
+    #undef isElem
+
+    return res;
+}
+
 static void
 iwin_finish (SoupSession *session, SoupMessage *msg, gpointer data)
 {
@@ -78,13 +384,17 @@
 
     if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
         /* forecast data is not really interesting anyway ;) */
-	g_warning ("Failed to get IWIN forecast data: %d %s\n",
-		   msg->status_code, msg->reason_phrase);
+    g_warning ("Failed to get IWIN forecast data: %d %s\n",
+           msg->status_code, msg->reason_phrase);
         request_done (info, FALSE);
-	return;
+    return;
     }
 
+    if (info->forecast_type == FORECAST_LIST)
+    info->forecast_list = parseForecastXml (msg->response_body->data, info);
+    else
     info->forecast = formatWeatherMsg (g_strdup (msg->response_body->data));
+
     request_done (info, TRUE);
 }
 
@@ -104,18 +414,41 @@
         return;
 
     if (info->forecast) {
-	g_free (info->forecast);
-	info->forecast = NULL;
+    g_free (info->forecast);
+    info->forecast = NULL;
+    }
+
+    free_forecast_list (info);    
+
+    if (info->forecast_type == FORECAST_LIST) {
+        /* see the description here: http://www.weather.gov/forecasts/xml/ */
+        if (loc->latlon_valid) {
+            struct tm tm;
+            time_t now = time (NULL);
+
+            localtime_r (&now, &tm);
+
+            url = g_strdup_printf ("http://www.weather.gov/forecasts/xml/sample_products/browser_interface/ndfdBrowserClientByDay.php?&lat=%.02f&lon=%.02f&format=24+hourly&startDate=%04d-%02d-%02d&numDays=7";,
+                       RADIANS_TO_DEGREES (loc->latitude), RADIANS_TO_DEGREES (loc->longitude), 1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday);
+
+            msg = soup_message_new ("GET", url);
+            g_free (url);
+            soup_session_queue_message (info->session, msg, iwin_finish, info);
+
+            info->requests_pending++;
+        }
+
+        return;
     }
 
     if (loc->zone[0] == ':') {
-	/* Met Office Region Names */
-    	metoffice_start_open (info);
-    	return;
+        /* Met Office Region Names */
+        metoffice_start_open (info);
+        return;
     } else if (loc->zone[0] == '@') {
-	/* Australian BOM forecasts */
-    	bom_start_open (info);
-    	return;
+        /* Australian BOM forecasts */
+        bom_start_open (info);
+        return;
     }
 
     /* The zone for Pittsburgh (for example) is given as PAZ021 in the locations
@@ -125,8 +458,8 @@
     zone = g_ascii_strdown (loc->zone, -1);
     state = g_strndup (zone, 2);
 
-    url = g_strdup_printf ("http://weather.noaa.gov/pub/data/forecasts/zone/%s/%s.txt";,
-        		   state, zone);
+    url = g_strdup_printf ("http://weather.noaa.gov/pub/data/forecasts/zone/%s/%s.txt";, state, zone);
+
     g_free (zone);
     g_free (state);
     

Modified: trunk/libgweather/weather-priv.h
==============================================================================
--- trunk/libgweather/weather-priv.h	(original)
+++ trunk/libgweather/weather-priv.h	Tue Nov 25 14:44:17 2008
@@ -21,6 +21,7 @@
 
 #include <time.h>
 #include <libintl.h>
+#include <math.h>
 #include <libsoup/soup.h>
 
 #include "weather.h"
@@ -40,79 +41,6 @@
  * Weather information.
  */
 
-enum _WeatherWindDirection {
-    WIND_VARIABLE,
-    WIND_N, WIND_NNE, WIND_NE, WIND_ENE,
-    WIND_E, WIND_ESE, WIND_SE, WIND_SSE,
-    WIND_S, WIND_SSW, WIND_SW, WIND_WSW,
-    WIND_W, WIND_WNW, WIND_NW, WIND_NNW
-};
-
-typedef enum _WeatherWindDirection WeatherWindDirection;
-
-enum _WeatherSky {
-    SKY_INVALID = -1,
-    SKY_CLEAR,
-    SKY_BROKEN,
-    SKY_SCATTERED,
-    SKY_FEW,
-    SKY_OVERCAST
-};
-
-typedef enum _WeatherSky WeatherSky;
-
-enum _WeatherConditionPhenomenon {
-    PHENOMENON_NONE,
-
-    PHENOMENON_DRIZZLE,
-    PHENOMENON_RAIN,
-    PHENOMENON_SNOW,
-    PHENOMENON_SNOW_GRAINS,
-    PHENOMENON_ICE_CRYSTALS,
-    PHENOMENON_ICE_PELLETS,
-    PHENOMENON_HAIL,
-    PHENOMENON_SMALL_HAIL,
-    PHENOMENON_UNKNOWN_PRECIPITATION,
-
-    PHENOMENON_MIST,
-    PHENOMENON_FOG,
-    PHENOMENON_SMOKE,
-    PHENOMENON_VOLCANIC_ASH,
-    PHENOMENON_SAND,
-    PHENOMENON_HAZE,
-    PHENOMENON_SPRAY,
-    PHENOMENON_DUST,
-
-    PHENOMENON_SQUALL,
-    PHENOMENON_SANDSTORM,
-    PHENOMENON_DUSTSTORM,
-    PHENOMENON_FUNNEL_CLOUD,
-    PHENOMENON_TORNADO,
-    PHENOMENON_DUST_WHIRLS
-};
-
-typedef enum _WeatherConditionPhenomenon WeatherConditionPhenomenon;
-
-enum _WeatherConditionQualifier {
-    QUALIFIER_NONE,
-
-    QUALIFIER_VICINITY,
-
-    QUALIFIER_LIGHT,
-    QUALIFIER_MODERATE,
-    QUALIFIER_HEAVY,
-    QUALIFIER_SHALLOW,
-    QUALIFIER_PATCHES,
-    QUALIFIER_PARTIAL,
-    QUALIFIER_THUNDERSTORM,
-    QUALIFIER_BLOWING,
-    QUALIFIER_SHOWERS,
-    QUALIFIER_DRIFTING,
-    QUALIFIER_FREEZING
-};
-
-typedef enum _WeatherConditionQualifier WeatherConditionQualifier;
-
 struct _WeatherConditions {
     gboolean significant;
     WeatherConditionPhenomenon phenomenon;
@@ -139,11 +67,14 @@
     gboolean valid;
     gboolean network_error;
     gboolean sunValid;
+    gboolean tempMinMaxValid;
     WeatherLocation *location;
     WeatherUpdate update;
     WeatherSky sky;
     WeatherConditions cond;
     WeatherTemperature temp;
+    WeatherTemperature temp_min;
+    WeatherTemperature temp_max;
     WeatherTemperature dew;
     WeatherWindDirection wind;
     WeatherWindSpeed windspeed;
@@ -152,6 +83,7 @@
     WeatherUpdate sunrise;
     WeatherUpdate sunset;
     gchar *forecast;
+    GSList *forecast_list; /* list of WeatherInfo* for the forecast, NULL if not available */
     gchar *radar_buffer;
     gchar *radar_url;
     GdkPixbufLoader *radar_loader;
@@ -219,5 +151,7 @@
 
 gboolean	calc_sun		(WeatherInfo *info);
 
+void		free_forecast_list	(WeatherInfo *info);
+
 #endif /* __WEATHER_PRIV_H_ */
 

Modified: trunk/libgweather/weather.c
==============================================================================
--- trunk/libgweather/weather.c	(original)
+++ trunk/libgweather/weather.c	Tue Nov 25 14:44:17 2008
@@ -332,8 +332,25 @@
         info->finish_cb (info, info->cb_data);
 }
 
-/* Relative humidity computation - thanks to <Olof Oberg modopaper modogroup com> */
+/* it's OK to pass in NULL */
+void
+free_forecast_list (WeatherInfo *info)
+{
+    GSList *p;
+
+    if (!info)
+	return;
+
+    for (p = info->forecast_list; p; p = p->next)
+	weather_info_free (p->data);
+
+    if (info->forecast_list) {
+	g_slist_free (info->forecast_list);
+	info->forecast_list = NULL;
+    }
+}
 
+/* Relative humidity computation - thanks to <Olof Oberg modopaper modogroup com> */
 
 static inline gdouble
 calc_humidity (gdouble temp, gdouble dewp)
@@ -490,8 +507,10 @@
         location = info->location;
 	if (info->forecast)
 	    g_free (info->forecast);
-
 	info->forecast = NULL;
+
+	free_forecast_list (info);
+
 	if (info->radar != NULL) {
 	    g_object_unref (info->radar);
 	    info->radar = NULL;
@@ -519,6 +538,9 @@
     info->cond.phenomenon = PHENOMENON_NONE;
     info->cond.qualifier = QUALIFIER_NONE;
     info->temp = -1000.0;
+    info->tempMinMaxValid = FALSE;
+    info->temp_min = -1000.0;
+    info->temp_max = -1000.0;
     info->dew = -1000.0;
     info->wind = -1;
     info->windspeed = -1;
@@ -528,6 +550,7 @@
     info->sunrise = 0;
     info->sunset = 0;
     info->forecast = NULL;
+    info->forecast_list = NULL;
     info->radar = NULL;
     info->radar_url = prefs->radar && prefs->radar_custom_url ?
     		      g_strdup (prefs->radar_custom_url) : NULL;
@@ -576,6 +599,17 @@
     clone->forecast = g_strdup (info->forecast);
     clone->radar_url = g_strdup (info->radar_url);
 
+    if (info->forecast_list) {
+	GSList *p;
+
+	clone->forecast_list = NULL;
+	for (p = info->forecast_list; p; p = p->next) {
+	    clone->forecast_list = g_slist_prepend (clone->forecast_list, weather_info_clone (p->data));
+	}
+
+	clone->forecast_list = g_slist_reverse (clone->forecast_list);
+    }
+
     clone->radar = info->radar;
     if (clone->radar != NULL)
 	g_object_ref (clone->radar);
@@ -599,6 +633,8 @@
     g_free (info->forecast);
     info->forecast = NULL;
 
+    free_forecast_list (info);
+
     if (info->radar != NULL) {
         g_object_unref (info->radar);
         info->radar = NULL;
@@ -621,6 +657,28 @@
     return info->network_error;
 }
 
+void
+weather_info_to_metric (WeatherInfo *info)
+{
+    g_return_if_fail(info != NULL);
+
+    info->temperature_unit = TEMP_UNIT_CENTIGRADE;
+    info->speed_unit = SPEED_UNIT_MS;
+    info->pressure_unit = PRESSURE_UNIT_HPA;
+    info->distance_unit = DISTANCE_UNIT_METERS;
+}
+
+void
+weather_info_to_imperial (WeatherInfo *info)
+{
+    g_return_if_fail(info != NULL);
+
+    info->temperature_unit = TEMP_UNIT_FAHRENHEIT;
+    info->speed_unit = SPEED_UNIT_MPH;
+    info->pressure_unit = PRESSURE_UNIT_INCH_HG;
+    info->distance_unit = DISTANCE_UNIT_MILES;
+}
+
 const WeatherLocation *
 weather_info_get_location (WeatherInfo *info)
 {
@@ -753,6 +811,32 @@
 }
 
 const gchar *
+weather_info_get_temp_min (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || !info->tempMinMaxValid)
+        return "-";
+    if (info->temp_min < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp_min, info->temperature_unit, FALSE);
+}
+
+const gchar *
+weather_info_get_temp_max (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid || !info->tempMinMaxValid)
+        return "-";
+    if (info->temp_max < -500.0)
+        return _("Unknown");
+
+    return temperature_string (info->temp_max, info->temperature_unit, FALSE);
+}
+
+const gchar *
 weather_info_get_dew (WeatherInfo *info)
 {
     g_return_val_if_fail (info != NULL, NULL);
@@ -996,6 +1080,26 @@
     return info->forecast;
 }
 
+/**
+ * weather_info_get_forecast_list:
+ * Returns list of WeatherInfo* objects for the forecast.
+ * The list is owned by the 'info' object thus is alive as long
+ * as the 'info'. This list is filled only when requested with
+ * type FORECAST_LIST and if available for given location.
+ * The 'update' property is the date/time when the forecast info
+ * is used for.
+ **/
+GSList *
+weather_info_get_forecast_list (WeatherInfo *info)
+{
+    g_return_val_if_fail (info != NULL, NULL);
+
+    if (!info->valid)
+	return NULL;
+
+    return info->forecast_list;
+}
+
 GdkPixbufAnimation *
 weather_info_get_radar (WeatherInfo *info)
 {
@@ -1113,3 +1217,338 @@
 
     return NULL;
 }
+
+static gboolean
+temperature_value (gdouble far, TempUnit to_unit, gdouble *value, TempUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = 0.0;
+    if (far < -500.0)
+	return FALSE;
+
+    if (to_unit == TEMP_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case TEMP_UNIT_FAHRENHEIT:
+	    *value = far;
+	    break;
+        case TEMP_UNIT_CENTIGRADE:
+	    *value = TEMP_F_TO_C (far);
+	    break;
+        case TEMP_UNIT_KELVIN:
+	    *value = TEMP_F_TO_K (far);
+	    break;
+        case TEMP_UNIT_INVALID:
+        case TEMP_UNIT_DEFAULT:
+	default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+static gboolean
+speed_value (gdouble knots, SpeedUnit to_unit, gdouble *value, SpeedUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (knots < 0.0)
+	return FALSE;
+
+    if (to_unit == SPEED_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case SPEED_UNIT_KNOTS:
+            *value = knots;
+	    break;
+        case SPEED_UNIT_MPH:
+            *value = WINDSPEED_KNOTS_TO_MPH (knots);
+	    break;
+        case SPEED_UNIT_KPH:
+            *value = WINDSPEED_KNOTS_TO_KPH (knots);
+	    break;
+        case SPEED_UNIT_MS:
+            *value = WINDSPEED_KNOTS_TO_MS (knots);
+	    break;
+	case SPEED_UNIT_BFT:
+	    *value = WINDSPEED_KNOTS_TO_BFT (knots);
+	    break;
+        case SPEED_UNIT_INVALID:
+        case SPEED_UNIT_DEFAULT:
+        default:
+            ok = FALSE;
+            break;
+    }
+
+    return ok;
+}
+
+static gboolean
+pressure_value (gdouble inHg, PressureUnit to_unit, gdouble *value, PressureUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (inHg < 0.0)
+	return FALSE;
+
+    if (to_unit == PRESSURE_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case PRESSURE_UNIT_INCH_HG:
+            *value = inHg;
+	    break;
+        case PRESSURE_UNIT_MM_HG:
+            *value = PRESSURE_INCH_TO_MM (inHg);
+	    break;
+        case PRESSURE_UNIT_KPA:
+            *value = PRESSURE_INCH_TO_KPA (inHg);
+	    break;
+        case PRESSURE_UNIT_HPA:
+            *value = PRESSURE_INCH_TO_HPA (inHg);
+	    break;
+        case PRESSURE_UNIT_MB:
+            *value = PRESSURE_INCH_TO_MB (inHg);
+	    break;
+        case PRESSURE_UNIT_ATM:
+            *value = PRESSURE_INCH_TO_ATM (inHg);
+	    break;
+        case PRESSURE_UNIT_INVALID:
+        case PRESSURE_UNIT_DEFAULT:
+        default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+static gboolean
+distance_value (gdouble miles, DistanceUnit to_unit, gdouble *value, DistanceUnit def_unit)
+{
+    gboolean ok = TRUE;
+
+    *value = -1.0;
+
+    if (miles < 0.0)
+	return FALSE;
+
+    if (to_unit == DISTANCE_UNIT_DEFAULT)
+	    to_unit = def_unit;
+
+    switch (to_unit) {
+        case DISTANCE_UNIT_MILES:
+            *value = miles;
+            break;
+        case DISTANCE_UNIT_KM:
+            *value = VISIBILITY_SM_TO_KM (miles);
+            break;
+        case DISTANCE_UNIT_METERS:
+            *value = VISIBILITY_SM_TO_M (miles);
+            break;
+        case DISTANCE_UNIT_INVALID:
+        case DISTANCE_UNIT_DEFAULT:
+        default:
+	    ok = FALSE;
+	    break;
+    }
+
+    return ok;
+}
+
+gboolean
+weather_info_get_value_sky (WeatherInfo *info, WeatherSky *sky)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (sky != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (info->sky < 0 || info->sky >= (sizeof (sky_str) / sizeof (char *)))
+	return FALSE;
+
+    *sky = info->sky;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_conditions (WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (phenomenon != NULL, FALSE);
+    g_return_val_if_fail (qualifier != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (!info->cond.significant)
+	return FALSE;
+
+    if (!(info->cond.phenomenon >= 0 &&
+	info->cond.phenomenon < 24 &&
+	info->cond.qualifier >= 0 &&
+	info->cond.qualifier < 13))
+        return FALSE;
+
+    *phenomenon = info->cond.phenomenon;
+    *qualifier = info->cond.qualifier;
+
+    return TRUE;
+}
+
+gboolean
+weather_info_get_value_temp (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (info->temp, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_temp_min (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->tempMinMaxValid)
+	return FALSE;
+
+    return temperature_value (info->temp_min, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_temp_max (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->tempMinMaxValid)
+	return FALSE;
+
+    return temperature_value (info->temp_max, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_dew (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (info->dew, unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_apparent (WeatherInfo *info, TempUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return temperature_value (calc_apparent (info), unit, value, info->temperature_unit);
+}
+
+gboolean
+weather_info_get_value_update (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    *value = info->update;
+
+    return *value != 0;
+}
+
+gboolean
+weather_info_get_value_sunrise (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->sunValid)
+	return FALSE;
+
+    *value = info->sunrise;
+
+    return *value != 0;
+}
+
+gboolean
+weather_info_get_value_sunset (WeatherInfo *info, time_t *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid || !info->sunValid)
+	return FALSE;
+
+    *value = info->sunset;
+
+    return *value != 0;
+}
+
+gboolean
+weather_info_get_value_wind (WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction)
+{
+    gboolean res = FALSE;
+
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (speed != NULL, FALSE);
+    g_return_val_if_fail (direction != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    if (info->windspeed < 0.0 || info->wind < 0 || info->wind >= (sizeof (wind_direction_str) / sizeof (char *)))
+        return FALSE;
+
+    res = speed_value (info->windspeed, unit, speed, info->speed_unit);
+    *direction = info->wind;
+
+    return res;
+}
+
+gboolean
+weather_info_get_value_pressure (WeatherInfo *info, PressureUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return pressure_value (info->pressure, unit, value, info->pressure_unit);
+}
+
+gboolean
+weather_info_get_value_visibility (WeatherInfo *info, DistanceUnit unit, gdouble *value)
+{
+    g_return_val_if_fail (info != NULL, FALSE);
+    g_return_val_if_fail (value != NULL, FALSE);
+
+    if (!info->valid)
+	return FALSE;
+
+    return distance_value (info->visibility, unit, value, info->distance_unit);
+}

Modified: trunk/libgweather/weather.h
==============================================================================
--- trunk/libgweather/weather.h	(original)
+++ trunk/libgweather/weather.h	Tue Nov 25 14:44:17 2008
@@ -67,7 +67,8 @@
 
 typedef enum _WeatherForecastType {
     FORECAST_STATE,
-    FORECAST_ZONE
+    FORECAST_ZONE,
+    FORECAST_LIST
 } WeatherForecastType;
 
 typedef enum {
@@ -153,6 +154,8 @@
 const gchar *		weather_info_get_sky		(WeatherInfo *info);
 const gchar *		weather_info_get_conditions	(WeatherInfo *info);
 const gchar *		weather_info_get_temp		(WeatherInfo *info);
+const gchar *		weather_info_get_temp_min	(WeatherInfo *info);
+const gchar *		weather_info_get_temp_max	(WeatherInfo *info);
 const gchar *		weather_info_get_dew		(WeatherInfo *info);
 const gchar *		weather_info_get_humidity	(WeatherInfo *info);
 const gchar *		weather_info_get_wind		(WeatherInfo *info);
@@ -162,6 +165,7 @@
 const gchar *		weather_info_get_sunrise	(WeatherInfo *info);
 const gchar *		weather_info_get_sunset		(WeatherInfo *info);
 const gchar *		weather_info_get_forecast	(WeatherInfo *info);
+GSList *		weather_info_get_forecast_list	(WeatherInfo *info);
 GdkPixbufAnimation *	weather_info_get_radar		(WeatherInfo *info);
 
 const gchar *		weather_info_get_temp_summary	(WeatherInfo *info);
@@ -169,6 +173,96 @@
 
 const gchar *		weather_info_get_icon_name	(WeatherInfo *info);
 gint			weather_info_next_sun_event	(WeatherInfo *info);
+
+/* values retrieving functions */
+
+enum _WeatherWindDirection {
+    WIND_VARIABLE,
+    WIND_N, WIND_NNE, WIND_NE, WIND_ENE,
+    WIND_E, WIND_ESE, WIND_SE, WIND_SSE,
+    WIND_S, WIND_SSW, WIND_SW, WIND_WSW,
+    WIND_W, WIND_WNW, WIND_NW, WIND_NNW
+};
+
+typedef enum _WeatherWindDirection WeatherWindDirection;
+
+enum _WeatherSky {
+    SKY_INVALID = -1,
+    SKY_CLEAR,
+    SKY_BROKEN,
+    SKY_SCATTERED,
+    SKY_FEW,
+    SKY_OVERCAST
+};
+
+typedef enum _WeatherSky WeatherSky;
+
+enum _WeatherConditionPhenomenon {
+    PHENOMENON_NONE,
+
+    PHENOMENON_DRIZZLE,
+    PHENOMENON_RAIN,
+    PHENOMENON_SNOW,
+    PHENOMENON_SNOW_GRAINS,
+    PHENOMENON_ICE_CRYSTALS,
+    PHENOMENON_ICE_PELLETS,
+    PHENOMENON_HAIL,
+    PHENOMENON_SMALL_HAIL,
+    PHENOMENON_UNKNOWN_PRECIPITATION,
+
+    PHENOMENON_MIST,
+    PHENOMENON_FOG,
+    PHENOMENON_SMOKE,
+    PHENOMENON_VOLCANIC_ASH,
+    PHENOMENON_SAND,
+    PHENOMENON_HAZE,
+    PHENOMENON_SPRAY,
+    PHENOMENON_DUST,
+
+    PHENOMENON_SQUALL,
+    PHENOMENON_SANDSTORM,
+    PHENOMENON_DUSTSTORM,
+    PHENOMENON_FUNNEL_CLOUD,
+    PHENOMENON_TORNADO,
+    PHENOMENON_DUST_WHIRLS
+};
+
+typedef enum _WeatherConditionPhenomenon WeatherConditionPhenomenon;
+
+enum _WeatherConditionQualifier {
+    QUALIFIER_NONE,
+
+    QUALIFIER_VICINITY,
+
+    QUALIFIER_LIGHT,
+    QUALIFIER_MODERATE,
+    QUALIFIER_HEAVY,
+    QUALIFIER_SHALLOW,
+    QUALIFIER_PATCHES,
+    QUALIFIER_PARTIAL,
+    QUALIFIER_THUNDERSTORM,
+    QUALIFIER_BLOWING,
+    QUALIFIER_SHOWERS,
+    QUALIFIER_DRIFTING,
+    QUALIFIER_FREEZING
+};
+
+typedef enum _WeatherConditionQualifier WeatherConditionQualifier;
+
+gboolean weather_info_get_value_update		(WeatherInfo *info, time_t *value);
+gboolean weather_info_get_value_sky		(WeatherInfo *info, WeatherSky *sky);
+gboolean weather_info_get_value_conditions	(WeatherInfo *info, WeatherConditionPhenomenon *phenomenon, WeatherConditionQualifier *qualifier);
+gboolean weather_info_get_value_temp		(WeatherInfo *info, TempUnit unit, gdouble *value);
+gboolean weather_info_get_value_temp_min	(WeatherInfo *info, TempUnit unit, gdouble *value);
+gboolean weather_info_get_value_temp_max	(WeatherInfo *info, TempUnit unit, gdouble *value);
+gboolean weather_info_get_value_dew		(WeatherInfo *info, TempUnit unit, gdouble *value);
+gboolean weather_info_get_value_apparent	(WeatherInfo *info, TempUnit unit, gdouble *value);
+gboolean weather_info_get_value_wind		(WeatherInfo *info, SpeedUnit unit, gdouble *speed, WeatherWindDirection *direction);
+gboolean weather_info_get_value_pressure	(WeatherInfo *info, PressureUnit unit, gdouble *value);
+gboolean weather_info_get_value_visibility	(WeatherInfo *info, DistanceUnit unit, gdouble *value);
+gboolean weather_info_get_value_sunrise		(WeatherInfo *info, time_t *value);
+gboolean weather_info_get_value_sunset 		(WeatherInfo *info, time_t *value);
+
 G_END_DECLS
 
 #endif /* __WEATHER_H_ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]