3106db01f6c42079607e390079c3b1356f252fa1
[platform/core/api/location-manager.git] / src / location_bounds.c
1 /*
2  * Copyright (c) 2011-2013 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <system_info.h>
21 #include "location_bounds.h"
22 #include "location_internal.h"
23
24
25 //LCOV_EXCL_START
26 static void __free_position_list(gpointer data)
27 {
28         if (data == NULL)
29                 return;
30
31         LocationPosition *position = (LocationPosition *) data;
32         location_position_free(position);
33 }
34 //LCOV_EXCL_STOP
35
36 static location_bounds_type_e __convert_bounds_type(LocationBoundaryType type)
37 {
38         location_bounds_type_e ret;
39         switch (type) {
40         case LOCATION_BOUNDARY_CIRCLE:
41                 ret = LOCATION_BOUNDS_CIRCLE;
42                 break;
43         case LOCATION_BOUNDARY_POLYGON:
44                 ret = LOCATION_BOUNDS_POLYGON;
45                 break;
46         case LOCATION_BOUNDARY_NONE:
47         case LOCATION_BOUNDARY_RECT:
48         default:
49                 ret = LOCATION_BOUNDS_RECT;
50                 break;
51         }
52         return ret;
53 }
54
55 EXPORT_API int location_bounds_create_rect(location_coords_s top_left, location_coords_s bottom_right, location_bounds_h *bounds)
56 {
57         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
58         LOCATIONS_NULL_ARG_CHECK(bounds);
59         LOCATIONS_CHECK_CONDITION(top_left.latitude >= -90 && top_left.latitude <= 90, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
60         LOCATIONS_CHECK_CONDITION(top_left.longitude >= -180 && top_left.longitude <= 180, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
61         LOCATIONS_CHECK_CONDITION(bottom_right.latitude >= -90 && bottom_right.latitude <= 90, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
62         LOCATIONS_CHECK_CONDITION(bottom_right.longitude >= -180 && bottom_right.longitude <= 180, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
63
64         if ((bottom_right.longitude - top_left.longitude) < 180 && (bottom_right.longitude - top_left.longitude) > -180) {
65                 if (bottom_right.longitude <= top_left.longitude || bottom_right.latitude >= top_left.latitude)
66                         return LOCATION_BOUNDS_ERROR_INVALID_PARAMETER;
67         } else {
68                 if (bottom_right.latitude >= top_left.latitude)
69                         return LOCATION_BOUNDS_ERROR_INVALID_PARAMETER;
70         }
71
72         LocationPosition *lt = location_position_new(0, top_left.latitude, top_left.longitude, 0, LOCATION_STATUS_2D_FIX);
73         if (lt == NULL) {
74                 //LCOV_EXCL_START
75                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
76                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
77                 //LCOV_EXCL_STOP
78         }
79
80         LocationPosition *rb = location_position_new(0, bottom_right.latitude, bottom_right.longitude, 0, LOCATION_STATUS_2D_FIX);
81         if (rb == NULL) {
82                 //LCOV_EXCL_START
83                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
84                 location_position_free(lt);
85                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
86                 //LCOV_EXCL_STOP
87         }
88
89         location_bounds_s *handle = (location_bounds_s *) malloc(sizeof(location_bounds_s));
90         if (handle == NULL) {
91                 //LCOV_EXCL_START
92                 LOCATIONS_LOGE("OUT_OF_MEMORY(0x%08x)", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
93                 location_position_free(rb);
94                 location_position_free(lt);
95                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
96                 //LCOV_EXCL_STOP
97         }
98         memset(handle, 0, sizeof(location_bounds_s));
99
100         handle->is_added = FALSE;
101         handle->boundary = location_boundary_new_for_rect(lt, rb);
102         location_position_free(rb);
103         location_position_free(lt);
104         if (handle->boundary == NULL) {
105                 //LCOV_EXCL_START
106                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_boundary_new_for_rect", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
107                 free(handle);
108                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
109                 //LCOV_EXCL_STOP
110         }
111
112         *bounds = (location_bounds_h) handle;
113         return LOCATION_BOUNDS_ERROR_NONE;
114 }
115
116 EXPORT_API int location_bounds_create_circle(location_coords_s center, double radius, location_bounds_h *bounds)
117 {
118         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
119         LOCATIONS_NULL_ARG_CHECK(bounds);
120         LOCATIONS_CHECK_CONDITION(radius > 0, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
121         LOCATIONS_CHECK_CONDITION(center.latitude >= -90 && center.latitude <= 90, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
122         LOCATIONS_CHECK_CONDITION(center.longitude >= -180 && center.longitude <= 180, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
123
124         LocationPosition *ct = location_position_new(0, center.latitude, center.longitude, 0, LOCATION_STATUS_2D_FIX);
125         if (ct == NULL) {
126                 //LCOV_EXCL_START
127                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
128                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
129                 //LCOV_EXCL_STOP
130         }
131
132         location_bounds_s *handle = (location_bounds_s *) malloc(sizeof(location_bounds_s));
133         if (handle == NULL) {
134                 //LCOV_EXCL_START
135                 LOCATIONS_LOGE("OUT_OF_MEMORY(0x%08x)", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
136                 location_position_free(ct);
137                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
138                 //LCOV_EXCL_STOP
139         }
140         memset(handle, 0, sizeof(location_bounds_s));
141
142         handle->is_added = FALSE;
143         handle->boundary = location_boundary_new_for_circle(ct, radius);
144         location_position_free(ct);
145         if (handle->boundary == NULL) {
146                 //LCOV_EXCL_START
147                 free(handle);
148                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_boundary_new_for_circle", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
149                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
150                 //LCOV_EXCL_STOP
151         }
152
153         *bounds = (location_bounds_h) handle;
154         return LOCATION_BOUNDS_ERROR_NONE;
155 }
156
157 EXPORT_API int location_bounds_create_polygon(location_coords_s *coords_list, int length, location_bounds_h *bounds)
158 {
159         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
160         LOCATIONS_NULL_ARG_CHECK(coords_list);
161         LOCATIONS_NULL_ARG_CHECK(bounds);
162         LOCATIONS_CHECK_CONDITION(length >= 3, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
163
164         int i;
165         GList *position_list = NULL;
166         LocationPosition *position = NULL;
167         bool isValid;
168
169         for (i = 0; i < length; i++) {
170                 if (coords_list[i].latitude < -90 || coords_list[i].latitude > 90 || coords_list[i].longitude < -180 || coords_list[i].longitude > 180) {
171                         LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_INVALID_PARAMETER(0x%08x)", LOCATION_BOUNDS_ERROR_INVALID_PARAMETER);
172                         isValid = FALSE;
173                         break;
174                 }
175                 position = location_position_new(0, coords_list[i].latitude, coords_list[i].longitude, 0.0, LOCATION_STATUS_2D_FIX);
176                 position_list = g_list_append(position_list, position);
177                 /* We should not remove position.
178                 location_position_free(position);
179                 */
180                 isValid = TRUE;
181         }
182
183         if (!isValid) {
184                 g_list_free_full(position_list, (GDestroyNotify) __free_position_list);
185                 return LOCATION_BOUNDS_ERROR_INVALID_PARAMETER;
186         }
187
188         if (position_list == NULL) {
189                 //LCOV_EXCL_START
190                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
191                 g_list_free_full(position_list, (GDestroyNotify) __free_position_list);
192                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
193                 //LCOV_EXCL_STOP
194         }
195
196         location_bounds_s *handle = (location_bounds_s *) malloc(sizeof(location_bounds_s));
197         if (handle == NULL) {
198                 //LCOV_EXCL_START
199                 LOCATIONS_LOGE("OUT_OF_MEMORY(0x%08x)", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
200                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
201                 //LCOV_EXCL_STOP
202         }
203         memset(handle, 0, sizeof(location_bounds_s));
204
205         handle->is_added = FALSE;
206         handle->boundary = location_boundary_new_for_polygon(position_list);
207         if (handle->boundary == NULL) {
208                 //LCOV_EXCL_START
209                 free(handle);
210                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_boundary_new_for_polygon", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
211                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
212                 //LCOV_EXCL_STOP
213         }
214
215         *bounds = (location_bounds_h) handle;
216         return LOCATION_BOUNDS_ERROR_NONE;
217 }
218
219 EXPORT_API bool location_bounds_contains_coordinates(location_bounds_h bounds, location_coords_s coords)
220 {
221         if (__is_location_supported() == LOCATIONS_ERROR_NOT_SUPPORTED) {
222                 //LCOV_EXCL_START
223                 set_last_result(LOCATIONS_ERROR_NOT_SUPPORTED);
224                 return FALSE;
225                 //LCOV_EXCL_STOP
226         }
227
228         if (!bounds) {
229                 set_last_result(LOCATION_BOUNDS_ERROR_INVALID_PARAMETER);
230                 return FALSE;
231         }
232
233         if (coords.latitude < -90 || coords.latitude > 90 || coords.longitude < -180 || coords.longitude > 180) {
234                 set_last_result(LOCATION_BOUNDS_ERROR_INVALID_PARAMETER);
235                 return FALSE;
236         }
237
238         LocationPosition *pos = location_position_new(0, coords.latitude, coords.longitude, 0, LOCATION_STATUS_2D_FIX);
239         if (pos == NULL) {
240                 //LCOV_EXCL_START
241                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
242                 set_last_result(LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
243                 return FALSE;
244                 //LCOV_EXCL_STOP
245         }
246         location_bounds_s *handle = (location_bounds_s *) bounds;
247         gboolean is_inside = location_boundary_if_inside(handle->boundary, pos);
248         location_position_free(pos);
249         bool result = is_inside ? TRUE : FALSE;
250
251         set_last_result(LOCATION_BOUNDS_ERROR_NONE);
252         return result;
253 }
254
255 EXPORT_API int location_bounds_get_type(location_bounds_h bounds, location_bounds_type_e *type)
256 {
257         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
258         LOCATIONS_NULL_ARG_CHECK(bounds);
259         LOCATIONS_NULL_ARG_CHECK(type);
260
261         location_bounds_s *handle = (location_bounds_s *) bounds;
262         *type = __convert_bounds_type(handle->boundary->type);
263         return LOCATION_BOUNDS_ERROR_NONE;
264 }
265
266 EXPORT_API int location_bounds_get_rect_coords(location_bounds_h bounds, location_coords_s *top_left, location_coords_s *bottom_right)
267 {
268         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
269         LOCATIONS_NULL_ARG_CHECK(bounds);
270         LOCATIONS_NULL_ARG_CHECK(top_left);
271         LOCATIONS_NULL_ARG_CHECK(bottom_right);
272
273         location_bounds_s *handle = (location_bounds_s *) bounds;
274         if (__convert_bounds_type(handle->boundary->type) != LOCATION_BOUNDS_RECT) {
275                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_INCORRECT_TYPE(0x%08x)", LOCATION_BOUNDS_ERROR_INCORRECT_TYPE);
276                 return LOCATION_BOUNDS_ERROR_INCORRECT_TYPE;
277         }
278
279         top_left->latitude = handle->boundary->rect.left_top->latitude;
280         top_left->longitude = handle->boundary->rect.left_top->longitude;
281         bottom_right->latitude = handle->boundary->rect.right_bottom->latitude;
282         bottom_right->longitude = handle->boundary->rect.right_bottom->longitude;
283         return LOCATION_BOUNDS_ERROR_NONE;
284 }
285
286 EXPORT_API int location_bounds_get_circle_coords(location_bounds_h bounds, location_coords_s *center, double *radius)
287 {
288         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
289         LOCATIONS_NULL_ARG_CHECK(bounds);
290         LOCATIONS_NULL_ARG_CHECK(center);
291         LOCATIONS_NULL_ARG_CHECK(radius);
292
293         location_bounds_s *handle = (location_bounds_s *) bounds;
294         if (__convert_bounds_type(handle->boundary->type) != LOCATION_BOUNDS_CIRCLE) {
295                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_INCORRECT_TYPE(0x%08x)", LOCATION_BOUNDS_ERROR_INCORRECT_TYPE);
296                 return LOCATION_BOUNDS_ERROR_INCORRECT_TYPE;
297         }
298
299         center->latitude = handle->boundary->circle.center->latitude;
300         center->longitude = handle->boundary->circle.center->longitude;
301         *radius = handle->boundary->circle.radius;
302         return LOCATION_BOUNDS_ERROR_NONE;
303 }
304
305 EXPORT_API int location_bounds_foreach_polygon_coords(location_bounds_h bounds, polygon_coords_cb callback, void *user_data)
306 {
307         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
308         LOCATIONS_NULL_ARG_CHECK(bounds);
309         LOCATIONS_NULL_ARG_CHECK(callback);
310
311         location_bounds_s *handle = (location_bounds_s *) bounds;
312         if (__convert_bounds_type(handle->boundary->type) != LOCATION_BOUNDS_POLYGON) {
313                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_INCORRECT_TYPE(0x%08x)", LOCATION_BOUNDS_ERROR_INCORRECT_TYPE);
314                 return LOCATION_BOUNDS_ERROR_INCORRECT_TYPE;
315         }
316
317         GList *list = handle->boundary->polygon.position_list;
318         while (list) {
319                 LocationPosition *pos = list->data;
320                 location_coords_s coords;
321                 coords.latitude = pos->latitude;
322                 coords.longitude = pos->longitude;
323
324                 if (callback(coords, user_data) != TRUE) {
325                         LOCATIONS_LOGI("User quit the loop ");
326                         break;
327                 }
328                 list = g_list_next(list);
329         }
330         return LOCATION_BOUNDS_ERROR_NONE;
331 }
332
333 EXPORT_API int location_bounds_destroy(location_bounds_h bounds)
334 {
335         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
336         LOCATIONS_NULL_ARG_CHECK(bounds);
337
338         location_bounds_s *handle = (location_bounds_s *) bounds;
339         if (handle->is_added) {
340                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_IS_ADDED(0x%08x)", LOCATION_BOUNDS_ERROR_IS_ADDED);
341                 return LOCATION_BOUNDS_ERROR_IS_ADDED;
342         }
343         location_boundary_free(handle->boundary);
344         handle->user_cb = NULL;
345         handle->user_data = NULL;
346         free(handle);
347         LOCATIONS_LOGE("");
348         return LOCATION_BOUNDS_ERROR_NONE;
349 }
350
351 EXPORT_API int location_bounds_set_state_changed_cb(location_bounds_h bounds, location_bounds_state_changed_cb callback, void *user_data)
352 {
353         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
354         LOCATIONS_NULL_ARG_CHECK(bounds);
355         LOCATIONS_NULL_ARG_CHECK(callback);
356
357         location_bounds_s *handle = (location_bounds_s *) bounds;
358         handle->user_cb = callback;
359         handle->user_data = user_data;
360         return LOCATION_BOUNDS_ERROR_NONE;
361 }
362
363 EXPORT_API int location_bounds_unset_state_changed_cb(location_bounds_h bounds)
364 {
365         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
366         LOCATIONS_NULL_ARG_CHECK(bounds);
367
368         location_bounds_s *handle = (location_bounds_s *) bounds;
369         handle->user_cb = NULL;
370         handle->user_data = NULL;
371         return LOCATION_BOUNDS_ERROR_NONE;
372 }