1. Code synchronization with tizen_2.4
[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                 location_position_free(position);
164                 isValid = TRUE;
165         }
166
167         if (!isValid) {
168                 g_list_free_full(position_list, (GDestroyNotify) __free_position_list);
169                 return LOCATION_BOUNDS_ERROR_INVALID_PARAMETER;
170         }
171
172         if (position_list == NULL) {
173                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
174                 g_list_free_full(position_list, (GDestroyNotify) __free_position_list);
175                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
176         }
177
178         location_bounds_s *handle = (location_bounds_s *) malloc(sizeof(location_bounds_s));
179         if (handle == NULL) {
180                 LOCATIONS_LOGE("OUT_OF_MEMORY(0x%08x)", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
181                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
182         }
183         memset(handle, 0, sizeof(location_bounds_s));
184
185         handle->is_added = FALSE;
186         handle->boundary = location_boundary_new_for_polygon(position_list);
187         if (handle->boundary == NULL) {
188                 int ret = get_last_result();
189                 free(handle);
190                 if (ret == LOCATION_ERROR_PARAMETER) {
191                         LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_INVALID_PARAMETER(0x%08x) fail to location_boundary_new_for_polygon", LOCATION_BOUNDS_ERROR_INVALID_PARAMETER);
192                         return LOCATION_BOUNDS_ERROR_INVALID_PARAMETER;
193                 } else {
194                         LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_boundary_new_for_polygon", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
195                         return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
196                 }
197         }
198         handle->user_cb = NULL;
199         handle->user_data = NULL;
200
201         *bounds = (location_bounds_h) handle;
202         return LOCATION_BOUNDS_ERROR_NONE;
203 }
204
205 EXPORT_API bool location_bounds_contains_coordinates(location_bounds_h bounds, location_coords_s coords)
206 {
207         if (__is_location_supported() == LOCATIONS_ERROR_NOT_SUPPORTED) {
208                 set_last_result(LOCATIONS_ERROR_NOT_SUPPORTED);
209                 return FALSE;
210         }
211
212         if (!bounds) {
213                 set_last_result(LOCATION_BOUNDS_ERROR_INVALID_PARAMETER);
214                 return FALSE;
215         }
216
217         if (coords.latitude < -90 || coords.latitude > 90 || coords.longitude < -180 || coords.longitude > 180) {
218                 set_last_result(LOCATION_BOUNDS_ERROR_INVALID_PARAMETER);
219                 return FALSE;
220         }
221
222         LocationPosition *pos = location_position_new(0, coords.latitude, coords.longitude, 0, LOCATION_STATUS_2D_FIX);
223         if (pos == NULL) {
224                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
225                 set_last_result(LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
226                 return FALSE;
227         }
228         location_bounds_s *handle = (location_bounds_s *) bounds;
229         gboolean is_inside = location_boundary_if_inside(handle->boundary, pos);
230         location_position_free(pos);
231         bool result = is_inside ? TRUE : FALSE;
232
233         set_last_result(LOCATION_BOUNDS_ERROR_NONE);
234         return result;
235 }
236
237 EXPORT_API int location_bounds_get_type(location_bounds_h bounds, location_bounds_type_e *type)
238 {
239         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
240         LOCATIONS_NULL_ARG_CHECK(bounds);
241         LOCATIONS_NULL_ARG_CHECK(type);
242
243         location_bounds_s *handle = (location_bounds_s *) bounds;
244         *type = __convert_bounds_type(handle->boundary->type);
245         return LOCATION_BOUNDS_ERROR_NONE;
246 }
247
248 EXPORT_API int location_bounds_get_rect_coords(location_bounds_h bounds, location_coords_s *top_left, location_coords_s *bottom_right)
249 {
250         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
251         LOCATIONS_NULL_ARG_CHECK(bounds);
252         LOCATIONS_NULL_ARG_CHECK(top_left);
253         LOCATIONS_NULL_ARG_CHECK(bottom_right);
254
255         location_bounds_s *handle = (location_bounds_s *) bounds;
256         if (__convert_bounds_type(handle->boundary->type) != LOCATION_BOUNDS_RECT) {
257                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_INCORRECT_TYPE(0x%08x)", LOCATION_BOUNDS_ERROR_INCORRECT_TYPE);
258                 return LOCATION_BOUNDS_ERROR_INCORRECT_TYPE;
259         }
260
261         top_left->latitude = handle->boundary->rect.left_top->latitude;
262         top_left->longitude = handle->boundary->rect.left_top->longitude;
263         bottom_right->latitude = handle->boundary->rect.right_bottom->latitude;
264         bottom_right->longitude = handle->boundary->rect.right_bottom->longitude;
265         return LOCATION_BOUNDS_ERROR_NONE;
266 }
267
268 EXPORT_API int location_bounds_get_circle_coords(location_bounds_h bounds, location_coords_s *center, double *radius)
269 {
270         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
271         LOCATIONS_NULL_ARG_CHECK(bounds);
272         LOCATIONS_NULL_ARG_CHECK(center);
273         LOCATIONS_NULL_ARG_CHECK(radius);
274
275         location_bounds_s *handle = (location_bounds_s *) bounds;
276         if (__convert_bounds_type(handle->boundary->type) != LOCATION_BOUNDS_CIRCLE) {
277                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_INCORRECT_TYPE(0x%08x)", LOCATION_BOUNDS_ERROR_INCORRECT_TYPE);
278                 return LOCATION_BOUNDS_ERROR_INCORRECT_TYPE;
279         }
280
281         center->latitude = handle->boundary->circle.center->latitude;
282         center->longitude = handle->boundary->circle.center->longitude;
283         *radius = handle->boundary->circle.radius;
284         return LOCATION_BOUNDS_ERROR_NONE;
285 }
286
287 EXPORT_API int location_bounds_foreach_polygon_coords(location_bounds_h bounds, polygon_coords_cb callback, void *user_data)
288 {
289         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
290         LOCATIONS_NULL_ARG_CHECK(bounds);
291         LOCATIONS_NULL_ARG_CHECK(callback);
292
293         location_bounds_s *handle = (location_bounds_s *) bounds;
294         if (__convert_bounds_type(handle->boundary->type) != LOCATION_BOUNDS_POLYGON) {
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         GList *list = handle->boundary->polygon.position_list;
300         while (list) {
301                 LocationPosition *pos = list->data;
302                 location_coords_s coords;
303                 coords.latitude = pos->latitude;
304                 coords.longitude = pos->longitude;
305
306                 if (callback(coords, user_data) != TRUE) {
307                         LOCATIONS_LOGI("User quit the loop ");
308                         break;
309                 }
310                 list = g_list_next(list);
311         }
312         return LOCATION_BOUNDS_ERROR_NONE;
313 }
314
315 EXPORT_API int location_bounds_destroy(location_bounds_h bounds)
316 {
317         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
318         LOCATIONS_NULL_ARG_CHECK(bounds);
319
320         location_bounds_s *handle = (location_bounds_s *) bounds;
321         if (handle->is_added) {
322                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_IS_ADDED(0x%08x)", LOCATION_BOUNDS_ERROR_IS_ADDED);
323                 return LOCATION_BOUNDS_ERROR_IS_ADDED;
324         }
325         location_boundary_free(handle->boundary);
326         handle->user_cb = NULL;
327         handle->user_data = NULL;
328         free(handle);
329         LOCATIONS_LOGE("");
330         return LOCATION_BOUNDS_ERROR_NONE;
331 }
332
333 EXPORT_API int location_bounds_set_state_changed_cb(location_bounds_h bounds, location_bounds_state_changed_cb callback, void *user_data)
334 {
335         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
336         LOCATIONS_NULL_ARG_CHECK(bounds);
337         LOCATIONS_NULL_ARG_CHECK(callback);
338
339         location_bounds_s *handle = (location_bounds_s *) bounds;
340         handle->user_cb = callback;
341         handle->user_data = user_data;
342         return LOCATION_BOUNDS_ERROR_NONE;
343 }
344
345 EXPORT_API int location_bounds_unset_state_changed_cb(location_bounds_h bounds)
346 {
347         LOCATIONS_NOT_SUPPORTED_CHECK(__is_location_supported());
348         LOCATIONS_NULL_ARG_CHECK(bounds);
349
350         location_bounds_s *handle = (location_bounds_s *) bounds;
351         handle->user_cb = NULL;
352         handle->user_data = NULL;
353         return LOCATION_BOUNDS_ERROR_NONE;
354 }