[geocode-glib/wip/nominatim: 14/14] lib: Port forward geocoding API to Nominatim



commit cc4f53857af323142ed43723819f63803483efa8
Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
Date:   Wed Jul 24 04:32:27 2013 +0300

    lib: Port forward geocoding API to Nominatim
    
    This patch completes porting from Yahoo Places API to Nominatim.
    
    Apart from keeping the working testcases still working, this patch also
    makes some of the failing testcases working again.

 geocode-glib/data/geoplanet-rio.json          |    1 -
 geocode-glib/data/nominatim-area.json         |    1 +
 geocode-glib/data/nominatim-no-results.json   |    1 +
 geocode-glib/data/nominatim-rio.json          |    1 +
 geocode-glib/data/placefinder-area.json       |    1 -
 geocode-glib/data/placefinder-got-error.json  |    1 -
 geocode-glib/data/placefinder-no-results.json |    1 -
 geocode-glib/geocode-forward.c                |  686 +++++++++----------------
 geocode-glib/geocode-glib-private.h           |    7 +-
 geocode-glib/geocode-glib.symbols             |    1 +
 geocode-glib/geocode-place.c                  |    5 +-
 geocode-glib/geocode-reverse.c                |   39 +-
 geocode-glib/test-gcglib.c                    |  100 ++--
 13 files changed, 322 insertions(+), 523 deletions(-)
---
diff --git a/geocode-glib/data/nominatim-area.json b/geocode-glib/data/nominatim-area.json
new file mode 100644
index 0000000..9c9f2c1
--- /dev/null
+++ b/geocode-glib/data/nominatim-area.json
@@ -0,0 +1 @@
+[{"place_id":"20666856","licence":"Data \u00a9 OpenStreetMap contributors, ODbL 1.0. 
http:\/\/www.openstreetmap.org\/copyright","osm_type":"way","osm_id":"4317978","boundingbox":["51.2366485595703","51.2370834350586","-0.593727946281433","-0.589645385742188"],"lat":"51.2368852","lon":"-0.5912434","display_name":"Old
 Palace Road, Guildford Park, Guildford, Surrey, South East England, England, GU2 7PJ, United 
Kingdom","class":"highway","type":"residential","importance":1.1,"address":{"road":"Old Palace 
Road","suburb":"Guildford Park","city":"Guildford","county":"Surrey","state_district":"South East 
England","state":"England","postcode":"GU2 7PJ","country":"United Kingdom","country_code":"gb"}}]
\ No newline at end of file
diff --git a/geocode-glib/data/nominatim-no-results.json b/geocode-glib/data/nominatim-no-results.json
new file mode 100644
index 0000000..fe51488
--- /dev/null
+++ b/geocode-glib/data/nominatim-no-results.json
@@ -0,0 +1 @@
+[]
diff --git a/geocode-glib/data/nominatim-rio.json b/geocode-glib/data/nominatim-rio.json
new file mode 100644
index 0000000..ff63973
--- /dev/null
+++ b/geocode-glib/data/nominatim-rio.json
@@ -0,0 +1 @@
+[{"place_id":"97370140","licence":"Data \u00a9 OpenStreetMap contributors, ODbL 1.0. 
http:\/\/www.openstreetmap.org\/copyright","osm_type":"relation","osm_id":"57963","boundingbox":["-23.7002544403076","-20.7631759643555","-44.8884963989258","-40.6241073608398"],"lat":"-22.2752762","lon":"-42.419415","display_name":"Rio
 de Janeiro, 
Brazil","class":"boundary","type":"administrative","importance":1.1529903290992,"icon":"http:\/\/nominatim.openstreetmap.org\/images\/mapicons\/poi_boundary_administrative.p.20.png","address":{"state":"Rio
 de Janeiro","country":"Brazil","country_code":"br"}},{"place_id":"3676494506","licence":"Data \u00a9 
OpenStreetMap contributors, ODbL 1.0. 
http:\/\/www.openstreetmap.org\/copyright","osm_type":"relation","osm_id":"2697338","boundingbox":["-23.0763473510742","-22.7756004333496","-43.793888092041","-43.1502380371094"],"lat":"-22.9112163","lon":"-43.2093781","display_name":"Rio
 de Janeiro, Regi\u00e3o Metropolitana do Rio de Janeiro, Rio de Janeiro
 , 
Brazil","class":"boundary","type":"administrative","importance":1.1352505367143,"icon":"http:\/\/nominatim.openstreetmap.org\/images\/mapicons\/poi_boundary_administrative.p.20.png","address":{"city":"Rio
 de Janeiro","county":"Rio de Janeiro","state_district":"Regi\u00e3o Metropolitana do Rio de 
Janeiro","state":"Rio de 
Janeiro","country":"Brazil","country_code":"br"}},{"place_id":"98213413","licence":"Data \u00a9 OpenStreetMap 
contributors, ODbL 1.0. 
http:\/\/www.openstreetmap.org\/copyright","osm_type":"relation","osm_id":"2220780","boundingbox":["-23.0763473510742","-22.4493675231934","-43.793888092041","-42.6359710693359"],"lat":"-22.76285795","lon":"-43.163137120742","display_name":"Rio
 de Janeiro, Regi\u00e3o Metropolitana do Rio de Janeiro, Rio de Janeiro, Regi\u00e3o Sudeste, 
Brazil","class":"boundary","type":"administrative","importance":0.9,"icon":"http:\/\/nominatim.openstreetmap.org\/images\/mapicons\/poi_boundary_administrative.p.20.png","address":{"county":"R
 io de Janeiro","state_district":"Regi\u00e3o Metropolitana do Rio de Janeiro","state":"Rio de 
Janeiro","country":"Brazil","country_code":"br"}},{"place_id":"4138975","licence":"Data \u00a9 OpenStreetMap 
contributors, ODbL 1.0. 
http:\/\/www.openstreetmap.org\/copyright","osm_type":"node","osm_id":"416761389","boundingbox":["-11.8030433654785","-11.8030424118042","-46.0533256530762","-46.0533218383789"],"lat":"-11.803043","lon":"-46.053324","display_name":"Rio
 de Janeiro, Bahia, 
Brazil","class":"place","type":"hamlet","importance":0.775,"icon":"http:\/\/nominatim.openstreetmap.org\/images\/mapicons\/poi_place_village.p.20.png","address":{"hamlet":"Rio
 de Janeiro","state":"Bahia","country":"Brazil","country_code":"br"}},{"place_id":"4158551","licence":"Data 
\u00a9 OpenStreetMap contributors, ODbL 1.0. 
http:\/\/www.openstreetmap.org\/copyright","osm_type":"node","osm_id":"416758278","boundingbox":["-4.61738204956055","-4.61738157272339","-69.5044631958008","-69.5044555664062"],"
 lat":"-4.617382","lon":"-69.50446","display_name":"Rio de Janeiro, Amazonas (old), 
Brazil","class":"place","type":"hamlet","importance":0.775,"icon":"http:\/\/nominatim.openstreetmap.org\/images\/mapicons\/poi_place_village.p.20.png","address":{"hamlet":"Rio
 de Janeiro","state":"Amazonas 
(old)","country":"Brazil","country_code":"br"}},{"place_id":"7213293","licence":"Data \u00a9 OpenStreetMap 
contributors, ODbL 1.0. 
http:\/\/www.openstreetmap.org\/copyright","osm_type":"node","osm_id":"703219534","boundingbox":["3.84114599227905","3.84114623069763","-75.6528549194336","-75.6528472900391"],"lat":"3.8411461","lon":"-75.6528531","display_name":"Rio
 De Janeiro, El Recreo - Sec. Davis, Chaparral, Tolima, 
Colombia","class":"place","type":"locality","importance":0.75,"icon":"http:\/\/nominatim.openstreetmap.org\/images\/mapicons\/poi_place_village.p.20.png","address":{"locality":"Rio
 De Janeiro","hamlet":"El Recreo - Sec. Davis","county":"Chaparral","state":"Tolima","country":"Colo
 mbia","country_code":"co"}},{"place_id":"7290665","licence":"Data \u00a9 OpenStreetMap contributors, ODbL 
1.0. 
http:\/\/www.openstreetmap.org\/copyright","osm_type":"node","osm_id":"703507495","boundingbox":["8.97100257873535","8.97100353240967","-74.881462097168","-74.8814544677734"],"lat":"8.9710032","lon":"-74.8814589","display_name":"Rio
 De Janeiro, Colombia, San Benito Abad, Sucre, 
Colombia","class":"place","type":"locality","importance":0.75,"icon":"http:\/\/nominatim.openstreetmap.org\/images\/mapicons\/poi_place_village.p.20.png","address":{"locality":"Rio
 De Janeiro","hamlet":"Colombia","county":"San Benito 
Abad","state":"Sucre","country":"Colombia","country_code":"co"}},{"place_id":"6994858","licence":"Data \u00a9 
OpenStreetMap contributors, ODbL 1.0. 
http:\/\/www.openstreetmap.org\/copyright","osm_type":"node","osm_id":"703211142","boundingbox":["9.87247943878174","9.87248039245605","-75.1155700683594","-75.1155624389648"],"lat":"9.8724798","lon":"-75.1155676","di
 splay_name":"Rio De Janeiro, SAN JACINTO, San Jacinto, Bol\u00edvar, 
Colombia","class":"place","type":"locality","importance":0.75,"icon":"http:\/\/nominatim.openstreetmap.org\/images\/mapicons\/poi_place_village.p.20.png","address":{"locality":"Rio
 De Janeiro","town":"SAN JACINTO","county":"San 
Jacinto","state":"Bol\u00edvar","country":"Colombia","country_code":"co"}},{"place_id":"3667989646","licence":"Data
 \u00a9 OpenStreetMap contributors, ODbL 1.0. 
http:\/\/www.openstreetmap.org\/copyright","osm_type":"node","osm_id":"2018636173","boundingbox":["-20.4294261932373","-20.4294242858887","-54.5962409973145","-54.5962371826172"],"lat":"-20.4294254","lon":"-54.5962373","display_name":"Rio
 de Janeiro, Margarida, Campo Grande, Mato Grosso do Sul, 
Brazil","class":"place","type":"neighbourhood","importance":0.7,"address":{"neighbourhood":"Rio de 
Janeiro","suburb":"Margarida","city":"Campo Grande","state":"Mato Grosso do 
Sul","country":"Brazil","country_code":"br"}},{"place_id":"5
 2476926","licence":"Data \u00a9 OpenStreetMap contributors, ODbL 1.0. 
http:\/\/www.openstreetmap.org\/copyright","osm_type":"way","osm_id":"53901237","boundingbox":["-34.6154937744141","-34.6136207580566","-58.4301300048828","-58.4300575256348"],"lat":"-34.6139818","lon":"-58.4300707","display_name":"R\u00edo
 de Janeiro, Almagro, Autonomous City of Buenos Aires, 1208, 
Argentina","class":"highway","type":"residential","importance":0.63050715237377,"address":{"road":"R\u00edo 
de Janeiro","suburb":"Almagro","city_district":"Almagro","city":"Autonomous City of Buenos 
Aires","state":"Autonomous City of Buenos 
Aires","postcode":"1208","country":"Argentina","country_code":"ar"}}]
\ No newline at end of file
diff --git a/geocode-glib/geocode-forward.c b/geocode-glib/geocode-forward.c
index d4b5602..a28e165 100644
--- a/geocode-glib/geocode-forward.c
+++ b/geocode-glib/geocode-forward.c
@@ -82,241 +82,6 @@ geocode_forward_init (GeocodeForward *forward)
        forward->priv->answer_count = DEFAULT_ANSWER_COUNT;
 }
 
-static void
-set_is_search (GeocodeForward *forward,
-              GObject        *object)
-{
-       if (forward->priv->answer_count != 1)
-               g_object_set_data (object, "is-search", GINT_TO_POINTER (1));
-}
-
-static gboolean
-is_search (GObject *object)
-{
-       return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (object), "is-search"));
-}
-
-static struct {
-       const char *pf_attr;
-       const char *xep_attr;
-} rev_attrs_map[] = {
-       { "longitude", "longitude" },
-       { "latitude", "latitude" },
-       { "offsetlat", NULL },
-       { "offsetlon", NULL },
-       { "name", "description" },
-       { "line1", "building" },
-       { "line2", NULL },
-       { "line3", NULL },
-       { "line4", NULL },
-       { "street", "street" },
-       { "postal", "postalcode" },
-       { "neighborhood", "area" },
-       { "city", "locality" },
-       { "county", NULL },
-       { "state", "region" },
-       { "country", "country" },
-       { "countrycode", "countrycode" },
-       { "countycode", NULL },
-       { "timezone", NULL },
-       { "uzip", NULL },
-};
-
-static const char *
-pf_to_xep (const char *attr)
-{
-       guint i;
-
-       for (i = 0; i < G_N_ELEMENTS (rev_attrs_map); i++) {
-               if (g_str_equal (attr, rev_attrs_map[i].pf_attr))
-                       return rev_attrs_map[i].xep_attr;
-       }
-
-       g_debug ("Can't convert unknown attribute '%s'", attr);
-
-       return NULL;
-}
-
-GHashTable *
-_geocode_parse_resolve_json (const char *contents,
-                            GError    **error)
-{
-       GHashTable *ret;
-       JsonParser *parser;
-       JsonNode *root;
-       JsonReader *reader;
-       gint64 err_code, found;
-       guint i;
-       const GError *err = NULL;
-       char **members;
-
-       ret = NULL;
-
-       parser = json_parser_new ();
-       if (json_parser_load_from_data (parser, contents, -1, error) == FALSE) {
-               g_object_unref (parser);
-               return ret;
-       }
-
-       root = json_parser_get_root (parser);
-       reader = json_reader_new (root);
-
-       if (json_reader_read_member (reader, "ResultSet") == FALSE)
-               goto parse;
-
-       if (json_reader_read_member (reader, "Error") == FALSE)
-               goto parse;
-
-       err_code = json_reader_get_int_value (reader);
-       json_reader_end_member (reader);
-
-       if (err_code != 0) {
-               const char *msg;
-
-               json_reader_read_member (reader, "ErrorMessage");
-               msg = json_reader_get_string_value (reader);
-               json_reader_end_member (reader);
-               if (msg && *msg == '\0')
-                       msg = NULL;
-
-               switch (err_code) {
-               case 1:
-                       g_set_error_literal (error, GEOCODE_ERROR, GEOCODE_ERROR_NOT_SUPPORTED, msg ? msg : 
"Query not supported");
-                       break;
-               case 100:
-                       g_set_error_literal (error, GEOCODE_ERROR, GEOCODE_ERROR_NOT_SUPPORTED, msg ? msg : 
"No input parameters");
-                       break;
-               case 102:
-                       g_set_error_literal (error, GEOCODE_ERROR, GEOCODE_ERROR_NOT_SUPPORTED, msg ? msg : 
"Address data not recognized as valid UTF-8");
-                       break;
-               case 103:
-                       g_set_error_literal (error, GEOCODE_ERROR, GEOCODE_ERROR_NOT_SUPPORTED, msg ? msg : 
"Insufficient address data");
-                       break;
-               case 104:
-                       g_set_error_literal (error, GEOCODE_ERROR, GEOCODE_ERROR_NOT_SUPPORTED, msg ? msg : 
"Unknown language");
-                       break;
-               case 105:
-                       g_set_error_literal (error, GEOCODE_ERROR, GEOCODE_ERROR_NOT_SUPPORTED, msg ? msg : 
"No country detected");
-                       break;
-               case 106:
-                       g_set_error_literal (error, GEOCODE_ERROR, GEOCODE_ERROR_NOT_SUPPORTED, msg ? msg : 
"Country not supported");
-                       break;
-               default:
-                       if (msg == NULL)
-                               g_set_error (error, GEOCODE_ERROR, GEOCODE_ERROR_PARSE, "Unknown error code 
%"G_GINT64_FORMAT, err_code);
-                       else
-                               g_set_error_literal (error, GEOCODE_ERROR, GEOCODE_ERROR_PARSE, msg);
-                       break;
-               }
-               g_object_unref (parser);
-               g_object_unref (reader);
-               return NULL;
-       }
-
-       /* Check for the number of results */
-       if (json_reader_read_member (reader, "Found") == FALSE)
-               goto parse;
-
-       found = json_reader_get_int_value (reader);
-       json_reader_end_member (reader);
-
-       if (!found) {
-               g_set_error_literal (error, GEOCODE_ERROR, GEOCODE_ERROR_NO_MATCHES, "No matches found for 
request");
-               g_object_unref (parser);
-               g_object_unref (reader);
-               return NULL;
-       }
-
-       if (json_reader_read_member (reader, "Results") == FALSE)
-               goto parse;
-
-       if (json_reader_read_element (reader, 0) == FALSE)
-               goto parse;
-
-       members = json_reader_list_members (reader);
-
-       /* Yay, start adding data */
-       ret = g_hash_table_new_full (g_str_hash, g_str_equal,
-                                    g_free, g_free);
-
-       for (i = 0; members[i] != NULL; i++) {
-               const char *value;
-
-               json_reader_read_member (reader, members[i]);
-
-               if (g_str_equal (members[i], "radius") ||
-                   g_str_equal (members[i], "quality") ||
-                   g_str_equal (members[i], "woeid")) {
-                       gint64 num;
-
-                       num = json_reader_get_int_value (reader);
-                       g_hash_table_insert (ret, g_strdup (members[i]), g_strdup_printf ("%"G_GINT64_FORMAT, 
num));
-                       json_reader_end_member (reader);
-                       continue;
-               }
-
-               value = json_reader_get_string_value (reader);
-               if (value && *value == '\0')
-                       value = NULL;
-
-               if (value != NULL) {
-                       const char *xep_attr;
-
-                       xep_attr = pf_to_xep (members[i]);
-                       if (xep_attr != NULL)
-                               g_hash_table_insert (ret, g_strdup (xep_attr), g_strdup (value));
-                       else
-                               g_hash_table_insert (ret, g_strdup (members[i]), g_strdup (value));
-               }
-               json_reader_end_member (reader);
-       }
-       g_strfreev (members);
-
-       g_object_unref (parser);
-       g_object_unref (reader);
-
-       return ret;
-
-parse:
-       if (ret != NULL)
-               g_hash_table_destroy (ret);
-       err = json_reader_get_error (reader);
-       g_set_error_literal (error, GEOCODE_ERROR, GEOCODE_ERROR_PARSE, err->message);
-       g_object_unref (parser);
-       g_object_unref (reader);
-       return NULL;
-}
-
-static GList *
-_geocode_parse_single_result_json (const char  *contents,
-                                  GError     **error)
-{
-       GHashTable *ht;
-        GeocodePlace *place = NULL;
-        const char *name;
-       GeocodeLocation *loc;
-       gdouble longitude;
-       gdouble latitude;
-
-       ht = _geocode_parse_resolve_json (contents, error);
-       if (ht == NULL)
-               return NULL;
-
-       longitude = g_ascii_strtod (g_hash_table_lookup (ht, "longitude"), NULL);
-       latitude = g_ascii_strtod (g_hash_table_lookup (ht, "latitude"), NULL);
-        name = g_hash_table_lookup (ht, "line2");
-        loc = geocode_location_new_with_description (longitude,
-                                                     latitude,
-                                                     GEOCODE_LOCATION_ACCURACY_UNKNOWN,
-                                                     name);
-        place = geocode_place_new_with_location (name, GEOCODE_PLACE_TYPE_UNKNOWN, loc);
-
-        g_object_unref (loc);
-       g_hash_table_destroy (ht);
-
-        return g_list_append (NULL, place);
-}
-
 static struct {
        const char *tp_attr;
        const char *gc_attr; /* NULL to ignore */
@@ -324,17 +89,18 @@ static struct {
        { "countrycode", NULL },
        { "country", "country" },
        { "region", "state" },
+       { "county", "county" },
        { "locality", "city" },
-       { "area", "neighborhood" },
-       { "postalcode", "postal" },
+       { "area", NULL },
+       { "postalcode", "postalcode" },
        { "street", "street" },
-       { "building", "house" },
+       { "building", NULL },
        { "floor", NULL },
-       { "room", "unit" },
+       { "room",  NULL },
        { "text", NULL },
        { "description", NULL },
        { "uri", NULL },
-       { "language", "locale" },
+       { "language", "accept-language" },
 };
 
 static const char *
@@ -395,8 +161,6 @@ geocode_forward_fill_params (GeocodeForward *forward,
  *
  * See also: <ulink url="http://xmpp.org/extensions/xep-0080.html";>XEP-0080 specification</ulink>.
  *
- * Note that you will get exactly one result when doing the search.
- *
  * Returns: a new #GeocodeForward. Use g_object_unref() when done.
  **/
 GeocodeForward *
@@ -413,7 +177,6 @@ geocode_forward_new_for_params (GHashTable *params)
 
        forward = g_object_new (GEOCODE_TYPE_FORWARD, NULL);
        geocode_forward_fill_params (forward, params);
-       geocode_forward_set_answer_count (forward, 1);
 
        return forward;
 }
@@ -474,10 +237,7 @@ on_query_data_loaded (SoupSession *session,
        }
 
         contents = g_strndup (query->response_body->data, query->response_body->length);
-       if (is_search (G_OBJECT (query)))
-               ret = _geocode_parse_search_json (contents, &error);
-       else
-               ret = _geocode_parse_single_result_json (contents, &error);
+        ret = _geocode_parse_search_json (contents, &error);
 
        if (ret == NULL) {
                g_simple_async_result_take_error (simple, error);
@@ -519,8 +279,6 @@ on_cache_data_loaded (GObject      *source_forward,
 
                 object = g_async_result_get_source_object (G_ASYNC_RESULT (simple));
                query = g_object_get_data (G_OBJECT (cache), "query");
-               g_object_set_data (G_OBJECT (query), "is-search",
-                                  g_object_get_data (G_OBJECT (cache), "is-search"));
                 g_object_ref (query); /* soup_session_queue_message steals ref */
                soup_session_queue_message (GEOCODE_FORWARD (object)->priv->soup_session,
                                             query,
@@ -529,10 +287,7 @@ on_cache_data_loaded (GObject      *source_forward,
                return;
        }
 
-       if (is_search (G_OBJECT (cache)))
-               ret = _geocode_parse_search_json (contents, &error);
-       else
-               ret = _geocode_parse_single_result_json (contents, &error);
+        ret = _geocode_parse_search_json (contents, &error);
        g_free (contents);
 
        if (ret == NULL)
@@ -554,66 +309,69 @@ get_search_query_for_params (GeocodeForward *forward,
        char *params;
        char *search_term;
        char *uri;
-       const char *location;
+        guint8 i;
+        gboolean query_possible = FALSE;
+        char *location;
+        const char *allowed_attributes[] = { "country",
+                                             "region",
+                                             "county",
+                                             "locality",
+                                             "postalcode",
+                                             "street",
+                                             "location",
+                                             NULL };
+
+        /* Make sure we have at least one parameter that Nominatim allows querying for */
+       for (i = 0; allowed_attributes[i] != NULL; i++) {
+               if (g_hash_table_lookup (forward->priv->ht,
+                                         allowed_attributes[i]) != NULL) {
+                       query_possible = TRUE;
+                       break;
+               }
+       }
+
+        if (!query_possible) {
+                char *str;
+
+                str = g_strjoinv (", ", (char **) allowed_attributes);
+                g_set_error (error, GEOCODE_ERROR, GEOCODE_ERROR_INVALID_ARGUMENTS,
+                             "Only following parameters supported: %s", str);
+                g_free (str);
 
-       location = g_hash_table_lookup (forward->priv->ht, "location");
-       if (location == NULL) {
-               g_set_error_literal (error, GEOCODE_ERROR, GEOCODE_ERROR_INVALID_ARGUMENTS,
-                                    "No location argument set");
                return NULL;
        }
 
-       /* Prepare the search term */
-       search_term = soup_uri_encode (location, NULL);
-
        /* Prepare the query parameters */
-       ht = g_hash_table_new (g_str_hash, g_str_equal);
-       g_hash_table_insert (ht, "appid", YAHOO_APPID);
+       ht = _geocode_glib_dup_hash_table (forward->priv->ht);
        g_hash_table_insert (ht, "format", "json");
-       lang = _geocode_object_get_lang ();
-       if (lang)
-               g_hash_table_insert (ht, "lang", lang);
-
-       params = soup_form_encode_hash (ht);
-       g_hash_table_destroy (ht);
-       g_free (lang);
-
-       uri = g_strdup_printf ("http://where.yahooapis.com/v1/places.q('%s');start=0;count=%u?%s",
-                              search_term, forward->priv->answer_count, params);
-       g_free (params);
-       g_free (search_term);
-
-       ret = soup_message_new ("GET", uri);
-       g_free (uri);
-
-       return ret;
-}
-
-static SoupMessage *
-get_resolve_query_for_params (GHashTable  *orig_ht)
-{
-       SoupMessage *ret;
-       GHashTable *ht;
-       char *locale;
-       char *params, *uri;
-
-       ht = _geocode_glib_dup_hash_table (orig_ht);
-
-       g_hash_table_insert (ht, "appid", YAHOO_APPID);
-       g_hash_table_insert (ht, "flags", "QJT");
-
-       locale = NULL;
-       if (g_hash_table_lookup (ht, "locale") == NULL) {
-               locale = _geocode_object_get_lang ();
-               if (locale)
-                       g_hash_table_insert (ht, "locale", locale);
+       g_hash_table_insert (ht, "email", "zeeshanak gnome org");
+       g_hash_table_insert (ht, "addressdetails", "1");
+
+       lang = NULL;
+       if (g_hash_table_lookup (ht, "accept-language") == NULL) {
+               lang = _geocode_object_get_lang ();
+               if (lang)
+                       g_hash_table_insert (ht, "accept-language", lang);
        }
 
+        location = g_strdup (g_hash_table_lookup (ht, "location"));
+        g_hash_table_remove (ht, "location");
        params = soup_form_encode_hash (ht);
        g_hash_table_destroy (ht);
-       g_free (locale);
-
-       uri = g_strdup_printf ("http://where.yahooapis.com/geocode?%s";, params);
+        if (lang)
+                g_free (lang);
+
+        if (location != NULL) {
+               /* Prepare the search term */
+                search_term = soup_uri_encode (location, NULL);
+                uri = g_strdup_printf ("http://nominatim.openstreetmap.org/search?q=%s&limit=%u&%s";,
+                                       search_term, forward->priv->answer_count, params);
+                g_free (search_term);
+                g_free (location);
+        } else {
+                uri = g_strdup_printf ("http://nominatim.openstreetmap.org/search?limit=1&%s";,
+                                       params);
+        }
        g_free (params);
 
        ret = soup_message_new ("GET", uri);
@@ -654,10 +412,7 @@ geocode_forward_search_async (GeocodeForward      *forward,
                                            user_data,
                                            geocode_forward_search_async);
 
-       if (forward->priv->answer_count != 1)
-               query = get_search_query_for_params (forward, &error);
-       else
-               query = get_resolve_query_for_params (forward->priv->ht);
+        query = get_search_query_for_params (forward, &error);
        if (!query) {
                g_simple_async_result_take_error (simple, error);
                g_simple_async_result_complete_in_idle (simple);
@@ -667,7 +422,6 @@ geocode_forward_search_async (GeocodeForward      *forward,
 
        cache_path = _geocode_glib_cache_path_for_query (query);
        if (cache_path == NULL) {
-               set_is_search (forward, G_OBJECT (query));
                soup_session_queue_message (forward->priv->soup_session,
                                             query,
                                            on_query_data_loaded,
@@ -676,7 +430,6 @@ geocode_forward_search_async (GeocodeForward      *forward,
                GFile *cache;
 
                cache = g_file_new_for_path (cache_path);
-               set_is_search (forward, G_OBJECT (cache));
                g_object_set_data_full (G_OBJECT (cache), "query", query, (GDestroyNotify) g_object_unref);
                g_file_load_contents_async (cache,
                                            cancellable,
@@ -715,90 +468,29 @@ geocode_forward_search_finish (GeocodeForward       *forward,
        return g_simple_async_result_get_op_res_gpointer (simple);
 }
 
-#define IS_EL(x) (g_str_equal (element_name, x))
-
-static void
-insert_place_attr (GHashTable *ht,
-                  JsonReader *reader,
-                  const char *element_name)
-{
-       char *value;
-
-       if (json_reader_read_member (reader, element_name) == FALSE) {
-               json_reader_end_member (reader);
-               return;
-       }
-
-       /* FIXME: check all the member names against what Place Finder outputs */
-
-       if (IS_EL("woeid") ||
-           IS_EL("popRank") ||
-           IS_EL("areaRank")) {
-               value = g_strdup_printf ("%"G_GINT64_FORMAT, json_reader_get_int_value (reader));
-       } else if (IS_EL("centroid")) {
-               char str[16];
-
-               json_reader_read_member (reader, "longitude");
-               g_ascii_dtostr (str, sizeof(str), json_reader_get_double_value (reader));
-               g_hash_table_insert (ht, g_strdup ("longitude"), g_strdup (str));
-               json_reader_end_member (reader);
-
-               json_reader_read_member (reader, "latitude");
-               g_ascii_dtostr (str, sizeof(str), json_reader_get_double_value (reader));
-               g_hash_table_insert (ht, g_strdup ("latitude"), g_strdup (str));
-               json_reader_end_member (reader);
-               goto end;
-       } else if (g_str_has_suffix (element_name, " attrs")) {
-                if (IS_EL("placeTypeName attrs")) {
-                        char *code;
-
-                        json_reader_read_member (reader, "code");
-                        code = g_strdup_printf ("%" G_GINT64_FORMAT,
-                                                json_reader_get_int_value (reader));
-                        g_hash_table_insert (ht, g_strdup ("placeType"), code);
-                        json_reader_end_member (reader);
-                        goto end;
-                } else {
-                        g_debug ("Ignoring attributes element '%s'", element_name);
-                        value = g_strdup (""); /* So that they're ignored */
-                }
-       } else if (IS_EL("boundingBox")) {
-               g_debug ("Ignoring element '%s'", element_name);
-               value = g_strdup (""); /* So that they're ignored */
-        } else if (IS_EL("placeTypeName")) {
-                /* This string is also localized so we want the code rather
-                 * than name, so we ignore name and extract the code above.
-                 */
-                g_debug ("Ignoring element '%s'", element_name);
-                value = g_strdup (""); /* So that they're ignored */
-       } else {
-               value = g_strdup (json_reader_get_string_value (reader));
-       }
-
-       if (value != NULL && *value == '\0') {
-               g_clear_pointer (&value, g_free);
-               goto end;
-       }
-
-       if (value != NULL)
-               g_hash_table_insert (ht, g_strdup (element_name), value);
-       else
-               g_warning ("Ignoring element %s, don't know how to parse it", element_name);
-
-end:
-       json_reader_end_member (reader);
-}
-
 static struct {
-        const char *yahoo_attr;
+       const char *nominatim_attr;
         const char *place_prop; /* NULL to ignore */
-} yahoo_to_place_map[] = {
-        { "postal", "postal-code" },
-        { "locality1", "town" },
-        { "admin1", "state" },
-        { "admin2", "county" },
-        { "admin3", "administrative-area" },
+} nominatim_to_place_map[] = {
+        { "license", NULL },
+        { "osm_type", NULL },
+        { "osm_id", NULL },
+        { "lat", NULL },
+        { "lon", NULL },
+        { "display_name", NULL },
+        { "house_number", "building" },
+        { "road", "street" },
+        { "suburb", "area" },
+        { "city",  "town" },
+        { "village",  "town" },
+        { "county", "county" },
+        { "state_district", "administrative-area" },
+        { "state", "state" },
+        { "postcode", "postal-code" },
         { "country", "country" },
+        { "country_code", "country-code" },
+        { "continent", "continent" },
+        { "address", NULL },
 };
 
 static void
@@ -808,10 +500,10 @@ fill_place_from_entry (const char   *key,
 {
         guint i;
 
-        for (i = 0; i < G_N_ELEMENTS (yahoo_to_place_map); i++) {
-                if (g_str_equal (key, yahoo_to_place_map[i].yahoo_attr)){
+        for (i = 0; i < G_N_ELEMENTS (nominatim_to_place_map); i++) {
+                if (g_str_equal (key, nominatim_to_place_map[i].nominatim_attr)){
                         g_object_set (G_OBJECT (place),
-                                      yahoo_to_place_map[i].place_prop,
+                                      nominatim_to_place_map[i].place_prop,
                                       value,
                                       NULL);
                         break;
@@ -831,26 +523,132 @@ node_free_func (GNode    *node,
        return FALSE;
 }
 
-#define N_ATTRS 7
-static const char const *attributes[7] = {
+#define N_ATTRS 8
+static const char const *attributes[8] = {
        "country",
-       "admin1",
-       "admin2",
-       "admin3",
-       "postal",
-       "placeTypeName",
-       "locality1"
+       "state",
+       "county",
+       "state_district",
+       "postalcode",
+       "city",
+       "suburb",
+       "village",
 };
 
+static GeocodePlace *
+create_place_from_attributes (GHashTable *ht)
+{
+        GeocodePlace *place;
+        char *class, *type;
+        const char *name, *street, *building;
+        GeocodePlaceType place_type = GEOCODE_PLACE_TYPE_UNKNOWN;
+
+        class = g_hash_table_lookup (ht, "class");
+        type = g_hash_table_lookup (ht, "type");
+
+        if (g_strcmp0 (class, "place") == 0) {
+                if (g_strcmp0 (type, "house") == 0 ||
+                    g_strcmp0 (type, "building") == 0 ||
+                    g_strcmp0 (type, "residential") == 0 ||
+                    g_strcmp0 (type, "plaza") == 0 ||
+                    g_strcmp0 (type, "office") == 0)
+                        place_type =  GEOCODE_PLACE_TYPE_BUILDING;
+                else if (g_strcmp0 (type, "estate") == 0)
+                        place_type =  GEOCODE_PLACE_TYPE_ESTATE;
+                else if (g_strcmp0 (type, "town") == 0 ||
+                         g_strcmp0 (type, "city") == 0 ||
+                         g_strcmp0 (type, "hamlet") == 0 ||
+                         g_strcmp0 (type, "isolated_dwelling") == 0 ||
+                         g_strcmp0 (type, "village") == 0)
+                        place_type =  GEOCODE_PLACE_TYPE_TOWN;
+                else if (g_strcmp0 (type, "suburb") == 0 ||
+                         g_strcmp0 (type, "neighbourhood") == 0)
+                        place_type =  GEOCODE_PLACE_TYPE_SUBURB;
+                else if (g_strcmp0 (type, "state") == 0 ||
+                         g_strcmp0 (type, "region") == 0)
+                        place_type =  GEOCODE_PLACE_TYPE_STATE;
+                else if (g_strcmp0 (type, "farm") == 0 ||
+                         g_strcmp0 (type, "forest") == 0 ||
+                         g_strcmp0 (type, "valey") == 0 ||
+                         g_strcmp0 (type, "park") == 0 ||
+                         g_strcmp0 (type, "hill") == 0)
+                        place_type =  GEOCODE_PLACE_TYPE_LAND_FEATURE;
+                else if (g_strcmp0 (type, "island") == 0 ||
+                         g_strcmp0 (type, "islet") == 0)
+                        place_type =  GEOCODE_PLACE_TYPE_ISLAND;
+                else if (g_strcmp0 (type, "country") == 0)
+                        place_type =  GEOCODE_PLACE_TYPE_COUNTRY;
+                else if (g_strcmp0 (type, "continent") == 0)
+                        place_type =  GEOCODE_PLACE_TYPE_CONTINENT;
+                else if (g_strcmp0 (type, "lake") == 0 ||
+                         g_strcmp0 (type, "bay") == 0 ||
+                         g_strcmp0 (type, "river") == 0)
+                        place_type =  GEOCODE_PLACE_TYPE_DRAINAGE;
+                else if (g_strcmp0 (type, "sea") == 0)
+                        place_type =  GEOCODE_PLACE_TYPE_SEA;
+                else if (g_strcmp0 (type, "ocean") == 0)
+                        place_type =  GEOCODE_PLACE_TYPE_OCEAN;
+        } else if (g_strcmp0 (class, "highway") == 0) {
+                if (g_strcmp0 (type, "motorway") == 0)
+                        place_type =  GEOCODE_PLACE_TYPE_MOTORWAY;
+                else if (g_strcmp0 (type, "bus_stop") == 0)
+                        place_type =  GEOCODE_PLACE_TYPE_BUS_STOP;
+                else
+                        place_type =  GEOCODE_PLACE_TYPE_STREET;
+        } else if (g_strcmp0 (class, "railway") == 0) {
+                if (g_strcmp0 (type, "station") == 0)
+                        place_type =  GEOCODE_PLACE_TYPE_RAILWAY_STATION;
+        } else if (g_strcmp0 (class, "waterway") == 0) {
+                place_type =  GEOCODE_PLACE_TYPE_DRAINAGE;
+        } else if (g_strcmp0 (class, "boundry") == 0) {
+                if (g_strcmp0 (type, "administrative") == 0) {
+                        int rank;
+
+                        rank = atoi (g_hash_table_lookup (ht, "place_rank"));
+                        if (rank < 2)
+                                place_type =  GEOCODE_PLACE_TYPE_UNKNOWN;
+
+                        if (rank == 28)
+                                place_type =  GEOCODE_PLACE_TYPE_BUILDING;
+                        else if (rank == 16)
+                                place_type =  GEOCODE_PLACE_TYPE_TOWN;
+                        else if (rank == 12)
+                                place_type =  GEOCODE_PLACE_TYPE_COUNTY;
+                        else if (rank == 10 || rank == 8)
+                                place_type =  GEOCODE_PLACE_TYPE_STATE;
+                        else if (rank == 4)
+                                place_type =  GEOCODE_PLACE_TYPE_COUNTRY;
+                }
+        }
+
+        name = g_hash_table_lookup (ht, "name");
+        if (name == NULL)
+                name = g_hash_table_lookup (ht, "display_name");
+
+        place = geocode_place_new (name, place_type);
+
+        /* Nominatim doesn't give us street addresses as such */
+        street = g_hash_table_lookup (ht, "road");
+        building = g_hash_table_lookup (ht, "house_number");
+        if (street != NULL && building != NULL) {
+            char *address;
+
+            address = g_strjoin (" ", street, building, NULL);
+            geocode_place_set_street_address (place, address);
+            g_free (address);
+        }
+
+        return place;
+}
+
 static void
 insert_place_into_tree (GNode *place_tree, GHashTable *ht)
 {
        GNode *start = place_tree, *child = NULL;
-        GeocodePlaceType place_type;
         GeocodePlace *place = NULL;
        GeocodeLocation *loc = NULL;
        char *attr_val = NULL;
-       char *name;
+       const char *name;
        gdouble longitude, latitude;
        guint i;
 
@@ -877,25 +675,16 @@ insert_place_into_tree (GNode *place_tree, GHashTable *ht)
                start = child;
        }
 
-        name = g_hash_table_lookup (ht, "name");
-        place_type = atoi (g_hash_table_lookup (ht, "placeType"));
-        place = geocode_place_new (name, place_type);
+        place = create_place_from_attributes (ht);
 
         g_hash_table_foreach (ht, (GHFunc) fill_place_from_entry, place);
 
-        /* Yahoo API doesn't give us street addresses so we'll just have to
-         * live with only street name for now. */
-        if (place_type == GEOCODE_PLACE_TYPE_SUBURB) {
-                const char *street = g_hash_table_lookup (ht, "locality2");
-                if (street != NULL)
-                        geocode_place_set_street_address (place, street);
-        }
-
        /* Get latitude and longitude and create GeocodeLocation object.
         * The leaf node of the tree is the GeocodePlace object, containing
          * associated GeocodeLocation object */
-       longitude = g_ascii_strtod (g_hash_table_lookup (ht, "longitude"), NULL);
-       latitude = g_ascii_strtod (g_hash_table_lookup (ht, "latitude"), NULL);
+       longitude = g_ascii_strtod (g_hash_table_lookup (ht, "lon"), NULL);
+       latitude = g_ascii_strtod (g_hash_table_lookup (ht, "lat"), NULL);
+        name = geocode_place_get_name (place);
 
        loc = geocode_location_new_with_description (latitude,
                                                  longitude,
@@ -914,7 +703,6 @@ make_place_list_from_tree (GNode  *node,
                            int     i)
 {
        GNode *child;
-       gboolean add_attribute = FALSE;
 
        if (node == NULL)
                return;
@@ -923,8 +711,7 @@ make_place_list_from_tree (GNode  *node,
                GPtrArray *rev_s_array;
                GeocodePlace *place;
                GeocodeLocation *loc;
-               const char *name;
-               char *description;
+               char *name;
                int counter = 0;
 
                rev_s_array = g_ptr_array_new ();
@@ -932,33 +719,34 @@ make_place_list_from_tree (GNode  *node,
                /* If leaf node, then add all the attributes in the s_array
                 * and set it to the description of the loc object */
                place = (GeocodePlace *) node->data;
+               name = (char *) geocode_place_get_name (place);
                loc = geocode_place_get_location (place);
 
-               name = geocode_location_get_description (loc);
-
                /* To print the attributes in a meaningful manner
                 * reverse the s_array */
                g_ptr_array_add (rev_s_array, (gpointer) name);
                for (counter = 1; counter <= i; counter++)
                        g_ptr_array_add (rev_s_array, s_array[i - counter]);
                g_ptr_array_add (rev_s_array, NULL);
-               description = g_strjoinv (", ", (char **) rev_s_array->pdata);
+               name = g_strjoinv (", ", (char **) rev_s_array->pdata);
                g_ptr_array_unref (rev_s_array);
 
-               geocode_location_set_description (loc, description);
-               g_free (description);
+               geocode_place_set_name (place, name);
+               geocode_location_set_description (loc, name);
+               g_free (name);
 
                *place_list = g_list_prepend (*place_list, place);
        } else {
+                GNode *prev, *next;
+
+                prev = g_node_prev_sibling (node);
+                next = g_node_next_sibling (node);
+
                /* If there are other attributes with a different value,
                 * add those attributes to the string to differentiate them */
-               if (g_node_prev_sibling (node) ||
-                  g_node_next_sibling (node))
-                       add_attribute = TRUE;
-
-               if (add_attribute) {
-                       s_array[i] = node->data;
-                       i++;
+               if (node->data && ((prev && prev->data) || (next && next->data))) {
+                        s_array[i] = node->data;
+                        i++;
                }
        }
 
@@ -990,36 +778,32 @@ _geocode_parse_search_json (const char *contents,
        root = json_parser_get_root (parser);
        reader = json_reader_new (root);
 
-       if (json_reader_read_member (reader, "places") == FALSE)
-               goto parse;
-       if (json_reader_read_member (reader, "place") == FALSE)
-               goto parse;
-
        num_places = json_reader_count_elements (reader);
        if (num_places < 0)
                goto parse;
+        if (num_places == 0) {
+               g_set_error_literal (error,
+                                     GEOCODE_ERROR,
+                                     GEOCODE_ERROR_NO_MATCHES,
+                                     "No matches found for request");
+               goto no_results;
+        }
 
        place_tree = g_node_new (NULL);
 
        for (i = 0; i < num_places; i++) {
                GHashTable *ht;
-               char **members;
-               int j;
 
                json_reader_read_element (reader, i);
 
-               ht = g_hash_table_new_full (g_str_hash, g_str_equal,
-                                           g_free, g_free);
-
-               members = json_reader_list_members (reader);
-               for (j = 0; members != NULL && members[j] != NULL; j++)
-                       insert_place_attr (ht, reader, members[j]);
+                ht = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                           g_free, g_free);
+                _geocode_read_nominatim_attributes (reader, ht, FALSE);
 
                /* Populate the tree with place details */
                insert_place_into_tree (place_tree, ht);
 
                g_hash_table_destroy (ht);
-               g_strfreev (members);
 
                json_reader_end_element (reader);
        }
@@ -1043,6 +827,7 @@ _geocode_parse_search_json (const char *contents,
 parse:
        err = json_reader_get_error (reader);
        g_set_error_literal (error, GEOCODE_ERROR, GEOCODE_ERROR_PARSE, err->message);
+no_results:
        g_object_unref (parser);
        g_object_unref (reader);
        return NULL;
@@ -1071,11 +856,7 @@ geocode_forward_search (GeocodeForward      *forward,
 
        g_return_val_if_fail (GEOCODE_IS_FORWARD (forward), NULL);
 
-       if (forward->priv->answer_count != 1)
-               query = get_search_query_for_params (forward, error);
-       else
-               query = get_resolve_query_for_params (forward->priv->ht);
-
+        query = get_search_query_for_params (forward, error);
        if (!query)
                return NULL;
 
@@ -1095,10 +876,7 @@ geocode_forward_search (GeocodeForward      *forward,
                to_cache = TRUE;
        }
 
-       if (forward->priv->answer_count != 1)
-               ret = _geocode_parse_search_json (contents, error);
-       else
-               ret = _geocode_parse_single_result_json (contents, error);
+        ret = _geocode_parse_search_json (contents, error);
        if (to_cache && ret != NULL)
                _geocode_glib_cache_save (query, contents);
 
diff --git a/geocode-glib/geocode-glib-private.h b/geocode-glib/geocode-glib-private.h
index c8f461f..b0409ea 100644
--- a/geocode-glib/geocode-glib-private.h
+++ b/geocode-glib/geocode-glib-private.h
@@ -25,6 +25,7 @@
 
 #include <glib.h>
 #include <libsoup/soup.h>
+#include <json-glib/json-glib.h>
 #include <geocode-glib/geocode-location.h>
 
 G_BEGIN_DECLS
@@ -37,12 +38,14 @@ typedef enum {
        GEOCODE_GLIB_RESOLVE_REVERSE
 } GeocodeLookupType;
 
-GHashTable *_geocode_parse_resolve_json (const char *contents,
-                                        GError    **error);
 GList      *_geocode_parse_search_json  (const char *contents,
                                         GError    **error);
 GeocodeLocation *_geocode_ip_json_to_location (const char  *json,
                                               GError     **error);
+void
+_geocode_read_nominatim_attributes (JsonReader *reader,
+                                    GHashTable *ht,
+                                    gboolean    translate_to_xep);
 
 char       *_geocode_object_get_lang (void);
 
diff --git a/geocode-glib/geocode-glib.symbols b/geocode-glib/geocode-glib.symbols
index 0bf7a93..1604295 100644
--- a/geocode-glib/geocode-glib.symbols
+++ b/geocode-glib/geocode-glib.symbols
@@ -24,6 +24,7 @@ geocode_error_quark
 geocode_error_get_type
 _geocode_parse_search_json
 _geocode_parse_resolve_json
+_geocode_read_nominatim_attributes
 _geocode_ip_json_to_location
 geocode_ipclient_get_type
 geocode_ipclient_new
diff --git a/geocode-glib/geocode-place.c b/geocode-glib/geocode-place.c
index fe1cdf2..d4e3886 100644
--- a/geocode-glib/geocode-place.c
+++ b/geocode-glib/geocode-place.c
@@ -550,10 +550,7 @@ geocode_place_set_name (GeocodePlace *place,
  * geocode_place_get_name:
  * @place: A place
  *
- * Gets the name of the @place. This is simply a short name. You want to read
- * the #GeocodeLocation:description property from the associated
- * #GeocodeLocation object to get unique names for each place object in
- * geocode_forward_search() results.
+ * Gets the name of the @place.
  **/
 const char *
 geocode_place_get_name (GeocodePlace *place)
diff --git a/geocode-glib/geocode-reverse.c b/geocode-glib/geocode-reverse.c
index ed7a9da..937acd8 100644
--- a/geocode-glib/geocode-reverse.c
+++ b/geocode-glib/geocode-reverse.c
@@ -142,11 +142,16 @@ nominatim_to_xep (const char *attr)
        return NULL;
 }
 
-static void
-add_nominatim_attributes (JsonReader *reader, GHashTable *hash_table)
+void
+_geocode_read_nominatim_attributes (JsonReader *reader,
+                                    GHashTable *ht,
+                                    gboolean    translate_to_xep)
 {
        char **members;
        guint i;
+        gboolean is_address;
+
+       is_address = (g_strcmp0 (json_reader_get_member_name (reader), "address") == 0);
 
        members = json_reader_list_members (reader);
 
@@ -162,17 +167,33 @@ add_nominatim_attributes (JsonReader *reader, GHashTable *hash_table)
                 if (value != NULL) {
                         const char *xep_attr;
 
-                        xep_attr = nominatim_to_xep (members[i]);
+                        if (translate_to_xep)
+                            xep_attr = nominatim_to_xep (members[i]);
+                        else
+                            xep_attr = NULL;
+
                         if (xep_attr != NULL)
-                                g_hash_table_insert (hash_table, g_strdup (xep_attr), g_strdup (value));
+                                g_hash_table_insert (ht, g_strdup (xep_attr), g_strdup (value));
                         else
-                                g_hash_table_insert (hash_table, g_strdup (members[i]), g_strdup (value));
+                                g_hash_table_insert (ht, g_strdup (members[i]), g_strdup (value));
+
+                        if (i == 0 && is_address) {
+                                /* Since Nominatim doesn't give us a short name,
+                                 * we use the first component of address as name.
+                                 */
+                                g_hash_table_insert (ht, g_strdup ("name"), g_strdup (value));
+                        }
                 }
 
                 json_reader_end_member (reader);
         }
 
        g_strfreev (members);
+
+       if (json_reader_read_member (reader, "address")) {
+                _geocode_read_nominatim_attributes (reader, ht, translate_to_xep);
+                json_reader_end_member (reader);
+        }
 }
 
 static GHashTable *
@@ -212,16 +233,10 @@ resolve_json (const char *contents,
                return NULL;
        }
 
-       /* Yay, start adding data */
        ret = g_hash_table_new_full (g_str_hash, g_str_equal,
                                     g_free, g_free);
 
-        add_nominatim_attributes (reader, ret);
-
-       if (json_reader_read_member (reader, "address")) {
-                add_nominatim_attributes (reader, ret);
-                json_reader_end_member (reader);
-        }
+        _geocode_read_nominatim_attributes (reader, ret, TRUE);
 
        g_object_unref (parser);
        g_object_unref (reader);
diff --git a/geocode-glib/test-gcglib.c b/geocode-glib/test-gcglib.c
index 0f44075..8e1a799 100644
--- a/geocode-glib/test-gcglib.c
+++ b/geocode-glib/test-gcglib.c
@@ -153,13 +153,15 @@ test_xep (void)
 
        tp = g_hash_table_new_full (g_str_hash, g_str_equal,
                                    g_free, g_free);
-       add_attr (tp, "country", "UK");
-       add_attr (tp, "region", "Surrey");
+        /* FIXME: Remove this comment & uncomment following line once this ticket is resolved:
+         *        https://trac.openstreetmap.org/ticket/4918
+         */
+       /*add_attr (tp, "country", "United Kingdom");*/
+       add_attr (tp, "region", "England");
+       add_attr (tp, "county", "Surrey");
        add_attr (tp, "locality", "Guildford");
-       add_attr (tp, "postalcode", "GU2 7");
-       add_attr (tp, "street", "Old Palace Rd");
-       add_attr (tp, "building", "9");
-       add_attr (tp, "description", "My local pub");
+       add_attr (tp, "postalcode", "GU2 7UP");
+       add_attr (tp, "street", "Old Palace Road");
 
        object = geocode_forward_new_for_params (tp);
        g_assert (object != NULL);
@@ -177,8 +179,8 @@ test_xep (void)
        place = res->data;
        loc = geocode_place_get_location (place);
        g_assert (loc != NULL);
-       g_assert_cmpfloat (geocode_location_get_latitude (loc), ==, 51.237070);
-       g_assert_cmpfloat (geocode_location_get_longitude (loc), ==, -0.589669);
+       g_assert_cmpfloat (geocode_location_get_latitude (loc), ==, 51.2371416);
+       g_assert_cmpfloat (geocode_location_get_longitude (loc), ==, -0.5894089);
 
        g_object_unref (place);
        g_list_free (res);
@@ -209,8 +211,8 @@ test_pub (void)
        loc = geocode_place_get_location (place);
        g_assert (loc != NULL);
 
-       g_assert_cmpfloat (geocode_location_get_latitude (loc), ==, 51.237070);
-       g_assert_cmpfloat (geocode_location_get_longitude (loc), ==, -0.589669);
+       g_assert_cmpfloat (geocode_location_get_latitude (loc), ==, 51.2371416);
+       g_assert_cmpfloat (geocode_location_get_longitude (loc), ==, -0.5894089);
 
        g_object_unref (place);
        g_list_free (res);
@@ -229,7 +231,6 @@ test_search (void)
        setlocale (LC_MESSAGES, "en_GB.UTF-8");
 
        forward = geocode_forward_new_for_string ("paris");
-       geocode_forward_set_answer_count (forward, 0);
        results = geocode_forward_search (forward, &error);
        if (results == NULL) {
                g_warning ("Failed at geocoding: %s", error->message);
@@ -239,7 +240,7 @@ test_search (void)
 
        g_object_unref (forward);
 
-       g_assert_cmpint (g_list_length (results), ==, 38);
+       g_assert_cmpint (g_list_length (results), ==, 10);
 
        /* We need to find Paris in France and in Texas */
        got_france = FALSE;
@@ -247,18 +248,20 @@ test_search (void)
        for (l = results; l != NULL; l = l->next) {
                GeocodeLocation *loc;
                GeocodePlace *place = l->data;
-               g_assert (g_strcmp0 (geocode_place_get_name (place), "Paris") == 0);
 
                loc = geocode_place_get_location (place);
                g_assert (loc != NULL);
 
                if (g_strcmp0 (geocode_place_get_state (place), "Ile-de-France") == 0 &&
                    g_strcmp0 (geocode_place_get_country (place), "France") == 0 &&
+                   g_strcmp0 (geocode_place_get_name (place), "Paris, France") == 0 &&
                    g_strcmp0 (geocode_location_get_description (loc), "Paris, France") == 0)
                        got_france = TRUE;
                else if (g_strcmp0 (geocode_place_get_state (place), "Texas") == 0 &&
-                        g_strcmp0 (geocode_place_get_country (place), "United States") == 0 &&
-                        g_strcmp0 (geocode_location_get_description (loc), "Paris, Texas, United States") == 
0)
+                        g_strcmp0 (geocode_place_get_country (place), "United States of America") == 0 &&
+                        g_strcmp0 (geocode_place_get_name (place), "Paris, Texas, United States of America") 
== 0 &&
+                        g_strcmp0 (geocode_location_get_description (loc),
+                                    "Paris, Texas, United States of America") == 0)
                        got_texas = TRUE;
 
                g_object_unref (place);
@@ -293,16 +296,16 @@ test_search_lat_long (void)
        g_assert (res != NULL);
        g_object_unref (object);
 
-       place = res->data;
+        /* Nominatim puts the Spanish city on the top & we want the Mexican one */
+       place = res->next->data;
        loc = geocode_place_get_location (place);
        g_assert (loc != NULL);
 
-       g_assert_cmpfloat (geocode_location_get_latitude (loc) - 21.800699, <, 0.000001);
-       g_assert_cmpfloat (geocode_location_get_longitude (loc) - -100.735626, <, 0.000001);
-       g_assert_cmpstr (geocode_place_get_name (place), ==, "Santa Maria Del Rio");
+       g_assert_cmpfloat (geocode_location_get_latitude (loc) - 21.8021297, <, 0.000001);
+       g_assert_cmpfloat (geocode_location_get_longitude (loc) - -100.7374556, <, 0.000001);
+       g_assert_cmpstr (geocode_place_get_name (place), ==, "Santa Maria Del Rio, Mexico");
        g_assert_cmpstr (geocode_place_get_town (place), ==, "Santa Maria Del Rio");
        g_assert_cmpstr (geocode_place_get_state (place), ==, "San Luis Potosi");
-       g_assert_cmpstr (geocode_place_get_county (place), ==, "Santa Maria del Rio");
        g_assert_cmpstr (geocode_place_get_country (place), ==, "Mexico");
        g_assert_cmpstr (geocode_location_get_description (loc), ==, "Santa Maria Del Rio, Mexico");
 
@@ -348,14 +351,13 @@ test_locale (void)
        g_object_unref (object);
 
        place = res->data;
-       g_assert_cmpstr (geocode_place_get_name (place), ==, "Moskva");
-       /* For some reason, Yahoo doesn't localise the state's name in this case */
-       g_assert_cmpstr (geocode_place_get_state (place), ==, "Moscow Federal City");
-       g_assert_cmpstr (geocode_place_get_country (place), ==, "Rusko");
+       g_assert_cmpstr (geocode_place_get_name (place), ==, "Moskva, Ruská federace");
+       g_assert_cmpstr (geocode_place_get_state (place), ==, "Moskva");
+       g_assert_cmpstr (geocode_place_get_country (place), ==, "Ruská federace");
 
        loc = geocode_place_get_location (place);
        g_assert (loc != NULL);
-       g_assert_cmpstr (geocode_location_get_description (loc), ==, "Moskva, Rusko");
+       g_assert_cmpstr (geocode_location_get_description (loc), ==, "Moskva, Ruská federace");
        g_assert_cmpfloat (geocode_location_get_latitude (loc) - 55.756950, <, 0.000001);
        g_assert_cmpfloat (geocode_location_get_longitude (loc) - 37.614971, <, 0.000001);
        print_place (place);
@@ -373,17 +375,16 @@ test_locale (void)
        g_assert (res != NULL);
        g_object_unref (object);
 
-       place = res->data;
+        /* Nominatim lists our desired town at index 5 */
+       place = res->next->next->next->next->data;
        loc = geocode_place_get_location (place);
        g_assert (loc != NULL);
 
-       g_assert_cmpstr (geocode_place_get_name (place), ==, "Bonneville");
+       g_assert_cmpstr (geocode_place_get_name (place), ==, "Bonneville, Rhône-Alpes, France 
métropolitaine");
        g_assert_cmpstr (geocode_place_get_town (place), ==, "Bonneville");
        g_assert_cmpstr (geocode_place_get_state (place), ==, "Rhône-Alpes");
-       g_assert_cmpstr (geocode_place_get_county (place), ==, "Haute-Savoie");
-       g_assert_cmpstr (geocode_place_get_administrative_area (place), ==, "Bonneville");
-       g_assert_cmpstr (geocode_place_get_country (place), ==, "France");
-       g_assert_cmpstr (geocode_location_get_description (loc), ==, "Bonneville, Rhône-Alpes, France");
+       g_assert_cmpstr (geocode_place_get_country (place), ==, "France métropolitaine");
+       g_assert_cmpstr (geocode_location_get_description (loc), ==, "Bonneville, Rhône-Alpes, France 
métropolitaine");
        print_place (place);
 
        g_list_free_full (res, (GDestroyNotify) g_object_unref);
@@ -396,23 +397,24 @@ test_locale (void)
 static void
 test_resolve_json (void)
 {
-       GHashTable *ht;
+       GList *list;
+       GeocodePlace *place;
        GError *error = NULL;
        guint i;
        struct {
                const char *fname;
                const char *error;
-               const char *key;
+               const char *prop;
                const char *value;
        } tests[] = {
-               { "placefinder-area.json", NULL, "area", "Onslow Village" },
-               { "placefinder-got-error.json", "You gotz done!" },
-               { "placefinder-no-results.json", "No matches found for request", NULL, NULL },
+               { "nominatim-area.json", NULL, "area", "Guildford Park" },
+               { "nominatim-no-results.json", "No matches found for request", NULL, NULL },
        };
 
        for (i = 0; i < G_N_ELEMENTS (tests); i++) {
                char *contents;
                char *filename;
+                char *value;
 
                filename = g_strdup_printf (TEST_SRCDIR "/%s", tests[i].fname);
                if (g_file_get_contents (filename, &contents, NULL, &error) == FALSE) {
@@ -421,24 +423,28 @@ test_resolve_json (void)
                }
                g_free (filename);
 
-               ht = _geocode_parse_resolve_json (contents, &error);
+                list = _geocode_parse_search_json (contents, &error);
                g_free (contents);
 
                if (tests[i].error) {
-                       g_assert (ht == NULL);
+                        g_assert (list == NULL);
                        g_assert_cmpstr (error->message, ==, tests[i].error);
                } else {
-                       g_assert (ht != NULL);
+                        g_assert (list != NULL);
+                        g_assert_cmpint (g_list_length (list), ==, 1);
                }
 
-               if (ht == NULL) {
+               if (list == NULL) {
                        g_error_free (error);
                        error = NULL;
                        continue;
                }
 
-               g_assert_cmpstr (g_hash_table_lookup (ht, tests[i].key), ==, tests[i].value);
-               g_hash_table_destroy (ht);
+                place = GEOCODE_PLACE (list->data);
+                g_object_get (place, tests[i].prop, &value, NULL);
+               g_assert_cmpstr (value, ==, tests[i].value);
+                g_free (value);
+                g_list_free (list);
        }
 }
 
@@ -451,26 +457,26 @@ test_search_json (void)
        GeocodePlace *place;
        GeocodeLocation *loc;
 
-       if (g_file_get_contents (TEST_SRCDIR "/geoplanet-rio.json",
+       if (g_file_get_contents (TEST_SRCDIR "/nominatim-rio.json",
                                 &contents, NULL, &error) == FALSE) {
                g_critical ("Couldn't load contents of '%s': %s",
-                           TEST_SRCDIR "/geoplanet-rio.json", error->message);
+                           TEST_SRCDIR "/nominatim-rio.json", error->message);
        }
        list = _geocode_parse_search_json (contents, &error);
 
        g_assert (list != NULL);
        g_assert_cmpint (g_list_length (list), ==, 10);
 
-       place = list->data;
+       place = list->next->data; /* First result is the state, not the town */
        loc = geocode_place_get_location (place);
        g_assert (loc != NULL);
 
-       g_assert_cmpstr (geocode_place_get_name (place), ==, "Rio de Janeiro");
+       g_assert_cmpstr (geocode_place_get_name (place), ==, "Rio de Janeiro, Rio de Janeiro, Brazil");
        g_assert_cmpstr (geocode_place_get_town (place), ==, "Rio de Janeiro");
        g_assert_cmpstr (geocode_place_get_state (place), ==, "Rio de Janeiro");
        g_assert_cmpstr (geocode_place_get_county (place), ==, "Rio de Janeiro");
        g_assert_cmpstr (geocode_place_get_country (place), ==, "Brazil");
-       g_assert_cmpstr (geocode_location_get_description (loc), ==, "Rio de Janeiro, Brazil");
+       g_assert_cmpstr (geocode_location_get_description (loc), ==, "Rio de Janeiro, Rio de Janeiro, 
Brazil");
 
        g_list_free_full (list, (GDestroyNotify) g_object_unref);
 }


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