f4f02011931cb48862d0df3a379e83409ac31027
[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 static void __free_position_list(gpointer data)
26 {
27         if (data == NULL)
28                 return;
29
30         LocationPosition *position = (LocationPosition *) data;
31         location_position_free(position);
32 }
33
34 static location_bounds_type_e __convert_bounds_type(LocationBoundaryType type)
35 {
36         location_bounds_type_e ret;
37         switch (type) {
38                 case LOCATION_BOUNDARY_CIRCLE:
39                         ret = LOCATION_BOUNDS_CIRCLE;
40                         break;
41                 case LOCATION_BOUNDARY_POLYGON:
42                         ret = LOCATION_BOUNDS_POLYGON;
43                         break;
44                 case LOCATION_BOUNDARY_NONE:
45                 case LOCATION_BOUNDARY_RECT:
46                 default:
47                         ret = LOCATION_BOUNDS_RECT;
48                         break;
49         }
50         return ret;
51 }
52
53 EXPORT_API int location_bounds_create_rect(location_coords_s top_left, location_coords_s bottom_right, location_bounds_h *bounds)
54 {
55         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
56         LOCATIONS_NULL_ARG_CHECK(bounds);
57         LOCATIONS_CHECK_CONDITION(top_left.latitude >= -90 && top_left.latitude <= 90, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
58         LOCATIONS_CHECK_CONDITION(top_left.longitude >= -180 && top_left.longitude <= 180, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
59         LOCATIONS_CHECK_CONDITION(bottom_right.latitude >= -90 && bottom_right.latitude <= 90, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
60         LOCATIONS_CHECK_CONDITION(bottom_right.longitude >= -180 && bottom_right.longitude <= 180, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
61
62         LocationPosition *lt = location_position_new(0, top_left.latitude, top_left.longitude, 0, LOCATION_STATUS_2D_FIX);
63         if (lt == NULL) {
64                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
65                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
66         }
67
68         LocationPosition *rb = location_position_new(0, bottom_right.latitude, bottom_right.longitude, 0, LOCATION_STATUS_2D_FIX);
69         if (rb == NULL) {
70                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
71                 location_position_free(lt);
72                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
73         }
74
75         location_bounds_s *handle = (location_bounds_s *) malloc(sizeof(location_bounds_s));
76         if (handle == NULL) {
77                 LOCATIONS_LOGE("OUT_OF_MEMORY(0x%08x)", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
78                 location_position_free(rb);
79                 location_position_free(lt);
80                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
81         }
82         memset(handle, 0, sizeof(location_bounds_s));
83
84         handle->is_added = FALSE;
85         handle->boundary = location_boundary_new_for_rect(lt, rb);
86         location_position_free(rb);
87         location_position_free(lt);
88         if (handle->boundary == NULL) {
89                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_boundary_new_for_rect", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
90                 free(handle);
91                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
92         }
93         handle->user_cb = NULL;
94         handle->user_data = NULL;
95
96         *bounds = (location_bounds_h) handle;
97         return LOCATION_BOUNDS_ERROR_NONE;
98 }
99
100 EXPORT_API int location_bounds_create_circle(location_coords_s center, double radius, location_bounds_h *bounds)
101 {
102         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
103         LOCATIONS_NULL_ARG_CHECK(bounds);
104         LOCATIONS_CHECK_CONDITION(radius >= 0, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
105         LOCATIONS_CHECK_CONDITION(center.latitude >= -90 && center.latitude <= 90, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
106         LOCATIONS_CHECK_CONDITION(center.longitude >= -180 && center.longitude <= 180, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
107
108         LocationPosition *ct = location_position_new(0, center.latitude, center.longitude, 0, LOCATION_STATUS_2D_FIX);
109         if (ct == NULL) {
110                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
111                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
112         }
113
114         location_bounds_s *handle = (location_bounds_s *) malloc(sizeof(location_bounds_s));
115         if (handle == NULL) {
116                 LOCATIONS_LOGE("OUT_OF_MEMORY(0x%08x)", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
117                 location_position_free(ct);
118                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
119         }
120         memset(handle, 0, sizeof(location_bounds_s));
121
122         handle->is_added = FALSE;
123         handle->boundary = location_boundary_new_for_circle(ct, radius);
124         location_position_free(ct);
125         if (handle->boundary == NULL) {
126                 int ret = get_last_result();
127                 free(handle);
128                 if (ret == LOCATION_ERROR_PARAMETER) {
129                         LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_INVALID_PARAMETER(0x%08x) fail to location_boundary_new_for_circle", LOCATION_BOUNDS_ERROR_INVALID_PARAMETER);
130                         return LOCATION_BOUNDS_ERROR_INVALID_PARAMETER;
131                 } else {
132                         LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_boundary_new_for_circle", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
133                         return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
134                 }
135         }
136         handle->user_cb = NULL;
137         handle->user_data = NULL;
138
139         *bounds = (location_bounds_h) handle;
140         return LOCATION_BOUNDS_ERROR_NONE;
141 }
142
143 EXPORT_API int location_bounds_create_polygon(location_coords_s *coords_list, int length, location_bounds_h *bounds)
144 {
145         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
146         LOCATIONS_NULL_ARG_CHECK(coords_list);
147         LOCATIONS_NULL_ARG_CHECK(bounds);
148         LOCATIONS_CHECK_CONDITION(length >= 3, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
149
150         int i;
151         GList *position_list = NULL;
152         LocationPosition *position = NULL;
153         bool isValid;
154
155         for (i = 0; i < length; i++) {
156                 if (coords_list[i].latitude < -90 || coords_list[i].latitude > 90 || coords_list[i].longitude < -180 || coords_list[i].longitude > 180) {
157                         LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_INVALID_PARAMETER(0x%08x)", LOCATION_BOUNDS_ERROR_INVALID_PARAMETER);
158                         isValid = FALSE;
159                         break;
160                 }
161                 position = location_position_new(0, coords_list[i].latitude, coords_list[i].longitude, 0.0, LOCATION_STATUS_2D_FIX);
162                 position_list = g_list_append(position_list, position);
163
164                 /* We should not remove position
165                 location_position_free(position);
166                 */
167                 isValid = TRUE;
168         }
169
170         if (!isValid) {
171                 g_list_free_full(position_list, (GDestroyNotify) __free_position_list);
172                 return LOCATION_BOUNDS_ERROR_INVALID_PARAMETER;
173         }
174
175         if (position_list == NULL) {
176                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
177                 g_list_free_full(position_list, (GDestroyNotify) __free_position_list);
178                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
179         }
180
181         location_bounds_s *handle = (location_bounds_s *) malloc(sizeof(location_bounds_s));
182         if (handle == NULL) {
183                 LOCATIONS_LOGE("OUT_OF_MEMORY(0x%08x)", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
184                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
185         }
186         memset(handle, 0, sizeof(location_bounds_s));
187
188         handle->is_added = FALSE;
189         handle->boundary = location_boundary_new_for_polygon(position_list);
190         if (handle->boundary == NULL) {
191                 int ret = get_last_result();
192                 free(handle);
193                 if (ret == LOCATION_ERROR_PARAMETER) {
194                         LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_INVALID_PARAMETER(0x%08x) fail to location_boundary_new_for_polygon", LOCATION_BOUNDS_ERROR_INVALID_PARAMETER);
195                         return LOCATION_BOUNDS_ERROR_INVALID_PARAMETER;
196                 } else {
197                         LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_boundary_new_for_polygon", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
198                         return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
199                 }
200         }
201
202         handle->user_cb = NULL;
203         handle->user_data = NULL;
204
205         *bounds = (location_bounds_h) handle;
206         return LOCATION_BOUNDS_ERROR_NONE;
207 }
208
209 EXPORT_API bool location_bounds_contains_coordinates(location_bounds_h bounds, location_coords_s coords)
210 {
211         if (__is_location_supported() == LOCATIONS_ERROR_NOT_SUPPORTED) {
212                 set_last_result(LOCATIONS_ERROR_NOT_SUPPORTED);
213                 return FALSE;
214         }
215
216         if (!bounds) {
217                 set_last_result(LOCATION_BOUNDS_ERROR_INVALID_PARAMETER);
218                 return FALSE;
219         }
220
221         if (coords.latitude < -90 || coords.latitude > 90 || coords.longitude < -180 || coords.longitude > 180) {
222                 set_last_result(LOCATION_BOUNDS_ERROR_INVALID_PARAMETER);
223                 return FALSE;
224         }
225
226         LocationPosition *pos = location_position_new(0, coords.latitude, coords.longitude, 0, LOCATION_STATUS_2D_FIX);
227         if (pos == NULL) {
228                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
229                 set_last_result(LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
230                 return FALSE;
231         }
232         location_bounds_s *handle = (location_bounds_s *) bounds;
233         gboolean is_inside = location_boundary_if_inside(handle->boundary, pos);
234         location_position_free(pos);
235         bool result = is_inside ? TRUE : FALSE;
236
237         set_last_result(LOCATION_BOUNDS_ERROR_NONE);
238         return result;
239 }
240
241 EXPORT_API int location_bounds_get_type(location_bounds_h bounds, location_bounds_type_e *type)
242 {
243         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
244         LOCATIONS_NULL_ARG_CHECK(bounds);
245         LOCATIONS_NULL_ARG_CHECK(type);
246
247         location_bounds_s *handle = (location_bounds_s *) bounds;
248         *type = __convert_bounds_type(handle->boundary->type);
249         return LOCATION_BOUNDS_ERROR_NONE;
250 }
251
252 EXPORT_API int location_bounds_get_rect_coords(location_bounds_h bounds, location_coords_s *top_left, location_coords_s *bottom_right)
253 {
254         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
255         LOCATIONS_NULL_ARG_CHECK(bounds);
256         LOCATIONS_NULL_ARG_CHECK(top_left);
257         LOCATIONS_NULL_ARG_CHECK(bottom_right);
258
259         location_bounds_s *handle = (location_bounds_s *) bounds;
260         if (__convert_bounds_type(handle->boundary->type) != LOCATION_BOUNDS_RECT) {
261                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_INCORRECT_TYPE(0x%08x)", LOCATION_BOUNDS_ERROR_INCORRECT_TYPE);
262                 return LOCATION_BOUNDS_ERROR_INCORRECT_TYPE;
263         }
264
265         top_left->latitude = handle->boundary->rect.left_top->latitude;
266         top_left->longitude = handle->boundary->rect.left_top->longitude;
267         bottom_right->latitude = handle->boundary->rect.right_bottom->latitude;
268         bottom_right->longitude = handle->boundary->rect.right_bottom->longitude;
269         return LOCATION_BOUNDS_ERROR_NONE;
270 }
271
272 EXPORT_API int location_bounds_get_circle_coords(location_bounds_h bounds, location_coords_s *center, double *radius)
273 {
274         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
275         LOCATIONS_NULL_ARG_CHECK(bounds);
276         LOCATIONS_NULL_ARG_CHECK(center);
277         LOCATIONS_NULL_ARG_CHECK(radius);
278
279         location_bounds_s *handle = (location_bounds_s *) bounds;
280         if (__convert_bounds_type(handle->boundary->type) != LOCATION_BOUNDS_CIRCLE) {
281                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_INCORRECT_TYPE(0x%08x)", LOCATION_BOUNDS_ERROR_INCORRECT_TYPE);
282                 return LOCATION_BOUNDS_ERROR_INCORRECT_TYPE;
283         }
284
285         center->latitude = handle->boundary->circle.center->latitude;
286         center->longitude = handle->boundary->circle.center->longitude;
287         *radius = handle->boundary->circle.radius;
288         return LOCATION_BOUNDS_ERROR_NONE;
289 }
290
291 EXPORT_API int location_bounds_foreach_polygon_coords(location_bounds_h bounds, polygon_coords_cb callback, void *user_data)
292 {
293         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
294         LOCATIONS_NULL_ARG_CHECK(bounds);
295         LOCATIONS_NULL_ARG_CHECK(callback);
296
297         location_bounds_s *handle = (location_bounds_s *) bounds;
298         if (__convert_bounds_type(handle->boundary->type) != LOCATION_BOUNDS_POLYGON) {
299                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_INCORRECT_TYPE(0x%08x)", LOCATION_BOUNDS_ERROR_INCORRECT_TYPE);
300                 return LOCATION_BOUNDS_ERROR_INCORRECT_TYPE;
301         }
302
303         GList *list = handle->boundary->polygon.position_list;
304         while (list) {
305                 LocationPosition *pos = list->data;
306                 location_coords_s coords;
307                 coords.latitude = pos->latitude;
308                 coords.longitude = pos->longitude;
309
310                 if (callback(coords, user_data) != TRUE) {
311                         LOCATIONS_LOGI("User quit the loop ");
312                         break;
313                 }
314                 list = g_list_next(list);
315         }
316         return LOCATION_BOUNDS_ERROR_NONE;
317 }
318
319 EXPORT_API int location_bounds_destroy(location_bounds_h bounds)
320 {
321         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
322         LOCATIONS_NULL_ARG_CHECK(bounds);
323
324         location_bounds_s *handle = (location_bounds_s *) bounds;
325         if (handle->is_added) {
326                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_IS_ADDED(0x%08x)", LOCATION_BOUNDS_ERROR_IS_ADDED);
327                 return LOCATION_BOUNDS_ERROR_IS_ADDED;
328         }
329         location_boundary_free(handle->boundary);
330         handle->user_cb = NULL;
331         handle->user_data = NULL;
332         free(handle);
333         LOCATIONS_LOGE("");
334         return LOCATION_BOUNDS_ERROR_NONE;
335 }
336
337 EXPORT_API int location_bounds_set_state_changed_cb(location_bounds_h bounds, location_bounds_state_changed_cb callback, void *user_data)
338 {
339         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
340         LOCATIONS_NULL_ARG_CHECK(bounds);
341         LOCATIONS_NULL_ARG_CHECK(callback);
342
343         location_bounds_s *handle = (location_bounds_s *) bounds;
344         handle->user_cb = callback;
345         handle->user_data = user_data;
346         return LOCATION_BOUNDS_ERROR_NONE;
347 }
348
349 EXPORT_API int location_bounds_unset_state_changed_cb(location_bounds_h bounds)
350 {
351         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
352         LOCATIONS_NULL_ARG_CHECK(bounds);
353
354         location_bounds_s *handle = (location_bounds_s *) bounds;
355         handle->user_cb = NULL;
356         handle->user_data = NULL;
357         return LOCATION_BOUNDS_ERROR_NONE;
358 }