merge from private
[platform/core/location/location-module.git] / modules / osm / location-osm-geocode.c
1 /*
2  * location-module
3  *
4  * Copyright (c) 2010-2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Youngae Kang <youngae.kang@samsung.com>, Minjune Kim <sena06.kim@samsung.com>
7  *          Genie Kim <daejins.kim@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21
22 #include "log.h"
23 #include "location-osm.h"
24
25 static GHashTable*
26 _get_geoclue_addr_from_location_addr (const LocationAddress *address)
27 {
28         if (!address) return NULL;
29
30         GHashTable *geoclue_addr = geoclue_address_details_new();
31         if (address->street) {
32                 if (address->building_number) {
33                         char *street_addr = g_strdup_printf ("%s %s", address->building_number, address->street);
34                         geoclue_address_details_insert (geoclue_addr, GEOCLUE_ADDRESS_KEY_STREET, street_addr);
35                         g_free (street_addr);
36                 } else geoclue_address_details_insert (geoclue_addr, GEOCLUE_ADDRESS_KEY_STREET, address->street);
37         }
38         if (address->district)     geoclue_address_details_insert (geoclue_addr, GEOCLUE_ADDRESS_KEY_AREA, address->district);
39         if (address->city)         geoclue_address_details_insert (geoclue_addr, GEOCLUE_ADDRESS_KEY_LOCALITY, address->city);
40         if (address->state)        geoclue_address_details_insert (geoclue_addr, GEOCLUE_ADDRESS_KEY_REGION, address->state);
41         if (address->country_code) geoclue_address_details_insert (geoclue_addr, GEOCLUE_ADDRESS_KEY_COUNTRY, address->country_code);
42         if (address->postal_code)  geoclue_address_details_insert (geoclue_addr, GEOCLUE_ADDRESS_KEY_POSTALCODE, address->postal_code);
43
44         return geoclue_addr;
45 }
46
47 static LocationAddress*
48 _get_location_addr_from_geoclue_addr (GHashTable *geoclue_addr)
49 {
50         if (!geoclue_addr) return NULL;
51
52         LocationAddress *addr = NULL;
53
54         gchar *country, *region, *locality, *postalcode, *area, *street;
55
56         country = g_hash_table_lookup (geoclue_addr, GEOCLUE_ADDRESS_KEY_COUNTRY);
57         region = g_hash_table_lookup (geoclue_addr, GEOCLUE_ADDRESS_KEY_REGION);
58         locality = g_hash_table_lookup (geoclue_addr, GEOCLUE_ADDRESS_KEY_LOCALITY);
59         area = g_hash_table_lookup (geoclue_addr, GEOCLUE_ADDRESS_KEY_AREA);
60         postalcode = g_hash_table_lookup (geoclue_addr, GEOCLUE_ADDRESS_KEY_POSTALCODE);
61         street = g_hash_table_lookup (geoclue_addr, GEOCLUE_ADDRESS_KEY_STREET);
62
63         addr = location_address_new (NULL, street, area, locality, region, NULL, postalcode, NULL, country, NULL);
64         return addr;
65 }
66
67
68 static LocationAccuracy *
69 _get_location_acc_from_geoclue_acc (GeoclueAccuracy *acc)
70 {
71         if (!acc) return NULL;
72
73         LocationAccuracy *accuracy = NULL;
74         GeoclueAccuracyLevel level;
75         double horiz_acc;
76         double vert_acc;
77         geoclue_accuracy_get_details (acc, &level, &horiz_acc, &vert_acc);
78
79         if (level == GEOCLUE_ACCURACY_LEVEL_DETAILED)        accuracy = location_accuracy_new (LOCATION_ACCURACY_LEVEL_DETAILED, horiz_acc, vert_acc);
80         else if (level == GEOCLUE_ACCURACY_LEVEL_STREET)     accuracy = location_accuracy_new (LOCATION_ACCURACY_LEVEL_STREET, horiz_acc, vert_acc);
81         else if (level == GEOCLUE_ACCURACY_LEVEL_POSTALCODE) accuracy = location_accuracy_new (LOCATION_ACCURACY_LEVEL_POSTALCODE, horiz_acc, vert_acc);
82         else if (level == GEOCLUE_ACCURACY_LEVEL_LOCALITY)   accuracy = location_accuracy_new (LOCATION_ACCURACY_LEVEL_LOCALITY, horiz_acc, vert_acc);
83         else if (level == GEOCLUE_ACCURACY_LEVEL_REGION)     accuracy = location_accuracy_new (LOCATION_ACCURACY_LEVEL_REGION, horiz_acc, vert_acc);
84         else if (level == GEOCLUE_ACCURACY_LEVEL_COUNTRY)    accuracy = location_accuracy_new (LOCATION_ACCURACY_LEVEL_COUNTRY, horiz_acc, vert_acc);
85         else accuracy = location_accuracy_new (LOCATION_ACCURACY_LEVEL_NONE, 0, 0);
86
87         return accuracy;
88 }
89
90 static void
91 address_cb (GeoclueReverseGeocode *revgeocode,
92         GHashTable            *details,
93         GeoclueAccuracy       *accuracy,
94         GError                *error,
95         gpointer               userdata)
96 {
97         OsmHandleData* data = (OsmHandleData*)userdata;
98         g_return_if_fail(data->addr_cb);
99
100         LocationAddress *addr = NULL;
101         LocationAccuracy *acc = NULL;
102         LocationError err = LOCATION_ERROR_NONE;
103
104         if (error) {
105                 MOD_LOGW ("Error getting reverse geocode: %s", error->message);
106                 err = LOCATION_ERROR_NOT_AVAILABLE;
107         } else {
108                 if (accuracy) acc = _get_location_acc_from_geoclue_acc (accuracy);
109                 else acc = location_accuracy_new (LOCATION_ACCURACY_LEVEL_NONE, 0, 0);
110
111                 if (details) addr = _get_location_addr_from_geoclue_addr (details);
112         }
113
114         data->addr_cb (err, addr, acc, data->userdata);
115         if (addr) location_address_free (addr);
116         if (acc) location_accuracy_free (acc);
117         g_free (data);
118 }
119
120 static void
121 _free_pos_list_item(gpointer data)
122 {
123         g_return_if_fail(data);
124
125         LocationPosition *position = (LocationPosition *)data;
126         location_position_free(position);
127 }
128
129 static void
130 _free_acc_list_item(gpointer data)
131 {
132         g_return_if_fail(data);
133
134         LocationAccuracy *accuracy = (LocationAccuracy *)data;
135         location_accuracy_free(accuracy);
136 }
137
138 static void
139 position_cb (GeoclueGeocode       *geocode,
140         GeocluePositionFields fields,
141         double                latitude,
142         double                longitude,
143         double                altitude,
144         GeoclueAccuracy      *accuracy,
145         GError               *error,
146         gpointer              userdata)
147 {
148         OsmHandleData* data = (OsmHandleData*)userdata;
149         GList *pos_list = NULL;
150         GList *acc_list = NULL;
151
152         g_return_if_fail(data->pos_cb);
153
154         LocationPosition *pos = NULL;
155         LocationAccuracy *acc = NULL;
156         LocationError err = LOCATION_ERROR_NONE;
157
158         if (error) {
159                 MOD_LOGW ("Error getting geocode: %s", error->message);
160                 err = LOCATION_ERROR_NOT_AVAILABLE;
161         } else {
162                 if (fields & GEOCLUE_POSITION_FIELDS_LATITUDE &&
163                         fields & GEOCLUE_POSITION_FIELDS_LONGITUDE) {
164                         if(fields & GEOCLUE_POSITION_FIELDS_ALTITUDE) pos = location_position_new (0, latitude, longitude, altitude, LOCATION_STATUS_3D_FIX);
165                         else pos = location_position_new (0, latitude, longitude, 0, LOCATION_STATUS_2D_FIX);
166
167                         pos_list = g_list_append(pos_list, pos);
168                 } else {
169                         err = LOCATION_ERROR_NOT_FOUND;
170                 }
171
172                 if (accuracy) {
173                         acc = _get_location_acc_from_geoclue_acc (accuracy);
174                         acc_list = g_list_append(acc_list, acc);
175                 }
176         }
177         data->pos_cb (err, pos_list, acc_list, data->userdata);
178
179         if (pos_list) g_list_free_full(pos_list, _free_pos_list_item);
180         if (acc_list) g_list_free_full(acc_list, _free_acc_list_item);
181         g_free (data);
182
183 }
184
185
186 int
187 osm_get_geocode (OsmHandle *osm,
188         const LocationAddress *addr,
189         GList **pos_list,
190         GList **acc_list)
191 {
192         double lat, lon, alt;
193         GeoclueAccuracy *geoclue_acc = NULL;
194         GError *error = NULL;
195         LocationPosition *pos = NULL;
196         LocationAccuracy *acc = NULL;
197         LocationError err = LOCATION_ERROR_NONE;
198
199         GHashTable* geoclue_addr = _get_geoclue_addr_from_location_addr (addr);
200         GeocluePositionFields fields = geoclue_geocode_address_to_position (osm->geocoder, geoclue_addr,
201                                                               &lat, &lon, &alt,
202                                                               &geoclue_acc, &error);
203         g_hash_table_destroy (geoclue_addr);
204
205         if (error) {
206                 MOD_LOGW ("Error getting geocode: %s", error->message);
207                 g_error_free (error);
208                 return LOCATION_ERROR_NOT_AVAILABLE;
209         }
210
211         if (fields & GEOCLUE_POSITION_FIELDS_LATITUDE &&
212                 fields & GEOCLUE_POSITION_FIELDS_LONGITUDE) {
213                 if(fields & GEOCLUE_POSITION_FIELDS_ALTITUDE) pos = location_position_new (0, lat, lon, alt, LOCATION_STATUS_3D_FIX);
214                         else pos = location_position_new (0, lat, lon, 0, LOCATION_STATUS_2D_FIX);
215
216                 *pos_list = g_list_append(*pos_list, pos);
217         }
218         else {
219                 err = LOCATION_ERROR_NOT_FOUND;
220         }
221
222         if (geoclue_acc) {
223                 acc = _get_location_acc_from_geoclue_acc (geoclue_acc);
224                 geoclue_accuracy_free (geoclue_acc);
225
226                 *acc_list = g_list_append(*acc_list, acc);
227         }
228
229         if (pos) location_position_free (pos);
230         if (acc) location_accuracy_free (acc);
231
232         return err;
233 }
234
235 int
236 osm_get_geocode_async (OsmHandle *osm,
237         const LocationAddress * addr,
238         LocationPositionCB callback,
239         gpointer userdata)
240 {
241         GHashTable* geoclue_addr = _get_geoclue_addr_from_location_addr (addr);
242         OsmHandleData *data = g_new0 (OsmHandleData, 1);
243         data->pos_cb = callback;
244         data->userdata = userdata;
245         geoclue_geocode_address_to_position_async (osm->geocoder, geoclue_addr, position_cb, data);
246         g_hash_table_destroy (geoclue_addr);
247
248         return LOCATION_ERROR_NONE;
249 }
250
251 int
252 osm_get_geocode_freetext(OsmHandle *osm,
253         const const gchar* addr,
254         GList **pos_list,
255         GList **acc_list)
256 {
257         double lat, lon, alt;
258         GeoclueAccuracy *geoclue_acc = NULL;
259         GError *error = NULL;
260         LocationPosition *pos = NULL;
261         LocationAccuracy *acc = NULL;
262         LocationError err = LOCATION_ERROR_NONE;
263
264         GeocluePositionFields fields = geoclue_geocode_freeform_address_to_position (osm->geocoder, addr,
265                                                               &lat, &lon, &alt,
266                                                               &geoclue_acc, &error);
267         if (error) {
268                 MOD_LOGW ("Error getting geocode: %s", error->message);
269                 g_error_free (error);
270                 return LOCATION_ERROR_NOT_AVAILABLE;
271         }
272
273         if (fields & GEOCLUE_POSITION_FIELDS_LATITUDE &&
274                 fields & GEOCLUE_POSITION_FIELDS_LONGITUDE) {
275                 if(fields & GEOCLUE_POSITION_FIELDS_ALTITUDE) pos = location_position_new (0, lat, lon, alt, LOCATION_STATUS_3D_FIX);
276                 else pos = location_position_new (0, lat, lon, 0, LOCATION_STATUS_2D_FIX);
277                 *pos_list = g_list_append(*pos_list, pos);
278         }
279         else {
280                 err = LOCATION_ERROR_NOT_FOUND;
281         }
282
283         if (geoclue_acc) {
284                 acc = _get_location_acc_from_geoclue_acc (geoclue_acc);
285                 geoclue_accuracy_free (geoclue_acc);
286                 *acc_list = g_list_append(*acc_list, acc);
287         }
288
289         if (pos) location_position_free (pos);
290         if (acc) location_accuracy_free (acc);
291         return err;
292 }
293
294 int
295 osm_get_geocode_freetext_async (OsmHandle *osm,
296         const gchar* addr,
297         LocationPositionCB callback,
298         gpointer userdata)
299 {
300         OsmHandleData *data = g_new0 (OsmHandleData, 1);
301         data->pos_cb = callback;
302         data->userdata = userdata;
303         geoclue_geocode_freeform_address_to_position_async (osm->geocoder, addr, position_cb, data);
304
305         return LOCATION_ERROR_NONE;
306 }
307
308 int
309 osm_get_reverse_geocode(OsmHandle *osm,
310         const LocationPosition *pos,
311         LocationAddress **addr,
312         LocationAccuracy **acc)
313 {
314         GeoclueAccuracy *addr_acc = NULL;
315         GError *error = NULL;
316         GHashTable* geoclue_addr = NULL;
317
318         double lat = pos->latitude;
319         double lon = pos->longitude;
320         GeoclueAccuracy *pos_acc = geoclue_accuracy_new (GEOCLUE_ACCURACY_LEVEL_DETAILED, 0.0, 0.0);
321
322         gboolean success = geoclue_reverse_geocode_position_to_address (osm->rev_geocoder, lat, lon,
323                                                                         pos_acc, &geoclue_addr,
324                                                                         &addr_acc, &error);
325         geoclue_accuracy_free (pos_acc);
326
327         if (!success || error) {
328                 MOD_LOGW ("Error getting reverse geocode: %s", error->message);
329                 g_error_free (error);
330                 return LOCATION_ERROR_NOT_AVAILABLE;
331         }
332
333         if (addr_acc) {
334                 *acc = _get_location_acc_from_geoclue_acc (addr_acc);
335                 geoclue_accuracy_free (addr_acc);
336         } else *acc = location_accuracy_new (LOCATION_ACCURACY_LEVEL_NONE, 0, 0);
337         if (geoclue_addr) {
338                 *addr = _get_location_addr_from_geoclue_addr (geoclue_addr);
339                 g_hash_table_destroy (geoclue_addr);
340         }
341
342         return LOCATION_ERROR_NONE;
343 }
344
345 int
346 osm_get_reverse_geocode_async (OsmHandle *osm,
347         const LocationPosition *pos,
348         LocationAddressCB callback,
349         gpointer userdata)
350 {
351         double lat = pos->latitude;
352         double lon = pos->longitude;
353         GeoclueAccuracy *pos_acc = geoclue_accuracy_new (GEOCLUE_ACCURACY_LEVEL_DETAILED, 0.0, 0.0);;
354         OsmHandleData *data = g_new0 (OsmHandleData, 1);
355         data->addr_cb = callback;
356         data->userdata = userdata;
357         geoclue_reverse_geocode_position_to_address_async (osm->rev_geocoder,
358                                                 lat, lon, pos_acc,
359                                                 address_cb, data);
360         geoclue_accuracy_free (pos_acc);
361
362         return LOCATION_ERROR_NONE;
363 }
364
365
366
367