merge with master
[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 <location_bounds.h>
21 #include <locations_private.h>
22
23
24 #define LOCATIONS_NULL_ARG_CHECK(arg)   \
25         LOCATIONS_CHECK_CONDITION((arg != NULL),LOCATION_BOUNDS_ERROR_INVALID_PARAMETER,"LOCATION_BOUNDS_ERROR_INVALID_PARAMETER") \
26
27 static void __free_position_list(gpointer data)
28 {
29         if (data == NULL)
30                 return;
31
32         LocationPosition *position = (LocationPosition *) data;
33         location_position_free(position);
34 }
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 int location_bounds_create_rect(location_coords_s top_left, location_coords_s bottom_right, location_bounds_h * bounds)
56 {
57         LOCATIONS_NULL_ARG_CHECK(bounds);
58         LOCATIONS_CHECK_CONDITION(top_left.latitude>=-90 && top_left.latitude<=90,LOCATION_BOUNDS_ERROR_INVALID_PARAMETER,"LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
59         LOCATIONS_CHECK_CONDITION(top_left.longitude>=-180 && top_left.longitude<=180,LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
60         LOCATIONS_CHECK_CONDITION(bottom_right.latitude>=-90 && bottom_right.latitude<=90,LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
61         LOCATIONS_CHECK_CONDITION(bottom_right.longitude>=-180 && bottom_right.longitude<=180,LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
62
63         LocationPosition *lt = location_position_new(0, top_left.latitude, top_left.longitude, 0, LOCATION_STATUS_2D_FIX);
64         if (lt == NULL) {
65                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
66                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
67         }
68
69         LocationPosition *rb = location_position_new(0, bottom_right.latitude, bottom_right.longitude, 0, LOCATION_STATUS_2D_FIX);
70         if (rb == NULL) {
71                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
72                 location_position_free(lt);
73                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
74         }
75
76         location_bounds_s *handle = (location_bounds_s *) malloc(sizeof(location_bounds_s));
77         if (handle == NULL) {
78                 LOCATIONS_LOGE("OUT_OF_MEMORY(0x%08x)", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
79                 location_position_free(rb);
80                 location_position_free(lt);
81                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
82         }
83         memset(handle, 0, sizeof(location_bounds_s));
84
85         handle->is_added = FALSE;
86         handle->boundary = location_boundary_new_for_rect(lt, rb);
87         location_position_free(rb);
88         location_position_free(lt);
89         if (handle->boundary == NULL) {
90                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_boundary_new_for_rect", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
91                 free(handle);
92                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
93         }
94         handle->user_cb = NULL;
95         handle->user_data = NULL;
96
97         *bounds = (location_bounds_h) handle;
98         return LOCATION_BOUNDS_ERROR_NONE;
99 }
100
101 int location_bounds_create_circle(location_coords_s center, double radius, location_bounds_h * bounds)
102 {
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                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_boundary_new_for_circle", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
127                 free(handle);
128                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
129         }
130         handle->user_cb = NULL;
131         handle->user_data = NULL;
132
133         *bounds = (location_bounds_h) handle;
134         return LOCATION_BOUNDS_ERROR_NONE;
135 }
136
137 int location_bounds_create_polygon(location_coords_s * coords_list, int length, location_bounds_h * bounds)
138 {
139         LOCATIONS_NULL_ARG_CHECK(coords_list);
140         LOCATIONS_NULL_ARG_CHECK(bounds);
141         LOCATIONS_CHECK_CONDITION(length>=3, LOCATION_BOUNDS_ERROR_INVALID_PARAMETER, "LOCATION_BOUNDS_ERROR_INVALID_PARAMETER");
142
143         int i;
144         GList *position_list = NULL;
145         LocationPosition *position = NULL;
146         bool isValid;
147
148         for (i = 0; i < length; i++) {
149                 if (coords_list[i].latitude < -90 || coords_list[i].latitude > 90 || coords_list[i].longitude < -180 || coords_list[i].longitude > 180) {
150                         LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_INVALID_PARAMETER(0x%08x)", LOCATION_BOUNDS_ERROR_INVALID_PARAMETER);
151                         isValid = FALSE;
152                         break;
153                 }
154                 position = location_position_new(0, coords_list[i].latitude, coords_list[i].longitude, 0.0, LOCATION_STATUS_2D_FIX);
155                 position_list = g_list_append(position_list, position);
156                 location_position_free(position);
157                 isValid = TRUE;
158         }
159
160         if (!isValid) {
161                 g_list_free_full(position_list, (GDestroyNotify) __free_position_list);
162                 return LOCATION_BOUNDS_ERROR_INVALID_PARAMETER;
163         }
164
165         if (position_list == NULL) {
166                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
167                 g_list_free_full(position_list, (GDestroyNotify) __free_position_list);
168                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
169         }
170
171         location_bounds_s *handle = (location_bounds_s *) malloc(sizeof(location_bounds_s));
172         if (handle == NULL) {
173                 LOCATIONS_LOGE("OUT_OF_MEMORY(0x%08x)", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
174                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
175         }
176         memset(handle, 0, sizeof(location_bounds_s));
177
178         handle->is_added = FALSE;
179         handle->boundary = location_boundary_new_for_polygon(position_list);
180         if (handle->boundary == NULL) {
181                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_boundary_new_for_polygon", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
182                 free(handle);
183                 return LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY;
184         }
185         handle->user_cb = NULL;
186         handle->user_data = NULL;
187
188         *bounds = (location_bounds_h) handle;
189         return LOCATION_BOUNDS_ERROR_NONE;
190 }
191
192 bool location_bounds_contains_coordinates(location_bounds_h bounds, location_coords_s coords)
193 {
194         if (!bounds)
195                 return FALSE;
196
197         if (coords.latitude < -90 || coords.latitude > 90 || coords.longitude < -180 || coords.longitude > 180)
198                 return FALSE;
199
200         LocationPosition *pos = location_position_new(0, coords.latitude, coords.longitude, 0, LOCATION_STATUS_2D_FIX);
201         if (pos == NULL) {
202                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY(0x%08x) : fail to location_position_new", LOCATION_BOUNDS_ERROR_OUT_OF_MEMORY);
203                 return FALSE;
204         }
205         location_bounds_s *handle = (location_bounds_s *) bounds;
206         gboolean is_inside = location_boundary_if_inside(handle->boundary, pos);
207         location_position_free(pos);
208         bool result = is_inside ? TRUE : FALSE;
209         return result;
210 }
211
212 int location_bounds_get_type(location_bounds_h bounds, location_bounds_type_e * type)
213 {
214         LOCATIONS_NULL_ARG_CHECK(bounds);
215         LOCATIONS_NULL_ARG_CHECK(type);
216         location_bounds_s *handle = (location_bounds_s *) bounds;
217         *type = __convert_bounds_type(handle->boundary->type);
218         return LOCATION_BOUNDS_ERROR_NONE;
219 }
220
221 int location_bounds_get_rect_coords(location_bounds_h bounds, location_coords_s * top_left, location_coords_s * bottom_right)
222 {
223         LOCATIONS_NULL_ARG_CHECK(bounds);
224         LOCATIONS_NULL_ARG_CHECK(top_left);
225         LOCATIONS_NULL_ARG_CHECK(bottom_right);
226         location_bounds_s *handle = (location_bounds_s *) bounds;
227         if (__convert_bounds_type(handle->boundary->type) != LOCATION_BOUNDS_RECT) {
228                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_INCORRECT_TYPE(0x%08x)", LOCATION_BOUNDS_ERROR_INCORRECT_TYPE);
229                 return LOCATION_BOUNDS_ERROR_INCORRECT_TYPE;
230         }
231
232         top_left->latitude = handle->boundary->rect.left_top->latitude;
233         top_left->longitude = handle->boundary->rect.left_top->longitude;
234         bottom_right->latitude = handle->boundary->rect.right_bottom->latitude;
235         bottom_right->longitude = handle->boundary->rect.right_bottom->longitude;
236         return LOCATION_BOUNDS_ERROR_NONE;
237 }
238
239 int location_bounds_get_circle_coords(location_bounds_h bounds, location_coords_s * center, double *radius)
240 {
241         LOCATIONS_NULL_ARG_CHECK(bounds);
242         LOCATIONS_NULL_ARG_CHECK(center);
243         LOCATIONS_NULL_ARG_CHECK(radius);
244         location_bounds_s *handle = (location_bounds_s *) bounds;
245         if (__convert_bounds_type(handle->boundary->type) != LOCATION_BOUNDS_CIRCLE) {
246                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_INCORRECT_TYPE(0x%08x)", LOCATION_BOUNDS_ERROR_INCORRECT_TYPE);
247                 return LOCATION_BOUNDS_ERROR_INCORRECT_TYPE;
248         }
249
250         center->latitude = handle->boundary->circle.center->latitude;
251         center->longitude = handle->boundary->circle.center->longitude;
252         *radius = handle->boundary->circle.radius;
253         return LOCATION_BOUNDS_ERROR_NONE;
254 }
255
256 int location_bounds_foreach_polygon_coords(location_bounds_h bounds, polygon_coords_cb callback, void *user_data)
257 {
258         LOCATIONS_NULL_ARG_CHECK(bounds);
259         LOCATIONS_NULL_ARG_CHECK(callback);
260         location_bounds_s *handle = (location_bounds_s *) bounds;
261         if (__convert_bounds_type(handle->boundary->type) != LOCATION_BOUNDS_POLYGON) {
262                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_INCORRECT_TYPE(0x%08x)", LOCATION_BOUNDS_ERROR_INCORRECT_TYPE);
263                 return LOCATION_BOUNDS_ERROR_INCORRECT_TYPE;
264         }
265
266         GList *list = handle->boundary->polygon.position_list;
267         while (list) {
268                 LocationPosition *pos = list->data;
269                 location_coords_s coords;
270                 coords.latitude = pos->latitude;
271                 coords.longitude = pos->longitude;
272
273                 if (callback(coords, user_data) != TRUE) {
274                         LOCATIONS_LOGI("User quit the loop ");
275                         break;
276                 }
277                 list = g_list_next(list);
278         }
279         return LOCATION_BOUNDS_ERROR_NONE;
280 }
281
282 int location_bounds_destroy(location_bounds_h bounds)
283 {
284         LOCATIONS_NULL_ARG_CHECK(bounds);
285         location_bounds_s *handle = (location_bounds_s *) bounds;
286         if (handle->is_added) {
287                 LOCATIONS_LOGE("LOCATION_BOUNDS_ERROR_IS_ADDED(0x%08x)", LOCATION_BOUNDS_ERROR_IS_ADDED);
288                 return LOCATION_BOUNDS_ERROR_IS_ADDED;
289         }
290         location_boundary_free(handle->boundary);
291         handle->user_cb = NULL;
292         handle->user_data = NULL;
293         free(handle);
294         LOCATIONS_LOGE("");
295         return LOCATION_BOUNDS_ERROR_NONE;
296 }
297
298 int location_bounds_set_state_changed_cb(location_bounds_h bounds, location_bounds_state_changed_cb callback, void *user_data)
299 {
300         LOCATIONS_NULL_ARG_CHECK(bounds);
301         LOCATIONS_NULL_ARG_CHECK(callback);
302         location_bounds_s *handle = (location_bounds_s *) bounds;
303         handle->user_cb = callback;
304         handle->user_data = user_data;
305         return LOCATION_BOUNDS_ERROR_NONE;
306 }
307
308 int location_bounds_unset_state_changed_cb(location_bounds_h bounds)
309 {
310         LOCATIONS_NULL_ARG_CHECK(bounds);
311         location_bounds_s *handle = (location_bounds_s *) bounds;
312         handle->user_cb = NULL;
313         handle->user_data = NULL;
314         return LOCATION_BOUNDS_ERROR_NONE;
315 }