From d11b203c332dc12a343c6d90895bff69455537d4 Mon Sep 17 00:00:00 2001 From: Kevin Kreiser Date: Thu, 16 Jun 2016 11:46:59 -0400 Subject: [PATCH] Adds base from the mapquests plugin Change-Id: I8999fd8fac54ba9bde4f746fb18dbe529e9c8172 --- .gitmodules | 3 + CMakeLists.txt | 1 + README.md | 2 + inc/mapzen_api.h | 27 + inc/mapzen_constants.h | 38 + inc/mapzen_plugin.h | 102 ++ inc/mapzen_plugin_internal.h | 61 + inc/mapzen_utils.h | 15 + rapidjson | 1 + src/mapzen/mapzen_api.c | 75 ++ src/mapzen/mapzen_api.h | 68 + src/mapzen/mapzen_debug.h | 38 + src/mapzen/mapzen_geocode.c | 78 ++ src/mapzen/mapzen_geocode.h | 26 + src/mapzen/mapzen_jsonparser.c | 307 +++++ .../mapzen_jsonparser.h} | 13 +- src/mapzen/mapzen_place.c | 87 ++ src/mapzen/mapzen_place.h | 25 + src/mapzen/mapzen_queue.c | 1263 ++++++++++++++++++ src/mapzen/mapzen_queue.h | 72 + src/mapzen/mapzen_restcurl.c | 671 ++++++++++ src/mapzen/mapzen_restcurl.h | 34 + src/mapzen/mapzen_revgeocode.c | 42 + src/mapzen/mapzen_revgeocode.h | 25 + src/mapzen/mapzen_route.c | 123 ++ src/mapzen/mapzen_route.h | 25 + src/mapzen/mapzen_server_private.h | 102 ++ src/mapzen/mapzen_types.h | 192 +++ src/mapzen/mapzen_util.c | 45 + src/mapzen/mapzen_util.h | 27 + src/mapzen_api.cpp | 36 + src/mapzen_plugin.c | 1395 ++++++++++++++++++++ src/mapzen_plugin.cpp | 241 ---- 33 files changed, 5012 insertions(+), 248 deletions(-) create mode 100644 .gitmodules create mode 100644 inc/mapzen_api.h create mode 100644 inc/mapzen_constants.h create mode 100644 inc/mapzen_plugin.h create mode 100644 inc/mapzen_plugin_internal.h create mode 160000 rapidjson create mode 100644 src/mapzen/mapzen_api.c create mode 100644 src/mapzen/mapzen_api.h create mode 100644 src/mapzen/mapzen_debug.h create mode 100644 src/mapzen/mapzen_geocode.c create mode 100644 src/mapzen/mapzen_geocode.h create mode 100644 src/mapzen/mapzen_jsonparser.c rename src/{mapzen_utils.cpp => mapzen/mapzen_jsonparser.h} (74%) create mode 100644 src/mapzen/mapzen_place.c create mode 100644 src/mapzen/mapzen_place.h create mode 100644 src/mapzen/mapzen_queue.c create mode 100644 src/mapzen/mapzen_queue.h create mode 100644 src/mapzen/mapzen_restcurl.c create mode 100644 src/mapzen/mapzen_restcurl.h create mode 100644 src/mapzen/mapzen_revgeocode.c create mode 100644 src/mapzen/mapzen_revgeocode.h create mode 100644 src/mapzen/mapzen_route.c create mode 100644 src/mapzen/mapzen_route.h create mode 100644 src/mapzen/mapzen_server_private.h create mode 100644 src/mapzen/mapzen_types.h create mode 100644 src/mapzen/mapzen_util.c create mode 100644 src/mapzen/mapzen_util.h create mode 100644 src/mapzen_api.cpp create mode 100644 src/mapzen_plugin.c delete mode 100644 src/mapzen_plugin.cpp diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..21ec3ff --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "rapidjson"] + path = rapidjson + url = https://github.com/miloyip/rapidjson diff --git a/CMakeLists.txt b/CMakeLists.txt index 6a0b313..0373c39 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,6 +61,7 @@ SET(SRCS # Maps API src/mapzen_utils.cpp src/mapzen_plugin.cpp + src/mapzen_api.cpp ) ADD_LIBRARY(${pkg_name} SHARED ${SRCS}) diff --git a/README.md b/README.md index 908d14d..4147a0b 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ gbs build --include-all -A i586 # to push to device sdb push ~/GBS-ROOT/local/BUILD-ROOTS/scratch..0/home/abuild/rpmbuild/RPMS//maps-plugin-mapzen-0.0.1-1..rpm /mnt/ +sdb shell + # install rpm -Uvh --force /mnt/maps-plugin-mapzen-0.0.1-1..rpm diff --git a/inc/mapzen_api.h b/inc/mapzen_api.h new file mode 100644 index 0000000..fe46189 --- /dev/null +++ b/inc/mapzen_api.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MAPZEN_API_H_ +#define _MAPZEN_API_H_ + +#include +#include + +int MapzenPluginRoute(maps_coordinates_h origin, maps_coordinates_h destination, + maps_item_hashtable_h pref, maps_service_search_route_cb callback_function, + void* user_data, int* request_id); + +#endif // _MAPZEN_API_H_ diff --git a/inc/mapzen_constants.h b/inc/mapzen_constants.h new file mode 100644 index 0000000..81f39c2 --- /dev/null +++ b/inc/mapzen_constants.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MAPZEN_CONSTANTS_H_ +#define _MAPZEN_CONSTANTS_H_ + +// Error types +enum ErrorType { + kNone = 0, // Success + kPermissionDenied, // Permission denied + kOutOfMemory, // Out of memory + kInvalidParameter, // Invalid parameter + kNotSupported, // Unsupported operation + kConnectionTimeout, // Connection timeout + kNetworkUnreachable, // Network unavailable + kInvalidOperation, // Invalid operation + kInvalidKey, // Invalid key + kResourceBusy, // Resource busy + kCancelled, // Service cancelled + kUnknown, // Unknown error + kServiceUnavailable, // Service unavailable + kResultNotFound // Result not found +}; + +#endif // _MAPZEN_CONSTANTS_H_ diff --git a/inc/mapzen_plugin.h b/inc/mapzen_plugin.h new file mode 100644 index 0000000..acfb4d3 --- /dev/null +++ b/inc/mapzen_plugin.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MAPZEN_PLUGIN_H_ +#define _MAPZEN_PLUGIN_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct callback_geocode { + maps_service_geocode_cb callback; + void *data; + int reqID; +} callback_info_geocode; + +typedef struct callback_reverse_geocode { + maps_service_reverse_geocode_cb callback; + void *data; + int reqID; +} callback_info_reverse_geocode; + +typedef struct callback_route { + maps_service_search_route_cb callback; + void *data; + int reqID; +} callback_info_route; + +typedef struct callback_place { + maps_service_search_place_cb callback; + void *data; + int reqID; +} callback_info_place; + +int maps_plugin_init(maps_plugin_h *plugin); + +int maps_plugin_shutdown(maps_plugin_h plugin); + +int maps_plugin_is_service_supported(maps_service_e service, bool *supported); + +int maps_plugin_is_data_supported(maps_service_data_e data, bool *supported); + +int maps_plugin_get_info(maps_plugin_info_h *info); + +int maps_plugin_set_provider_key(const char *provider_key); + +int maps_plugin_get_provider_key(char **provider_key); + +int maps_plugin_set_preference(maps_item_hashtable_h preference); + +int maps_plugin_get_preference(maps_item_hashtable_h *preference); + +/* Geocode */ +int maps_plugin_geocode(const char *address, const maps_preference_h preference, maps_service_geocode_cb callback, void *user_data, int *request_id); + +/* Geocode inside area */ +int maps_plugin_geocode_inside_area(const char *address, const maps_area_h bounds, const maps_preference_h preference, maps_service_geocode_cb callback, void *user_data, int *request_id); + +/* Geocode by structured address */ +int maps_plugin_geocode_by_structured_address(const maps_address_h address, const maps_preference_h preference, maps_service_geocode_cb callback, void *user_data, int *request_id); + +/* Rev Geocode */ +int maps_plugin_reverse_geocode(double latitude, double longitude, const maps_preference_h preference, maps_service_reverse_geocode_cb callback, void *user_data, int *request_id); + +/* Route search */ +int maps_plugin_search_route(const maps_coordinates_h origin, const maps_coordinates_h destination, maps_preference_h preference, maps_service_search_route_cb callback, void *user_data, int *request_id); + +/* Route search waypoints */ +int maps_plugin_search_route_waypoints(const maps_coordinates_h *waypoint_list, int waypoint_num, maps_preference_h preference, maps_service_search_route_cb callback, void *user_data, int *request_id); + +/* Place search */ +int maps_plugin_search_place(const maps_coordinates_h position, int distance, const maps_place_filter_h filter, maps_preference_h preference, maps_service_search_place_cb callback, void *user_data, int *request_id); + +/* Place search by area */ +int maps_plugin_search_place_by_area(const maps_area_h boundary, const maps_place_filter_h filter, maps_preference_h preference, maps_service_search_place_cb callback, void *user_data, int *request_id); + +/* Place search by address */ +int maps_plugin_search_place_by_address(const char *address, const maps_area_h boundary, const maps_place_filter_h filter, maps_preference_h preference, maps_service_search_place_cb callback, void *user_data, int *request_id); + +/* Cancel Request */ +int maps_plugin_cancel_request(int request_id); + +#ifdef __cplusplus +} +#endif +#endif /* _MAPZEN_PLUGIN_H_ */ diff --git a/inc/mapzen_plugin_internal.h b/inc/mapzen_plugin_internal.h new file mode 100644 index 0000000..517bdc4 --- /dev/null +++ b/inc/mapzen_plugin_internal.h @@ -0,0 +1,61 @@ +/* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MAPZEN_PLUGIN_INTERNAL_H__ +#define __MAPZEN_PLUGIN_INTERNAL_H__ + +#include + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "MAPZEN_PLUGIN" + +/* + * Internal Macros + */ +#define MAPS_LOGD(fmt, args...) LOGD(fmt, ##args) +#define MAPS_LOGW(fmt, args...) LOGW(fmt, ##args) +#define MAPS_LOGI(fmt, args...) LOGI(fmt, ##args) +#define MAPS_LOGE(fmt, args...) LOGE(fmt, ##args) +#define MAPS_SECLOG(fmt, args...) SECURE_LOGD(fmt, ##args) + +#define MAPS_CHECK_CONDITION(condition, error, msg) \ + do { \ + if (condition) { \ + } else { \ + MAPS_LOGE("%s(0x%08x)", msg, error); \ + return error; \ + } \ + } while (0) + +#define MAPS_NULL_ARG_CHECK_RETURN_FALSE(arg)\ + do { \ + if (arg != NULL) { \ + } else { \ + MAPS_LOGE("MAPS_ERROR_INVALID_PARAMETER"); \ + return false; }; \ + } while (0) + +#define MAPS_NULL_ARG_CHECK(arg) \ + MAPS_CHECK_CONDITION(arg != NULL, MAPS_ERROR_INVALID_PARAMETER, "MAPS_ERROR_INVALID_PARAMETER") + +#define MAPS_PRINT_ERROR_CODE_RETURN(code) \ + do { \ + MAPS_LOGE("%s(0x%08x)", #code, code); \ + return code; \ + } while (0) + +#endif /* __MAPZEN_PLUGIN_INTERNAL_H__ */ diff --git a/inc/mapzen_utils.h b/inc/mapzen_utils.h index 30646c5..e88abef 100644 --- a/inc/mapzen_utils.h +++ b/inc/mapzen_utils.h @@ -14,6 +14,8 @@ * limitations under the License. */ +#include +#include #include #include #include @@ -22,12 +24,25 @@ extern "C" { + } +constexpr double kPolylinePrecision = 1E6; +constexpr double kInvPolylinePrecision = 1.0 / kPolylinePrecision; + class MapzenUtils { public: MapzenUtils(); ~MapzenUtils(); + + // Is the map coordinate valid (in valid latitude,longitude range) + static bool IsValid(maps_coordinates_s& coord); + + // Decode the shape string returned in the route result + void DecodeShape(const std::string& encoded, + std::vector& output); + private: }; + diff --git a/rapidjson b/rapidjson new file mode 160000 index 0000000..3d5848a --- /dev/null +++ b/rapidjson @@ -0,0 +1 @@ +Subproject commit 3d5848a7cd3367c5cb451c6493165b7745948308 diff --git a/src/mapzen/mapzen_api.c b/src/mapzen/mapzen_api.c new file mode 100644 index 0000000..4eb72b5 --- /dev/null +++ b/src/mapzen/mapzen_api.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "mapzen_api.h" +#include "mapzen_server_private.h" +#include "mapzen_queue.h" +#include "mapzen_debug.h" + +EXPORT_API int mapzen_init() +{ + int ret = mapzen_init_queue(); + + return ret; +} + +EXPORT_API int mapzen_shutdown() +{ + int ret = mapzen_deinit_queue(); + + return ret; +} + +EXPORT_API int mapzen_geocode(mapzen_geocode_req_s *req_details, mapzen_geocode_cb callback, int request_id, void *user_data) +{ + int ret = MAPZEN_ERROR_NONE; + ret = start_geocode_service(req_details, callback, request_id, user_data); + + return ret; +} + +EXPORT_API int mapzen_cancel_request(int request_id) +{ + int ret = remove_from_request_list(request_id); + + return ret; +} + +EXPORT_API int mapzen_reverse_geocode(mapzen_revgeocode_req_s *req_details, mapzen_reverse_geocode_cb callback, int request_id, void *user_data) +{ + int ret = MAPZEN_ERROR_NONE; + ret = start_reversegeocode_service(req_details, callback, request_id, user_data); + + return ret; +} + +EXPORT_API int mapzen_search_place(mapzen_search_req_s *req_details, mapzen_place_search_cb callback, int request_id, void *user_data) +{ + int ret = MAPZEN_ERROR_NONE; + ret = start_places_service(req_details, callback, request_id, user_data); + + return ret; +} + +EXPORT_API int mapzen_start_route(mapzen_route_req_s *req_details, mapzen_route_cb callback, int request_id, void *user_data) +{ + int ret = MAPZEN_ERROR_NONE; + ret = start_route_service(req_details, callback, request_id, user_data); + + return ret; +} diff --git a/src/mapzen/mapzen_api.h b/src/mapzen/mapzen_api.h new file mode 100644 index 0000000..ceddc3a --- /dev/null +++ b/src/mapzen/mapzen_api.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MAPZEN_API_H_ +#define _MAPZEN_API_H_ + +#include "mapzen_types.h" +#include + +/** + * @ingroup MAPZEN_ENGINE_MODULE + * @defgroup MAPZEN_ENGINE_API_MODULE + * + * @file mapzen_api.h + * @brief This file contains the Mapzen engine API's that should be called by the plugin + * + * @addtogroup MAPZEN_ENGINE_MODULE + * @{ + * @brief This provides APIs related to Mapzen engine. + */ + +#ifdef __cplusplus +extern "C" { +#endif + + /* Callbacks */ +typedef void (*mapzen_geocode_cb) (mapzen_error_e result, int request_id, GList *co_ordinates, void *user_data); + +typedef void (*mapzen_reverse_geocode_cb) (mapzen_error_e result, int request_id, mapzen_address_resp_s *address, void *user_data); + +typedef void (*mapzen_place_search_cb) (mapzen_error_e result, int request_id, GList *places, void *user_data); + +typedef void (*mapzen_route_cb) (mapzen_error_e result, int request_id, mapzen_route_resp_s *route_info, void *user_data); + +typedef void (*mapzen_maptile_cb) (mapzen_error_e result, int request_id, char *buffer, void *user_data); + +int mapzen_init(); + +int mapzen_shutdown(); + +int mapzen_geocode(mapzen_geocode_req_s *req_details, mapzen_geocode_cb callback, int request_id, void *user_data); + +int mapzen_cancel_request(int request_id); + +int mapzen_reverse_geocode(mapzen_revgeocode_req_s *req_details, mapzen_reverse_geocode_cb callback, int request_id, void *user_data); + +int mapzen_search_place(mapzen_search_req_s *req_details, mapzen_place_search_cb callback, int request_id, void *user_data); + +int mapzen_start_route(mapzen_route_req_s *req_details, mapzen_route_cb callback, int request_id, void *user_data); + +#ifdef __cplusplus +} +#endif + +#endif /* _MAPZEN_API_H_ */ diff --git a/src/mapzen/mapzen_debug.h b/src/mapzen/mapzen_debug.h new file mode 100644 index 0000000..78b8767 --- /dev/null +++ b/src/mapzen/mapzen_debug.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef _MAPZEN_DEBUG_H_ +#define _MAPZEN_DEBUG_H_ + +#include +#include +#include + +#ifdef LOG_TAG +#undef LOG_TAG +#endif + +#define EXPORT_API __attribute__((visibility("default"))) + +#define LOG_TAG "MAPZEN_ENGINE" + +/* normal log */ +#define MAP_DEBUG(fmt, args...) LOGD(fmt, ##args) +#define MAP_ENTER() LOGD(WCOLOR_GREEN "BEGIN >>>>" WCOLOR_END) +#define MAP_LEAVE() LOGD(WCOLOR_GREEN "END <<<<" WCOLOR_END) + +#endif /* _MAPZEN_DEBUG_H_ */ diff --git a/src/mapzen/mapzen_geocode.c b/src/mapzen/mapzen_geocode.c new file mode 100644 index 0000000..c7719cf --- /dev/null +++ b/src/mapzen/mapzen_geocode.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include "mapzen_geocode.h" +#include "mapzen_types.h" +#include "mapzen_server_private.h" +#include "mapzen_debug.h" +#include "mapzen_queue.h" +#include "mapzen_restcurl.h" +#include "mapzen_util.h" + +#define GEOCODE_URL "https://open.mapzenapi.com/geocoding/v1/address?key=%s&inFormat=kvp&outFormat=json" + +int query_geocode_within_bounds(gchar *maps_key, char *address, coords_s top_left, coords_s bottom_right, int num_results, gpointer user_data) +{ + char url[1024]; + char tmpStr[512]; + + if (maps_key != NULL) + snprintf(tmpStr, sizeof(tmpStr), GEOCODE_URL, maps_key); + else + snprintf(tmpStr, sizeof(tmpStr), GEOCODE_URL, "null"); + + STRCPY(url, tmpStr); + + snprintf(tmpStr, sizeof(tmpStr), "&boundingBox=%f,%f,%f,%f", top_left.latitude, top_left.longitude, bottom_right.latitude, bottom_right.longitude); + STRCAT(url, tmpStr); + + snprintf(tmpStr, sizeof(tmpStr), "&maxResults=%d", num_results); + STRCAT(url, tmpStr); + + snprintf(tmpStr, sizeof(tmpStr), "&location=%s", address); + STRCAT(url, tmpStr); + + add_handle(url, REQ_TYPE_GEOCODE, user_data); + + return 0; +} + +int query_geocode(gchar *maps_key, char *address, int num_results, gpointer user_data) +{ + MAP_DEBUG("geocode address : %s", address); + char url[1024]; + char tmpStr[512]; + + if (maps_key != NULL) + snprintf(tmpStr, sizeof(tmpStr), GEOCODE_URL, maps_key); + else + snprintf(tmpStr, sizeof(tmpStr), GEOCODE_URL, "null"); + + STRCPY(url, tmpStr); + + snprintf(tmpStr, sizeof(tmpStr), "&maxResults=%d", num_results); + STRCAT(url, tmpStr); + + snprintf(tmpStr, sizeof(tmpStr), "&location=%s", address); + STRCAT(url, tmpStr); + + add_handle(url, REQ_TYPE_GEOCODE, user_data); + + return 0; +} diff --git a/src/mapzen/mapzen_geocode.h b/src/mapzen/mapzen_geocode.h new file mode 100644 index 0000000..d4035ae --- /dev/null +++ b/src/mapzen/mapzen_geocode.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MAPZEN_GEOCODE_H_ +#define _MAPZEN_GEOCODE_H_ + +#include "mapzen_api.h" +#include "mapzen_types.h" + +int query_geocode(gchar *maps_key, char *address, int num_results, gpointer user_data); +int query_geocode_within_bounds(gchar *maps_key, char *address, coords_s top_left, coords_s bottom_right, int num_results, gpointer user_data); + +#endif /* MAPZEN_GEOCODE_H_ */ diff --git a/src/mapzen/mapzen_jsonparser.c b/src/mapzen/mapzen_jsonparser.c new file mode 100644 index 0000000..62142a8 --- /dev/null +++ b/src/mapzen/mapzen_jsonparser.c @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "rapidjson/rapidjson.h" +#include "mapzen_jsonparser.h" +#include "mapzen_queue.h" +#include "mapzen_debug.h" +#include "mapzen_util.h" + +#define ROUTE_UNIT_CONVERSION_MILE_TO_M(x) (1609.34 * (x)) +#define ROUTE_UNIT_CONVERSION_MILE_TO_KM(x) (1.60934 * (x)) +#define ROUTE_UNIT_CONVERSION_MILE_TO_FT(x) (5280 * (x)) +#define ROUTE_UNIT_CONVERSION_MILE_TO_YD(x) (1760 * (x)) + +static route_unit __route_unit = ROUTE_UNIT_M; +static int __maneuver_index = 0; +static coords_s __destination_point; + +static mapzen_error_e __convert_status(int status) +{ + mapzen_error_e error = MAPZEN_ERROR_UNKNOWN; + switch (status) { + case 0: + { + /* Successful Geocode call */ + error = MAPZEN_ERROR_NONE; + break; + } + case 400: + { + /* Error with input - Illegal argument from request */ + error = MAPZEN_ERROR_INVALID_PARAMETER; + break; + } + case 403: + { + /* Key related error - Invalid key */ + error = MAPZEN_ERROR_KEY_NOT_AVAILABLE; + break; + } + case 500: + { + /* Unknown error */ + error = MAPZEN_ERROR_UNKNOWN; + break; + } + case -1: + { + /* Network error */ + error = MAPZEN_ERROR_NETWORK_UNREACHABLE; + break; + } + } + + return error; +} + +/************ GEOCODE ***************/ + + +static void __parse_geocode_response(char *response, int size, int *status, GList **coordsList) +{ + if (!response || !status || !coordsList) return; + + *coordsList = NULL; + + //TODO: +} + +/****************** REVERSE GEOCODE *********************/ + +static void __parse_revgeocode_response(char *response, int size, int *status, mapzen_address_resp_s **respAddr) +{ + if (!response || !status || !respAddr) return; + + *respAddr = NULL; + + //TODO: +} + +/**************** PLACE SEARCH ********************/ + +static void __parse_place_response(char *response, int size, GList **placeList) +{ + if (!response || !placeList) return; + + *placeList = NULL; + + //TODO +} + +/********************* ROUTE RESPONSE ***********************/ + +static void __parse_route_response(char *response, int size, int *status, mapzen_route_resp_s **routeResp) +{ + if (!response || !status || !routeResp) return; + + *routeResp = NULL; + +} + +void post_curl_response(char *response, int size, mapzen_resp_type type, void *user_data) +{ + if (!response) return; + + if (!user_data) { + MAP_DEBUG("Response data is NULL"); + return; + } + + MAP_DEBUG("Response received from Curl. [Size=%d]", size); + switch (type) { + case RESP_TYPE_GEOCODE: + { + MAP_DEBUG("Inside Geocode JSON Parsing.."); + int status = -1; + MapzenGeocodeQueryData *queryData = (MapzenGeocodeQueryData *)user_data; + MapzenGeocodeResponseData *responseData = (MapzenGeocodeResponseData *)g_malloc(sizeof(MapzenGeocodeResponseData)); + + if (responseData) { + responseData->requestId = queryData->requestId; + responseData->geocode_cb = queryData->geocode_cb; + responseData->user_data = queryData->user_data; + + if (response && (size > 0)) { + GList *coordsList = NULL; + __parse_geocode_response(response, size, &status, &coordsList); + + if (coordsList != NULL) { + /* Put the response in queue */ + responseData->error = __convert_status(status); + responseData->coords = coordsList; + } else { + /* Response parsing failure */ + responseData->error = __convert_status(status); + responseData->coords = NULL; + } + } else { + responseData->error = __convert_status(status); + responseData->coords = NULL; + } + + mapzen_push_to_queue(type, (gpointer)responseData); + } + + if (queryData) { + g_free(queryData); + queryData = NULL; + } + break; + } + case RESP_TYPE_REVGEOCODE: + { + MAP_DEBUG("Inside Rev Geocode JSON Parsing.."); + int status = -1; + MapzenRevGeocodeQueryData *queryData = (MapzenRevGeocodeQueryData *)user_data; + MapzenRevGeocodeResponseData *responseData = (MapzenRevGeocodeResponseData *)g_malloc(sizeof(MapzenRevGeocodeResponseData)); + + if (responseData) { + responseData->requestId = queryData->requestId; + responseData->reverse_geocode_cb = queryData->reverse_geocode_cb; + responseData->user_data = queryData->user_data; + + if (response && (size > 0)) { + /* Coords Result GList */ + mapzen_address_resp_s *addrResponse = NULL; + + MAP_DEBUG("Rev Geocode :- Parsing json Response"); + __parse_revgeocode_response(response, size, &status, &addrResponse); + + if (addrResponse != NULL) { + /* Put the response in queue */ + responseData->error = __convert_status(status); + responseData->addressDetails = addrResponse; + } else { + /* REPSONSE PARSING FAILURE */ + MAP_DEBUG("addr Response is NULL"); + responseData->error = __convert_status(status); + responseData->addressDetails = NULL; + } + } else { + MAP_DEBUG("JSON Response is NULL.."); + responseData->error = __convert_status(status); + responseData->addressDetails = NULL; + } + + mapzen_push_to_queue(type, (gpointer)responseData); + } + + if (queryData) { + g_free(queryData); + queryData = NULL; + } + break; + } + case RESP_TYPE_PLACES: + { + MAP_DEBUG("Inside Places JSON Parsing.."); + MapzenPlaceQueryData *queryData = (MapzenPlaceQueryData *)user_data; + MapzenPlaceResponseData *responseData = (MapzenPlaceResponseData *)g_malloc(sizeof(MapzenPlaceResponseData)); + + if (responseData) { + responseData->requestId = queryData->requestId; + responseData->place_search_cb = queryData->place_search_cb; + responseData->user_data = queryData->user_data; + + if (response && (size > 0)) { + /* Coords Result GList */ + GList *placeList = NULL; + + MAP_DEBUG("Search Places :- Parsing Json Response"); + __parse_place_response(response, size, &placeList); + + if (placeList != NULL) { + /* Put the response in queue */ + responseData->error = MAPZEN_ERROR_NONE; + responseData->places = placeList; + } else { + /* REPSONSE PARSING FAILURE */ + MAP_DEBUG("addr Response is NULL"); + responseData->error = MAPZEN_ERROR_UNKNOWN; + responseData->places = NULL; + } + } else { + responseData->error = MAPZEN_ERROR_UNKNOWN; + responseData->places = NULL; + } + + mapzen_push_to_queue(type, (gpointer)responseData); + } + + if (queryData) { + g_free(queryData); + queryData = NULL; + } + + break; + } + case RESP_TYPE_ROUTE: + { + MAP_DEBUG("Inside Route JSON Parsing.."); + int status = -1; + MapzenRouteQueryData *queryData = (MapzenRouteQueryData *)user_data; + __route_unit = queryData->unit; + __maneuver_index = 0; + __destination_point = queryData->destination; + + MapzenRouteResponseData *responseData = (MapzenRouteResponseData *)g_malloc(sizeof(MapzenRouteResponseData)); + + if (responseData) { + responseData->requestId = queryData->requestId; + responseData->route_cb = queryData->route_cb; + responseData->user_data = queryData->user_data; + + if (response && (size > 0)) { + /* Coords Result GList */ + mapzen_route_resp_s *routeResponse = NULL; + + MAP_DEBUG("Route :- Parsing Response"); + __parse_route_response(response, size, &status, &routeResponse); + + if (routeResponse != NULL) { + /* Put the response in queue */ + responseData->error = __convert_status(status); + responseData->routeResponse = routeResponse; + } else { + /* REPSONSE PARSING FAILURE */ + MAP_DEBUG("route Response is NULL"); + responseData->error = __convert_status(status); + responseData->routeResponse = NULL; + } + } else { + responseData->error = __convert_status(status); + responseData->routeResponse = NULL; + } + + mapzen_push_to_queue(type, (gpointer)responseData); + } + + if (queryData) { + g_free(queryData); + queryData = NULL; + } + + break; + } + default: + { + MAP_DEBUG("Inside default JSON Parsing.."); + break; + } + } +} diff --git a/src/mapzen_utils.cpp b/src/mapzen/mapzen_jsonparser.h similarity index 74% rename from src/mapzen_utils.cpp rename to src/mapzen/mapzen_jsonparser.h index fff89d2..9a766eb 100644 --- a/src/mapzen_utils.cpp +++ b/src/mapzen/mapzen_jsonparser.h @@ -14,12 +14,11 @@ * limitations under the License. */ -#include "mapzen_utils.h" +#ifndef _MAPZEN_JSONPARSER_H_ +#define _MAPZEN_JSONPARSER_H_ -MapzenUtils::MapzenUtils() -{ -} +#include "mapzen_server_private.h" -MapzenUtils::~MapzenUtils() -{ -} +void post_curl_response(char *response, int size, mapzen_resp_type type, void *user_data); + +#endif /* _MAPZEN_JSONPARSER_H_ */ diff --git a/src/mapzen/mapzen_place.c b/src/mapzen/mapzen_place.c new file mode 100644 index 0000000..8df590a --- /dev/null +++ b/src/mapzen/mapzen_place.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include "mapzen_place.h" +#include "mapzen_types.h" +#include "mapzen_server_private.h" +#include "mapzen_debug.h" +#include "mapzen_queue.h" +#include "mapzen_restcurl.h" +#include "mapzen_util.h" + +#define PLACES_URL "https://open.mapzenapi.com/nominatim/v1/search.php?format=json" + +int query_places(gchar *maps_key, gchar *search_str, mapzen_boundary_s *boundary, int num_res, gpointer user_data) +{ + char url[1024]; + char tmpStr[512]; + + STRCPY(url, PLACES_URL); + + if (search_str != NULL) { + snprintf(tmpStr, sizeof(tmpStr), "&q=%s", search_str); + strncat(url, tmpStr, sizeof(url)-strlen(url)-1); + } + + if (boundary != NULL) { + if (boundary->type == MAPZEN_BOUNDARY_RECT) { + snprintf(tmpStr, sizeof(tmpStr), "&viewbox=%f,%f,%f,%f", boundary->rect.top_left.longitude, boundary->rect.top_left.latitude, boundary->rect.bottom_right.longitude, boundary->rect.bottom_right.latitude); + + strncat(url, tmpStr, sizeof(url)-strlen(url)-1); + } else if (boundary->type == MAPZEN_BOUNDARY_CIRCLE) { + coords_s *top_left = NULL, *bottom_right = NULL; + coords_s circle = boundary->circle.center; + gdouble radius = (boundary->circle.radius) * 0.001; + + /* Calculate the top left coordinate of bounding box. */ + calculate_point(circle.latitude, circle.longitude, 315, radius, &top_left); + + /* Calculate the bottom right coordinate of bounding box. */ + calculate_point(circle.latitude, circle.longitude, 135, radius, &bottom_right); + + if (top_left && bottom_right) { + snprintf(tmpStr, sizeof(tmpStr), "&viewbox=%f,%f,%f,%f", top_left->longitude, top_left->latitude, bottom_right->longitude, bottom_right->latitude); + strncat(url, tmpStr, sizeof(url)-strlen(url)-1); + } + + if (top_left) { + g_free(top_left); + top_left = NULL; + } + if (bottom_right) { + g_free(bottom_right); + bottom_right = NULL; + } + } + + STRCAT(url, "&bounded=1"); + } + + STRCAT(url, "&addressdetails=1"); + + if (num_res > 0) { + snprintf(tmpStr, sizeof(tmpStr), "&limit=%d", num_res); + STRCAT(url, tmpStr); + } + + add_handle(url, REQ_TYPE_PLACES, user_data); + + return 0; +} diff --git a/src/mapzen/mapzen_place.h b/src/mapzen/mapzen_place.h new file mode 100644 index 0000000..ed122a1 --- /dev/null +++ b/src/mapzen/mapzen_place.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MAPZEN_PLACES_H_ +#define _MAPZEN_PLACES_H_ + +#include "mapzen_api.h" +#include "mapzen_types.h" + +int query_places(gchar *maps_key, gchar *search_str, mapzen_boundary_s *boundary, int num_res, gpointer user_data); + +#endif /* _MAPZEN_PLACES_H_ */ diff --git a/src/mapzen/mapzen_queue.c b/src/mapzen/mapzen_queue.c new file mode 100644 index 0000000..da8364a --- /dev/null +++ b/src/mapzen/mapzen_queue.c @@ -0,0 +1,1263 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "mapzen_queue.h" +#include "mapzen_geocode.h" +#include "mapzen_revgeocode.h" +#include "mapzen_route.h" +#include "mapzen_place.h" +#include "mapzen_restcurl.h" +#include "mapzen_util.h" +#include "mapzen_debug.h" +#include + +pthread_mutex_t __requestLock; +static GAsyncQueue *responseQueue = NULL; +int __ResponseQueueLen = 0; +bool __response_timer_running = false; + +/* Request List */ +GList *requestList = NULL; + +/* Request Cancel List */ +GList *reqCancelList = NULL; + +static void __free_geocode_response(void *ptr); +static void __free_revgeocode_response(void *ptr); +static void __free_place_response(void *ptr); +static void __free_route_response(void *ptr); + +int add_to_geocode_list(mapzen_geocode_req_s *req_details, mapzen_geocode_cb callback, int request_id, void *user_data) +{ + mapzen_request_s *req = (mapzen_request_s *)g_malloc0(sizeof(mapzen_request_s)); + + if (req != NULL) { + + req->type = REQ_TYPE_GEOCODE; + + mapzen_geocode_req *data = (mapzen_geocode_req *)g_malloc0(sizeof(mapzen_geocode_req)); + + if (data != NULL) { + data->req_details = req_details; + data->requestId = request_id; + data->geocode_cb = callback; + data->user_data = user_data; + + req->request = data; + + MAP_DEBUG("Added GEOCODE REQUEST to geocode List"); + + pthread_mutex_lock(&__requestLock); + if (requestList == NULL) + requestList = g_list_append(requestList, (gpointer)req); + else + requestList = g_list_insert_before(requestList, NULL, (gpointer)req); + pthread_mutex_unlock(&__requestLock); + } + } + + return MAPZEN_ERROR_NONE; +} + +int add_to_revgeocode_list(mapzen_revgeocode_req_s *req_details, mapzen_reverse_geocode_cb callback, int request_id, void *user_data) +{ + mapzen_request_s *req = (mapzen_request_s *)g_malloc0(sizeof(mapzen_request_s)); + + if (req != NULL) { + + req->type = REQ_TYPE_REVGEOCODE; + + mapzen_revgeocode_req *data = (mapzen_revgeocode_req *)g_malloc0(sizeof(mapzen_revgeocode_req)); + + if (data != NULL) { + data->req_details = req_details; + data->requestId = request_id; + data->revgeocode_cb = callback; + data->user_data = user_data; + + req->request = data; + + MAP_DEBUG("Added REVERSE GEOCODE request to geocode List"); + + pthread_mutex_lock(&__requestLock); + if (requestList == NULL) + requestList = g_list_append(requestList, (gpointer)req); + else + requestList = g_list_insert_before(requestList, NULL, (gpointer)req); + pthread_mutex_unlock(&__requestLock); + } + } + + return MAPZEN_ERROR_NONE; +} + +int add_to_places_list(mapzen_search_req_s *req_details, mapzen_place_search_cb callback, int request_id, void *user_data) +{ + mapzen_request_s *req = (mapzen_request_s *)g_malloc0(sizeof(mapzen_request_s)); + + if (req != NULL) { + + req->type = REQ_TYPE_PLACES; + + mapzen_search_place_req *data = (mapzen_search_place_req *)g_malloc0(sizeof(mapzen_search_place_req)); + + if (data != NULL) { + data->req_details = req_details; + data->requestId = request_id; + data->search_place_cb = callback; + data->user_data = user_data; + + req->request = data; + + MAP_DEBUG("Added PLACE request to places List"); + + pthread_mutex_lock(&__requestLock); + if (requestList == NULL) + requestList = g_list_append(requestList, (gpointer)req); + else + requestList = g_list_insert_before(requestList, NULL, (gpointer)req); + pthread_mutex_unlock(&__requestLock); + } + } + + return MAPZEN_ERROR_NONE; +} + +int add_to_route_list(mapzen_route_req_s *req_details, mapzen_route_cb callback, int request_id, void *user_data) +{ + mapzen_request_s *req = (mapzen_request_s *)g_malloc0(sizeof(mapzen_request_s)); + + if (req != NULL) { + + req->type = REQ_TYPE_ROUTE; + + mapzen_route_req *data = (mapzen_route_req *)g_malloc0(sizeof(mapzen_route_req)); + + if (data != NULL) { + data->req_details = req_details; + data->requestId = request_id; + data->route_cb = callback; + data->user_data = user_data; + + req->request = data; + + MAP_DEBUG("Added request to route List"); + + pthread_mutex_lock(&__requestLock); + if (requestList == NULL) + requestList = g_list_append(requestList, (gpointer)req); + else + requestList = g_list_insert_before(requestList, NULL, (gpointer)req); + pthread_mutex_unlock(&__requestLock); + } + + } + + return MAPZEN_ERROR_NONE; +} + +static int __add_to_cancel_list(int request_id) +{ + if (reqCancelList == NULL) + reqCancelList = g_list_append(reqCancelList, (gpointer) GINT_TO_POINTER(request_id)); + else + reqCancelList = g_list_insert_before(reqCancelList, NULL, (gpointer) GINT_TO_POINTER(request_id)); + + return MAPZEN_ERROR_NONE; +} + +static int __remove_from_cancel_list(int request_id) +{ + if (g_list_length(reqCancelList) != 0) + reqCancelList = g_list_remove(reqCancelList, (gpointer) GINT_TO_POINTER(request_id)); + + return MAPZEN_ERROR_NONE; +} + +int remove_from_request_list(int request_id) +{ + bool is_request_cancelled = false; + GList *list = NULL; + pthread_mutex_lock(&__requestLock); + list = g_list_first(requestList); + pthread_mutex_unlock(&__requestLock); + mapzen_request_s *req = NULL; + + while (list != NULL) { + req = (mapzen_request_s *) list->data; + + if (req != NULL) { + if (req->type == REQ_TYPE_GEOCODE) { + mapzen_geocode_req *geocode_req = (mapzen_geocode_req *) req->request; + + if (geocode_req->requestId == request_id) { + /* Means the request is pending in queue. Not started yet */ + /* Deleting the request from the request queue */ + pthread_mutex_lock(&__requestLock); + requestList = g_list_remove(requestList, (gpointer)req); + pthread_mutex_unlock(&__requestLock); + mapzen_geocode_req_s *geocode_req_details = (mapzen_geocode_req_s *)geocode_req->req_details; + + if (geocode_req_details) + g_free(geocode_req_details); + geocode_req_details = NULL; + + g_free(geocode_req); + geocode_req = NULL; + + g_free(req); + req = NULL; + + __remove_from_cancel_list(request_id); + + is_request_cancelled = true; + break; + } + } else if (req->type == REQ_TYPE_REVGEOCODE) { + mapzen_revgeocode_req *revgeocode_req = (mapzen_revgeocode_req *)req->request; + + if (revgeocode_req->requestId == request_id) { + /* Means the request is pending in queue. Not started yet */ + /* Deleting the request from the request queue */ + pthread_mutex_lock(&__requestLock); + requestList = g_list_remove(requestList, (gpointer)req); + pthread_mutex_unlock(&__requestLock); + mapzen_revgeocode_req_s *reverse_geocode_req_details = (mapzen_revgeocode_req_s *)revgeocode_req->req_details; + + if (reverse_geocode_req_details) + g_free(reverse_geocode_req_details); + reverse_geocode_req_details = NULL; + + g_free(revgeocode_req); + revgeocode_req = NULL; + + g_free(req); + req = NULL; + + __remove_from_cancel_list(request_id); + + is_request_cancelled = true; + break; + } + } else if (req->type == REQ_TYPE_ROUTE) { + mapzen_route_req *route_req = (mapzen_route_req *) req->request; + + if (route_req->requestId == request_id) { + /* Means the request is pending in queue. Not started yet */ + /* Deleting the request from the request queue */ + pthread_mutex_lock(&__requestLock); + requestList = g_list_remove(requestList, (gpointer)req); + pthread_mutex_unlock(&__requestLock); + mapzen_route_req_s *route_req_details = (mapzen_route_req_s *)route_req->req_details; + + if (route_req_details) + g_free(route_req_details); + route_req_details = NULL; + + g_free(route_req); + route_req = NULL; + + g_free(req); + req = NULL; + + __remove_from_cancel_list(request_id); + + is_request_cancelled = true; + break; + } + } else if (req->type == REQ_TYPE_PLACES) { + mapzen_search_place_req *places_req = (mapzen_search_place_req *) req->request; + + if (places_req->requestId == request_id) { + /* Means the request is pending in queue. Not started yet */ + /* Deleting the request from the request queue */ + pthread_mutex_lock(&__requestLock); + requestList = g_list_remove(requestList, (gpointer)req); + pthread_mutex_unlock(&__requestLock); + mapzen_search_req_s *place_req_details = (mapzen_search_req_s *)places_req->req_details; + + if (place_req_details) + g_free(place_req_details); + place_req_details = NULL; + + g_free(places_req); + places_req = NULL; + + g_free(req); + req = NULL; + + __remove_from_cancel_list(request_id); + + is_request_cancelled = true; + break; + } + } + } + + list = g_list_next(list); + } + + if (!is_request_cancelled) { + /* Means it is currently running. */ + /* Cancel the request */ + cancel_request(request_id); + /* add to cancel list */ + __add_to_cancel_list(request_id); + } + + return MAPZEN_ERROR_NONE; +} + +static bool __is_request_in_cancel_list(int requestId) +{ + bool match_id = false; + + GList *list = NULL; + list = g_list_first(reqCancelList); + + while (list != NULL) { + + int id = (int) GPOINTER_TO_INT(list->data); + + if (id == requestId) { + match_id = true; + break; + } + + list = g_list_next(list); + } + + return match_id; +} + +mapzen_request_s *get_next_request() +{ + if (g_list_length(requestList) > 0) { + pthread_mutex_lock(&__requestLock); + GList *list = g_list_first(requestList); + pthread_mutex_unlock(&__requestLock); + + if (list) { + mapzen_request_s *req = (mapzen_request_s *) list->data; + return req; + } else { + return NULL; + } + } + + return NULL; +} + +static gboolean __timeout_cb(gpointer data) +{ + MAP_DEBUG("timeout_cb"); + __response_timer_running = true; + g_async_queue_ref(responseQueue); + + __ResponseQueueLen = g_async_queue_length(responseQueue); + MAP_DEBUG("Queue Len :: [%d]", __ResponseQueueLen); + while (__ResponseQueueLen > 0) { + gpointer data = g_async_queue_try_pop(responseQueue); + if (!data) + continue; + + MapzenQueueData *response = (MapzenQueueData *) data; + + switch (response->type) { + case RESP_TYPE_GEOCODE: + { + MAP_DEBUG("Got geocode response.."); + MapzenGeocodeResponseData *geocodeData = (MapzenGeocodeResponseData *) (response->data); + if (geocodeData) { + if (__is_request_in_cancel_list(geocodeData->requestId) == false) { + /* Deliver results to consumer */ + geocodeData->geocode_cb(geocodeData->error, geocodeData->requestId, geocodeData->coords, geocodeData->user_data); + } else { + /* If present in cancel list, dont trigger the response. */ + /* Remove the requestId from cancel list. */ + __remove_from_cancel_list(geocodeData->requestId); + } + __free_geocode_response(geocodeData); + + g_free(geocodeData); + geocodeData = NULL; + } + + /* Start the Next valid request */ + if (get_num_running_requests() < CURL_MAX_CONNECTS) { + MAP_DEBUG("Fetching the next request from the request list...."); + mapzen_request_s *req = get_next_request(); + if (req) { + pthread_mutex_lock(&__requestLock); + requestList = g_list_remove(requestList, (gpointer)req); + pthread_mutex_unlock(&__requestLock); + + if (req->type == REQ_TYPE_GEOCODE) { + mapzen_geocode_req *geocode_req = (mapzen_geocode_req *) req->request; + if (geocode_req != NULL) { + start_geocode_service(geocode_req->req_details, geocode_req->geocode_cb, geocode_req->requestId, geocode_req->user_data); + + g_free(geocode_req); + geocode_req = NULL; + } + } else if (req->type == REQ_TYPE_REVGEOCODE) { + mapzen_revgeocode_req *revgeocode_req = (mapzen_revgeocode_req *) req->request; + if (revgeocode_req != NULL) { + start_reversegeocode_service(revgeocode_req->req_details, revgeocode_req->revgeocode_cb, revgeocode_req->requestId, revgeocode_req->user_data); + + g_free(revgeocode_req); + revgeocode_req = NULL; + } + } else if (req->type == REQ_TYPE_PLACES) { + mapzen_search_place_req *places_req = (mapzen_search_place_req *) req->request; + if (places_req) { + start_places_service(places_req->req_details, places_req->search_place_cb, places_req->requestId, places_req->user_data); + + g_free(places_req); + places_req = NULL; + } + } else if (req->type == REQ_TYPE_ROUTE) { + mapzen_route_req *route_req = (mapzen_route_req *) req->request; + if (route_req) { + start_route_service(route_req->req_details, route_req->route_cb, route_req->requestId, route_req->user_data); + + g_free(route_req); + route_req = NULL; + } + } + + g_free(req); + req = NULL; + } else { + MAP_DEBUG("No request in queue or request type is wrong"); + } + } else { + MAP_DEBUG("Libcurl request queue is FULL.."); + } + } + break; + + case RESP_TYPE_REVGEOCODE: + { + MapzenRevGeocodeResponseData *revGeocodeData = (MapzenRevGeocodeResponseData *) (response->data); + if (revGeocodeData) { + if (__is_request_in_cancel_list(revGeocodeData->requestId) == false) { + /* Deliver results to consumer */ + revGeocodeData->reverse_geocode_cb(revGeocodeData->error, revGeocodeData->requestId, revGeocodeData->addressDetails, revGeocodeData->user_data); + } else { + /* If present in cancel list, dont trigger the response. */ + /* Remove the requestId from cancel list. */ + __remove_from_cancel_list(revGeocodeData->requestId); + } + __free_revgeocode_response(revGeocodeData); + + g_free(revGeocodeData); + revGeocodeData = NULL; + } + + /* Start the Next valid request */ + MAP_DEBUG(">> Condition Check <<"); + if (get_num_running_requests() < CURL_MAX_CONNECTS) { + MAP_DEBUG("Fetching the next request from the request list...."); + mapzen_request_s *req = get_next_request(); + if (req) { + pthread_mutex_lock(&__requestLock); + requestList = g_list_remove(requestList, (gpointer)req); + pthread_mutex_unlock(&__requestLock); + + if (req->type == REQ_TYPE_GEOCODE) { + mapzen_geocode_req *geocode_req = (mapzen_geocode_req *) req->request; + if (geocode_req != NULL) { + start_geocode_service(geocode_req->req_details, geocode_req->geocode_cb, geocode_req->requestId, geocode_req->user_data); + + g_free(geocode_req); + geocode_req = NULL; + } + } else if (req->type == REQ_TYPE_REVGEOCODE) { + mapzen_revgeocode_req *revgeocode_req = (mapzen_revgeocode_req *) req->request; + if (revgeocode_req != NULL) { + start_reversegeocode_service(revgeocode_req->req_details, revgeocode_req->revgeocode_cb, revgeocode_req->requestId, revgeocode_req->user_data); + + g_free(revgeocode_req); + revgeocode_req = NULL; + } + } else if (req->type == REQ_TYPE_PLACES) { + mapzen_search_place_req *places_req = (mapzen_search_place_req *) req->request; + if (places_req) { + start_places_service(places_req->req_details, places_req->search_place_cb, places_req->requestId, places_req->user_data); + + g_free(places_req); + places_req = NULL; + } + } else if (req->type == REQ_TYPE_ROUTE) { + mapzen_route_req *route_req = (mapzen_route_req *) req->request; + if (route_req) { + start_route_service(route_req->req_details, route_req->route_cb, route_req->requestId, route_req->user_data); + + g_free(route_req); + route_req = NULL; + } + } + + g_free(req); + req = NULL; + } else { + MAP_DEBUG("No request in queue or request type is wrong"); + } + } else { + MAP_DEBUG("Libcurl request queue is FULL.."); + } + } + break; + + case RESP_TYPE_ROUTE: + { + MapzenRouteResponseData *routeData = (MapzenRouteResponseData *) (response->data); + if (routeData != NULL) { + if (__is_request_in_cancel_list(routeData->requestId) == false) { + /* Deliver results to consumer */ + routeData->route_cb(routeData->error, routeData->requestId, routeData->routeResponse, routeData->user_data); + } else { + /* If present in cancel list, dont trigger the response. */ + /* Remove the requestId from cancel list. */ + __remove_from_cancel_list(routeData->requestId); + } + __free_route_response(routeData); + + g_free(routeData); + routeData = NULL; + } + + /* Start the Next valid request */ + if (get_num_running_requests() < CURL_MAX_CONNECTS) { + MAP_DEBUG("Fetching the next request from the request list...."); + mapzen_request_s *req = get_next_request(); + if (req) { + pthread_mutex_lock(&__requestLock); + requestList = g_list_remove(requestList, (gpointer)req); + pthread_mutex_unlock(&__requestLock); + + if (req->type == REQ_TYPE_GEOCODE) { + mapzen_geocode_req *geocode_req = (mapzen_geocode_req *) req->request; + if (geocode_req != NULL) { + start_geocode_service(geocode_req->req_details, geocode_req->geocode_cb, geocode_req->requestId, geocode_req->user_data); + + g_free(geocode_req); + geocode_req = NULL; + } + } else if (req->type == REQ_TYPE_REVGEOCODE) { + mapzen_revgeocode_req *revgeocode_req = (mapzen_revgeocode_req *) req->request; + if (revgeocode_req != NULL) { + start_reversegeocode_service(revgeocode_req->req_details, revgeocode_req->revgeocode_cb, revgeocode_req->requestId, revgeocode_req->user_data); + + g_free(revgeocode_req); + revgeocode_req = NULL; + } + } else if (req->type == REQ_TYPE_PLACES) { + mapzen_search_place_req *places_req = (mapzen_search_place_req *) req->request; + if (places_req) { + start_places_service(places_req->req_details, places_req->search_place_cb, places_req->requestId, places_req->user_data); + + g_free(places_req); + places_req = NULL; + } + } else if (req->type == REQ_TYPE_ROUTE) { + mapzen_route_req *route_req = (mapzen_route_req *) req->request; + if (route_req) { + start_route_service(route_req->req_details, route_req->route_cb, route_req->requestId, route_req->user_data); + + g_free(route_req); + route_req = NULL; + } + } + + g_free(req); + req = NULL; + } else { + MAP_DEBUG("No request in queue or request type is wrong"); + } + } else { + MAP_DEBUG("Libcurl request queue is FULL.."); + } + } + break; + + case RESP_TYPE_PLACES: + { + MapzenPlaceResponseData *placesData = (MapzenPlaceResponseData *) (response->data); + if (placesData != NULL) { + MAP_DEBUG("Sending places result.."); + if (__is_request_in_cancel_list(placesData->requestId) == false) { + /* Deliver results to consumer */ + placesData->place_search_cb(placesData->error, placesData->requestId, placesData->places, placesData->user_data); + } else { + /* If present in cancel list, dont trigger the response. */ + /* Remove the requestId from cancel list. */ + __remove_from_cancel_list(placesData->requestId); + } + __free_place_response(placesData); + + g_free(placesData); + placesData = NULL; + } + + /* Start the Next valid request */ + if (get_num_running_requests() < CURL_MAX_CONNECTS) { + MAP_DEBUG("Fetching the next request from the request list...."); + mapzen_request_s *req = get_next_request(); + if (req) { + pthread_mutex_lock(&__requestLock); + requestList = g_list_remove(requestList, (gpointer)req); + pthread_mutex_unlock(&__requestLock); + + if (req->type == REQ_TYPE_GEOCODE) { + mapzen_geocode_req *geocode_req = (mapzen_geocode_req *) req->request; + if (geocode_req != NULL) { + start_geocode_service(geocode_req->req_details, geocode_req->geocode_cb, geocode_req->requestId, geocode_req->user_data); + + g_free(geocode_req); + geocode_req = NULL; + } + } else if (req->type == REQ_TYPE_REVGEOCODE) { + mapzen_revgeocode_req *revgeocode_req = (mapzen_revgeocode_req *) req->request; + if (revgeocode_req != NULL) { + start_reversegeocode_service(revgeocode_req->req_details, revgeocode_req->revgeocode_cb, revgeocode_req->requestId, revgeocode_req->user_data); + + g_free(revgeocode_req); + revgeocode_req = NULL; + } + } else if (req->type == REQ_TYPE_PLACES) { + mapzen_search_place_req *places_req = (mapzen_search_place_req *) req->request; + if (places_req) { + start_places_service(places_req->req_details, places_req->search_place_cb, places_req->requestId, places_req->user_data); + + g_free(places_req); + places_req = NULL; + } + } else if (req->type == REQ_TYPE_ROUTE) { + mapzen_route_req *route_req = (mapzen_route_req *) req->request; + if (route_req) { + start_route_service(route_req->req_details, route_req->route_cb, route_req->requestId, route_req->user_data); + + g_free(route_req); + route_req = NULL; + } + } + + g_free(req); + req = NULL; + } else { + MAP_DEBUG("No request in queue or request type is wrong"); + } + } else { + MAP_DEBUG("Libcurl request queue is FULL.."); + } + } + break; + + default: + MAP_DEBUG("UNKNOWN RESPONSE TYPE"); + break; + } + + __ResponseQueueLen = g_async_queue_length(responseQueue); + + if (response) { + g_free(response); + response = NULL; + } + }; + + g_async_queue_unref(responseQueue); + + __response_timer_running = false; + + return false; +} + +static void __free_geocode_response(void *ptr) +{ + MapzenGeocodeResponseData *geocodeData = (MapzenGeocodeResponseData *) (ptr); + + if (geocodeData) { + GList *coords = NULL; + coords = g_list_first(geocodeData->coords); + + while (coords) { + coords_s *data = (coords_s *) coords->data; + + if (data) { + geocodeData->coords = g_list_remove(geocodeData->coords, (gpointer)data); + + g_free(data); + data = NULL; + } + coords = g_list_first(geocodeData->coords); + } + + g_list_free(geocodeData->coords); + geocodeData->coords = NULL; + + if (geocodeData->user_data) { + g_free(geocodeData->user_data); + geocodeData->user_data = NULL; + } + } +} + +static void __free_revgeocode_response(void *ptr) +{ + MapzenRevGeocodeResponseData *revGeocodeData = (MapzenRevGeocodeResponseData *) (ptr); + if (revGeocodeData) { + if (revGeocodeData->addressDetails) { + if (revGeocodeData->addressDetails->street_add) { + g_free(revGeocodeData->addressDetails->street_add); + revGeocodeData->addressDetails->street_add = NULL; + } + if (revGeocodeData->addressDetails->neighbourhood) { + g_free(revGeocodeData->addressDetails->neighbourhood); + revGeocodeData->addressDetails->neighbourhood = NULL; + } + if (revGeocodeData->addressDetails->city) { + g_free(revGeocodeData->addressDetails->city); + revGeocodeData->addressDetails->city = NULL; + } + if (revGeocodeData->addressDetails->county) { + g_free(revGeocodeData->addressDetails->county); + revGeocodeData->addressDetails->county = NULL; + } + if (revGeocodeData->addressDetails->state) { + g_free(revGeocodeData->addressDetails->state); + revGeocodeData->addressDetails->state = NULL; + } + if (revGeocodeData->addressDetails->country) { + g_free(revGeocodeData->addressDetails->country); + revGeocodeData->addressDetails->country = NULL; + } + if (revGeocodeData->addressDetails->country_code) { + g_free(revGeocodeData->addressDetails->country_code); + revGeocodeData->addressDetails->country_code = NULL; + } + if (revGeocodeData->addressDetails->postal_code) { + g_free(revGeocodeData->addressDetails->postal_code); + revGeocodeData->addressDetails->postal_code = NULL; + } + + g_free(revGeocodeData->addressDetails); + revGeocodeData->addressDetails = NULL; + } + + if (revGeocodeData->user_data) { + g_free(revGeocodeData->user_data); + revGeocodeData->user_data = NULL; + } + } +} + +static void __free_place_response(void *ptr) +{ + MapzenPlaceResponseData *placeData = (MapzenPlaceResponseData *) (ptr); + if (placeData) { + GList *place = NULL; + place = g_list_first(placeData->places); + + while (place) { + mapzen_place_resp_s *mapzen_place = (mapzen_place_resp_s *) place->data; + + if (mapzen_place->address) { + if (mapzen_place->address->street_add) { + g_free(mapzen_place->address->street_add); + mapzen_place->address->street_add = NULL; + } + if (mapzen_place->address->neighbourhood) { + g_free(mapzen_place->address->neighbourhood); + mapzen_place->address->neighbourhood = NULL; + } + if (mapzen_place->address->building_number) { + g_free(mapzen_place->address->building_number); + mapzen_place->address->building_number = NULL; + } + if (mapzen_place->address->city) { + g_free(mapzen_place->address->city); + mapzen_place->address->city = NULL; + } + if (mapzen_place->address->county) { + g_free(mapzen_place->address->county); + mapzen_place->address->county = NULL; + } + if (mapzen_place->address->state) { + g_free(mapzen_place->address->state); + mapzen_place->address->state = NULL; + } + if (mapzen_place->address->country) { + g_free(mapzen_place->address->country); + mapzen_place->address->country = NULL; + } + if (mapzen_place->address->country_code) { + g_free(mapzen_place->address->country_code); + mapzen_place->address->country_code = NULL; + } + if (mapzen_place->address->postal_code) { + g_free(mapzen_place->address->postal_code); + mapzen_place->address->postal_code = NULL; + } + g_free(mapzen_place->address); + mapzen_place->address = NULL; + } + + if (mapzen_place->category) { + g_free(mapzen_place->category); + mapzen_place->category = NULL; + } + if (mapzen_place->subcategory) { + g_free(mapzen_place->subcategory); + mapzen_place->subcategory = NULL; + } + if (mapzen_place->display_name) { + g_free(mapzen_place->display_name); + mapzen_place->display_name = NULL; + } + + placeData->places = g_list_remove(placeData->places, (gpointer)mapzen_place); + + g_free(mapzen_place); + mapzen_place = NULL; + + place = g_list_first(placeData->places); + } + g_list_free(placeData->places); + placeData->places = NULL; + + if (placeData->user_data) { + g_free(placeData->user_data); + placeData->user_data = NULL; + } + } +} + +static void __free_route_response(void *ptr) +{ + MapzenRouteResponseData *routeData = (MapzenRouteResponseData *) (ptr); + if (routeData) { + mapzen_route_resp_s *route_info = routeData->routeResponse; + if (route_info) { + GList *maneuver_data = NULL; + maneuver_data = g_list_first(route_info->maneuvers); + while (maneuver_data) { + mapzen_route_maneuver *maneuver = (mapzen_route_maneuver *) maneuver_data->data; + + if (maneuver->instruction) { + g_free(maneuver->instruction); + maneuver->instruction = NULL; + } + if (maneuver->formatted_time) { + g_free(maneuver->formatted_time); + maneuver->formatted_time = NULL; + } + if (maneuver->direction_name) { + g_free(maneuver->direction_name); + maneuver->direction_name = NULL; + } + if (maneuver->street_name) { + g_free(maneuver->street_name); + maneuver->street_name = NULL; + } + + route_info->maneuvers = g_list_remove(route_info->maneuvers, (gpointer)maneuver); + + g_free(maneuver); + maneuver = NULL; + + /* Fetching the next item from Maneuver/Segment list */ + maneuver_data = g_list_first(route_info->maneuvers); + } + g_list_free(route_info->maneuvers); + route_info->maneuvers = NULL; + + GList *shapePoints = NULL; + shapePoints = g_list_first(route_info->shapePoints); + while (shapePoints) { + coords_s *data = (coords_s *) shapePoints->data; + + route_info->shapePoints = g_list_remove(route_info->shapePoints, (gpointer)data); + + g_free(data); + data = NULL; + + shapePoints = g_list_first(route_info->shapePoints); + } + g_list_free(route_info->shapePoints); + route_info->shapePoints = NULL; + + if (route_info->formatted_time) { + g_free(route_info->formatted_time); + route_info->formatted_time = NULL; + } + g_free(route_info); + route_info = NULL; + } + if (routeData->user_data) { + g_free(routeData->user_data); + routeData->user_data = NULL; + } + } +} + +int mapzen_init_queue() +{ +#if !GLIB_CHECK_VERSION(2, 35, 0) + g_type_init(); /* Needed for using json in Emulator */ +#endif + + pthread_mutex_init(&__requestLock, NULL); + + /* Queue initialize */ + responseQueue = g_async_queue_new(); + + /* Initialise Curl Service */ + int ret = init_curl(); + + if (ret != MAPZEN_ERROR_NONE) + return MAPZEN_ERROR_UNKNOWN; + + pthread_mutex_lock(&__requestLock); + requestList = NULL; + pthread_mutex_unlock(&__requestLock); + reqCancelList = NULL; + __ResponseQueueLen = 0; + __response_timer_running = false; + + return MAPZEN_ERROR_NONE; +} + +int mapzen_deinit_queue() +{ + deinit_curl(); + + g_list_free(reqCancelList); + reqCancelList = NULL; + + pthread_mutex_destroy(&__requestLock); + + /* Free the queue */ + if (responseQueue) { + g_async_queue_ref(responseQueue); + __ResponseQueueLen = g_async_queue_length(responseQueue); + MAP_DEBUG("Queue len : %d", __ResponseQueueLen); + + while (__ResponseQueueLen > 0) { + gpointer data = g_async_queue_try_pop(responseQueue); + if (!data) { + __ResponseQueueLen = g_async_queue_length(responseQueue); + continue; + } + + MapzenQueueData *response = (MapzenQueueData *) data; + + switch (response->type) { + case RESP_TYPE_GEOCODE: + { + MapzenGeocodeResponseData *geocodeData = (MapzenGeocodeResponseData *) (response->data); + if (geocodeData) { + __free_geocode_response(geocodeData); + + g_free(geocodeData); + geocodeData = NULL; + } + } + break; + case RESP_TYPE_REVGEOCODE: + { + MapzenRevGeocodeResponseData *revGeocodeData = (MapzenRevGeocodeResponseData *) (response->data); + if (revGeocodeData) { + __free_revgeocode_response(revGeocodeData); + + g_free(revGeocodeData); + revGeocodeData = NULL; + } + } + break; + case RESP_TYPE_PLACES: + { + MapzenPlaceResponseData *placeData = (MapzenPlaceResponseData *) (response->data); + if (placeData != NULL) { + __free_place_response(placeData); + + g_free(placeData); + placeData = NULL; + } + } + break; + case RESP_TYPE_ROUTE: + { + MapzenRouteResponseData *routeData = (MapzenRouteResponseData *) (response->data); + if (routeData != NULL) { + __free_route_response(routeData); + + g_free(routeData); + routeData = NULL; + } + } + break; + default: + break; + } + + __ResponseQueueLen = g_async_queue_length(responseQueue); + + if (response) { + g_free(response); + response = NULL; + } + } + g_async_queue_unref(responseQueue); + responseQueue = NULL; + } + + return MAPZEN_ERROR_NONE; +} + +int mapzen_push_to_queue(mapzen_resp_type type, gpointer data) +{ + MAP_DEBUG("Pushing to Queue...."); + + MapzenQueueData *queueData = (MapzenQueueData *)g_malloc0(sizeof(MapzenQueueData)); + if (!queueData) return MAPZEN_ERROR_OUT_OF_MEMORY; + + queueData->type = type; + queueData->data = data; + + g_async_queue_ref(responseQueue); + g_async_queue_push(responseQueue, (gpointer)queueData); + g_async_queue_unref(responseQueue); + + if (!__response_timer_running) { + MAP_DEBUG(">>>>>>>>>>>>>>>>>>>>>>> TRIGGER RESPONSE TIMER <<<<<<<<<<<<<<<<<<<<<<<<<"); + g_timeout_add_seconds(1, __timeout_cb, NULL); /* timeout : 1 sec */ + } else { + __ResponseQueueLen = g_async_queue_length(responseQueue); + MAP_DEBUG(">>>>>>>>>>>>>>>>>> Timer already running. Response Queue Len [%d] <<<<<<<<<<<<<<<<<", __ResponseQueueLen); + } + + return MAPZEN_ERROR_NONE; +} + +int start_geocode_service(mapzen_geocode_req_s *req_details, mapzen_geocode_cb callback, int request_id, void *user_data) +{ + int num_running_req = get_num_running_requests(); + + if (num_running_req >= CURL_MAX_CONNECTS) { + /* Add the request to queue */ + add_to_geocode_list(req_details, callback, request_id, user_data); + } else { + MapzenGeocodeQueryData *queryData = (MapzenGeocodeQueryData *)g_malloc0(sizeof(MapzenGeocodeQueryData)); + + if (queryData != NULL) { + queryData->requestId = request_id; + queryData->geocode_cb = callback; + queryData->user_data = user_data; + + if (req_details->boundary != NULL) { + if (req_details->boundary->type == MAPZEN_BOUNDARY_RECT) { + MAP_DEBUG("TOP LEFT >>><<< LATITUDE : %f, LONGITUDE : %f", req_details->boundary->rect.top_left.latitude, req_details->boundary->rect.top_left.longitude); + MAP_DEBUG("BOTTOM RIGHT >>><<< LATITUDE : %f, LONGITUDE : %f", req_details->boundary->rect.bottom_right.latitude, req_details->boundary->rect.bottom_right.longitude); + + query_geocode_within_bounds(req_details->maps_key, req_details->address, req_details->boundary->rect.top_left, req_details->boundary->rect.bottom_right, req_details->num_res, queryData); + + } else if (req_details->boundary->type == MAPZEN_BOUNDARY_CIRCLE) { + + coords_s *top_left = NULL, *bottom_right = NULL; + coords_s circle = req_details->boundary->circle.center; + gdouble radius = (req_details->boundary->circle.radius) * 0.001; + + MAP_DEBUG("User input LATITUDE : %f, LONGITUDE : %f", circle.latitude, circle.longitude); + + /* Calculate the top left coordinate of bounding box. */ + calculate_point(circle.latitude, circle.longitude, 315, radius, &top_left); + + /* Calculate the bottom right coordinate of bounding box. */ + calculate_point(circle.latitude, circle.longitude, 135, radius, &bottom_right); + + if ((top_left != NULL) && (bottom_right != NULL)) { + MAP_DEBUG("Top Left LATITUDE : %f, LONGITUDE : %f", top_left->latitude, top_left->longitude); + MAP_DEBUG("Bottom Right LATITUDE : %f, LONGITUDE : %f", bottom_right->latitude, bottom_right->longitude); + + query_geocode_within_bounds(req_details->maps_key, req_details->address, *top_left, *bottom_right, req_details->num_res, queryData); + + g_free(top_left); + top_left = NULL; + + g_free(bottom_right); + bottom_right = NULL; + } + + } else { + query_geocode(req_details->maps_key, req_details->address, req_details->num_res, queryData); + } + + } else { + MAP_DEBUG("BOUNDARY is NULL.. NORMAL GEOCODE QUERY WITHOUT BOUNDS"); + + query_geocode(req_details->maps_key, req_details->address, req_details->num_res, queryData); + } + } + + if (req_details) { + if (req_details->address) { + g_free(req_details->address); + req_details->address = NULL; + } + if (req_details->maps_key) { + g_free(req_details->maps_key); + req_details->maps_key = NULL; + } + if (req_details->boundary) { + g_free(req_details->boundary); + req_details->boundary = NULL; + } + g_free(req_details); + req_details = NULL; + } + } + + return MAPZEN_ERROR_NONE; +} + +int start_reversegeocode_service(mapzen_revgeocode_req_s *req_details, mapzen_reverse_geocode_cb callback, int request_id, void *user_data) +{ + int num_running_req = get_num_running_requests(); + + if (num_running_req >= CURL_MAX_CONNECTS) { + /* Add the request to queue */ + add_to_revgeocode_list(req_details, callback, request_id, user_data); + } else { + MapzenRevGeocodeQueryData *queryData = (MapzenRevGeocodeQueryData *)g_malloc0(sizeof(MapzenRevGeocodeQueryData)); + + if (queryData != NULL) { + queryData->requestId = request_id; + queryData->reverse_geocode_cb = callback; + queryData->user_data = user_data; + + coords_s coords = req_details->coordinates; + + query_revgeocode(req_details->maps_key, coords.latitude, coords.longitude, queryData); + } + + if (req_details) { + if (req_details->maps_key) { + g_free(req_details->maps_key); + req_details->maps_key = NULL; + } + g_free(req_details); + req_details = NULL; + } + } + + return MAPZEN_ERROR_NONE; +} + +int start_route_service(mapzen_route_req_s *req_details, mapzen_route_cb callback, int request_id, void *user_data) +{ + int num_running_req = get_num_running_requests(); + + if (num_running_req >= CURL_MAX_CONNECTS) { + /* Add the request to queue */ + add_to_route_list(req_details, callback, request_id, user_data); + } else { + MapzenRouteQueryData *queryData = (MapzenRouteQueryData *)g_malloc0(sizeof(MapzenRouteQueryData)); + + if (queryData != NULL) { + queryData->requestId = request_id; + queryData->route_cb = callback; + queryData->origin = req_details->from; + queryData->destination = req_details->to; + queryData->unit = req_details->unit; + queryData->user_data = user_data; + + query_route(req_details->maps_key, req_details->from, req_details->to, req_details->type, req_details->avoids, req_details->driving_style, req_details->way_points, queryData); + } + + if (req_details) { + if (req_details->maps_key) { + g_free(req_details->maps_key); + req_details->maps_key = NULL; + } + if (req_details->way_points) { + if (g_list_length(req_details->way_points) > 0) { + GList *list = NULL; + list = g_list_first(req_details->way_points); + while (list) { + coords_s *data = (coords_s *)list->data; + if (data) { + req_details->way_points = g_list_remove(req_details->way_points, (gpointer)data); + + g_free(data); + data = NULL; + } + list = g_list_first(req_details->way_points); + } + } + g_list_free(req_details->way_points); + req_details->way_points = NULL; + } + g_free(req_details); + req_details = NULL; + } + } + + return MAPZEN_ERROR_NONE; +} + +int start_places_service(mapzen_search_req_s *req_details, mapzen_place_search_cb callback, int request_id, void *user_data) +{ + int num_running_req = get_num_running_requests(); + + if (num_running_req >= CURL_MAX_CONNECTS) { + /* Add the request to queue */ + add_to_places_list(req_details, callback, request_id, user_data); + } else { + MapzenPlaceQueryData *queryData = (MapzenPlaceQueryData *)g_malloc0(sizeof(MapzenPlaceQueryData)); + + if (queryData != NULL) { + queryData->requestId = request_id; + queryData->place_search_cb = callback; + queryData->user_data = user_data; + + query_places(req_details->maps_key, req_details->search_string, req_details->boundary, req_details->num_res, queryData); + } + + if (req_details) { + if (req_details->maps_key) { + g_free(req_details->maps_key); + req_details->maps_key = NULL; + } + if (req_details->boundary) { + g_free(req_details->boundary); + req_details->boundary = NULL; + } + if (req_details->search_string) { + g_free(req_details->search_string); + req_details->search_string = NULL; + } + g_free(req_details); + req_details = NULL; + } + } + + return MAPZEN_ERROR_NONE; +} diff --git a/src/mapzen/mapzen_queue.h b/src/mapzen/mapzen_queue.h new file mode 100644 index 0000000..3d0d73c --- /dev/null +++ b/src/mapzen/mapzen_queue.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MAPZEN_QUEUE_H_ +#define _MAPZEN_QUEUE_H_ + +#include +#include "mapzen_server_private.h" + +typedef struct { + mapzen_req_type type; + void *request; +} mapzen_request_s; + +typedef struct { + mapzen_geocode_req_s *req_details; + int requestId; + mapzen_geocode_cb geocode_cb; + void *user_data; +} mapzen_geocode_req; + +typedef struct { + mapzen_revgeocode_req_s *req_details; + int requestId; + mapzen_reverse_geocode_cb revgeocode_cb; + void *user_data; +} mapzen_revgeocode_req; + +typedef struct { + mapzen_route_req_s *req_details; + mapzen_route_cb route_cb; + int requestId; + void *user_data; +} mapzen_route_req; + +typedef struct { + mapzen_search_req_s *req_details; + mapzen_place_search_cb search_place_cb; + int requestId; + void *user_data; +} mapzen_search_place_req; + +int add_to_geocode_list(mapzen_geocode_req_s *req_details, mapzen_geocode_cb callback, int request_id, void *user_data); +int add_to_revgeocode_list(mapzen_revgeocode_req_s *req_details, mapzen_reverse_geocode_cb callback, int request_id, void *user_data); +int add_to_route_list(mapzen_route_req_s *req_details, mapzen_route_cb callback, int request_id, void *user_data); +int add_to_places_list(mapzen_search_req_s *req_details, mapzen_place_search_cb callback, int request_id, void *user_data); + +int remove_from_request_list(int request_id); + +int start_geocode_service(mapzen_geocode_req_s *req_details, mapzen_geocode_cb callback, int request_id, void *user_data); +int start_reversegeocode_service(mapzen_revgeocode_req_s *req_details, mapzen_reverse_geocode_cb callback, int request_id, void *user_data); +int start_route_service(mapzen_route_req_s *req_details, mapzen_route_cb callback, int request_id, void *user_data); +int start_places_service(mapzen_search_req_s *req_details, mapzen_place_search_cb callback, int request_id, void *user_data); + +int mapzen_init_queue(); +int mapzen_deinit_queue(); +int mapzen_push_to_queue(mapzen_resp_type type, gpointer data); + +#endif /* _MAPZEN_QUEUE_H_ */ diff --git a/src/mapzen/mapzen_restcurl.c b/src/mapzen/mapzen_restcurl.c new file mode 100644 index 0000000..8d41417 --- /dev/null +++ b/src/mapzen/mapzen_restcurl.c @@ -0,0 +1,671 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include "mapzen_restcurl.h" +#include "mapzen_types.h" +#include "mapzen_jsonparser.h" +#include "mapzen_debug.h" + +#define RESTCURL_USE_MULTI_CURL + +CURLM *__cm_handle; +pthread_t __CurlThread; +pthread_mutex_t __MultiCurlArgsLock; +pthread_mutex_t __CmHandleLock; +static bool __thread_running_for_curlmulti = false; +static int __MultiCurlArgsRemain = 0; +pthread_cond_t __curl_delivered_cond; +pthread_mutex_t __curl_deliver_mutex; +static char *__proxy_address = NULL; +GList *__cancel_req_list = NULL; + +typedef struct { + char *memory; + size_t size; +} MemoryStruct_s; + +struct MultiCurlArg { + MemoryStruct_s m_chunk; + CURL *curl_handle; + mapzen_req_type req_type; + int request_id; + void *user_data; + char url[1024]; +}; + +/****************** LIST for maintaining easy curl related data *******************/ + +struct MultiCurlArg_List { + struct MultiCurlArg *mcArg; + struct MultiCurlArg_List *next; +}; + +struct MultiCurlArg_List *head = NULL; +struct MultiCurlArg_List *curr = NULL; + +static struct MultiCurlArg_List *__create_list(struct MultiCurlArg *mcArg) +{ + MAP_DEBUG("\n creating list with headnode as [%p]\n", mcArg); + struct MultiCurlArg_List *ptr = (struct MultiCurlArg_List *)g_malloc0(sizeof(struct MultiCurlArg_List)); + if (NULL == ptr) { + MAP_DEBUG("\n Node creation failed \n"); + return NULL; + } + ptr->mcArg = mcArg; + ptr->next = NULL; + + head = curr = ptr; + return ptr; +} + +static struct MultiCurlArg_List *__add_to_list(struct MultiCurlArg *mcArg, bool add_to_end) +{ + if (NULL == head) + return (__create_list(mcArg)); + + struct MultiCurlArg_List *ptr = (struct MultiCurlArg_List *)g_malloc0(sizeof(struct MultiCurlArg_List)); + if (NULL == ptr) { + MAP_DEBUG("\n Node creation failed \n"); + return NULL; + } + ptr->mcArg = mcArg; + ptr->next = NULL; + + if (add_to_end) { + curr->next = ptr; + curr = ptr; + } else { + ptr->next = head; + head = ptr; + } + return ptr; +} + +static struct MultiCurlArg_List *__search_in_list(CURL * handle, struct MultiCurlArg_List **prev) +{ + struct MultiCurlArg_List *ptr = head; + struct MultiCurlArg_List *tmp = NULL; + bool found = false; + + MAP_DEBUG("\n Searching the list for value\n"); + + while (ptr != NULL) { + if (ptr->mcArg->curl_handle == handle) { + found = true; + break; + } else { + tmp = ptr; + ptr = ptr->next; + } + } + + if (true == found) { + if (prev) + *prev = tmp; + return ptr; + } else { + return NULL; + } +} + +static struct MultiCurlArg_List *__delete_from_list(CURL *handle) +{ + struct MultiCurlArg_List *prev = NULL; + struct MultiCurlArg_List *del = NULL; + + MAP_DEBUG("\n Deleting value handle from list\n"); + + del = __search_in_list(handle, &prev); + if (del == NULL) { + return NULL; + } else { + if (prev != NULL) + prev->next = del->next; + + if (del == curr) { + curr = prev; + if (prev == NULL) + head = NULL; + } else if (del == head) { + head = del->next; + } + } + + del->next = NULL; + + return del; +} + +/*****************************************/ + +mapzen_error_e __get_proxy_address() +{ + mapzen_error_e err = MAPZEN_ERROR_NONE; + + connection_h con = NULL; + int errorCode = CONNECTION_ERROR_NOT_SUPPORTED; + char *address = NULL; + + errorCode = connection_create(&con); + + if (errorCode == CONNECTION_ERROR_NONE) + errorCode = connection_get_proxy(con, CONNECTION_ADDRESS_FAMILY_IPV4, &address); + + if (errorCode != CONNECTION_ERROR_NONE) { + err = MAPZEN_ERROR_UNKNOWN; + switch (errorCode) { + case CONNECTION_ERROR_INVALID_PARAMETER: + MAP_DEBUG("Invalid parameter"); + err = MAPZEN_ERROR_INVALID_PARAMETER; + break; + case CONNECTION_ERROR_OUT_OF_MEMORY: + MAP_DEBUG("Out of memory error"); + err = MAPZEN_ERROR_OUT_OF_MEMORY; + break; + case CONNECTION_ERROR_INVALID_OPERATION: + MAP_DEBUG("Invalid Operation"); + err = MAPZEN_ERROR_INVALID_OPERATION; + break; + case CONNECTION_ERROR_ADDRESS_FAMILY_NOT_SUPPORTED: + MAP_DEBUG("Address family not supported"); + err = MAPZEN_ERROR_NOT_SUPPORTED; + break; + /* + case CONNECTION_ERROR_PERMISSION_DENIED: + MAP_DEBUG("Permission denied"); + err = MAPZEN_ERROR_PERMISSION_DENIED; + break; + */ + case CONNECTION_ERROR_OPERATION_FAILED: + MAP_DEBUG("Operation failed"); + err = MAPZEN_ERROR_INVALID_OPERATION; + break; + case CONNECTION_ERROR_ITERATOR_END: + MAP_DEBUG("End of iteration"); + break; + case CONNECTION_ERROR_NO_CONNECTION: + MAP_DEBUG("There is no connection"); + err = MAPZEN_ERROR_NETWORK_UNREACHABLE; + break; + case CONNECTION_ERROR_NOW_IN_PROGRESS: + MAP_DEBUG("Now in progress"); + err = MAPZEN_ERROR_RESOURCE_BUSY; + break; + case CONNECTION_ERROR_ALREADY_EXISTS: + MAP_DEBUG("Already exists"); + break; + case CONNECTION_ERROR_OPERATION_ABORTED: + MAP_DEBUG("Operation is aborted"); + err = MAPZEN_ERROR_CANCELED; + break; + case CONNECTION_ERROR_DHCP_FAILED: + MAP_DEBUG("DHCP failed"); + break; + case CONNECTION_ERROR_INVALID_KEY: + MAP_DEBUG("Invalid key"); + err = MAPZEN_ERROR_KEY_NOT_AVAILABLE; + break; + case CONNECTION_ERROR_NO_REPLY: + MAP_DEBUG("No reply"); + err = MAPZEN_ERROR_RESOURCE_BUSY; + break; + case CONNECTION_ERROR_NOT_SUPPORTED: + MAP_DEBUG("Not Supported"); + err = MAPZEN_ERROR_NOT_SUPPORTED; + break; + default: + MAP_DEBUG("Unknown"); + break; + } + MAP_DEBUG("errorCode = %ld", (long)errorCode); + } + + if (con) + connection_destroy(con); + + if (err != MAPZEN_ERROR_NONE) + return err; + + if (address) { + int len = strlen(address); + if (len > 0) { + __proxy_address = (char *)g_malloc0(len+1); + strncpy(__proxy_address, address, len); + __proxy_address[len] = '\0'; + } + g_free(address); + address = NULL; + } + + MAP_DEBUG("Proxy = %s", (__proxy_address ? __proxy_address : "(null)")); + + return MAPZEN_ERROR_NONE; +} + +static size_t __write_memory_callback(void *contents, size_t size, size_t nmemb, void *userp) +{ + size_t realsize = size * nmemb; +#ifdef RESTCURL_USE_MULTI_CURL + MemoryStruct_s *mem = &(((struct MultiCurlArg *) userp)->m_chunk); +#else + MemoryStruct_s *mem = (MemoryStruct_s *) userp; +#endif + + if (mem->memory == NULL) + mem->memory = g_malloc(realsize); + else + mem->memory = g_realloc(mem->memory, mem->size + realsize); + + if (mem->memory == NULL) + return 0; + + memcpy(mem->memory + mem->size, contents, realsize); + + mem->size += realsize; + + MAP_DEBUG("REal size : %d", realsize); + MAP_DEBUG("response size :: %d", strlen(mem->memory)); + + return realsize; +} + +static int __xferinfo(void *p, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) +{ + struct MultiCurlArg *pMultiCurlArg = (struct MultiCurlArg *) p; + + GList *list = NULL; + list = g_list_first(__cancel_req_list); + int req_id_to_be_cancelled = -1; + bool cancel_request = false; + + while (list) { + req_id_to_be_cancelled = (int) GPOINTER_TO_INT(list->data); + MAP_DEBUG("Req id in the list waiting to get cancelled [%d]", req_id_to_be_cancelled); + if (pMultiCurlArg->request_id == req_id_to_be_cancelled) { + MAP_DEBUG(">>>>>>>>>>>> Req id matched :: To be cancelled [%d]", req_id_to_be_cancelled); + cancel_request = true; + break; + } + list = list->next; + } + + if (cancel_request) { + MAP_DEBUG(">>>>>>>> Req Id to be aborted :: [%d] <<<<<<<<<<<<<", req_id_to_be_cancelled); + /* Remove the request id from cancel list */ + __cancel_req_list = g_list_remove(__cancel_req_list, (gpointer) GINT_TO_POINTER(req_id_to_be_cancelled)); + MAP_DEBUG(">>>>>>>>>> Request removed from cancel list <<<<<<<<"); + return 1; /* Returning Non-Zero value will abort the transfer */ + } + + return 0; +} + +static int __progress_info(void *p, double dltotal, double dlnow, double ultotal, double ulnow) +{ + return __xferinfo(p, (curl_off_t)dltotal, (curl_off_t)dlnow, (curl_off_t)ultotal, (curl_off_t)ulnow); +} + +int add_handle(char *url, mapzen_req_type type, void *user_data) +{ + if (!url || !user_data) return -1; + + int req_id = -1; + + switch (type) { + case REQ_TYPE_GEOCODE: + req_id = ((MapzenGeocodeQueryData *) user_data)->requestId; + break; + case REQ_TYPE_REVGEOCODE: + req_id = ((MapzenRevGeocodeQueryData *) user_data)->requestId; + break; + case REQ_TYPE_PLACES: + req_id = ((MapzenPlaceQueryData *) user_data)->requestId; + break; + case REQ_TYPE_ROUTE: + req_id = ((MapzenRouteQueryData *) user_data)->requestId; + break; + default: + break; + } + +#ifdef RESTCURL_USE_MULTI_CURL + MAP_DEBUG("HTTP Req URL [%s]", url); + CURL *curl_handle; + + struct MultiCurlArg *pMultiCurlArg = (struct MultiCurlArg *)g_malloc0(sizeof(struct MultiCurlArg)); + + if (!pMultiCurlArg) return -1; + + (pMultiCurlArg->m_chunk).memory = (char *) g_malloc0(1); /* will be grown as needed by the realloc above */ + (pMultiCurlArg->m_chunk).size = 0; /* no data at this point */ + + /* init the curl session */ + curl_handle = curl_easy_init(); + + /* set URL to get */ + curl_easy_setopt(curl_handle, CURLOPT_URL, url); + + curl_easy_setopt(curl_handle, CURLOPT_PROGRESSFUNCTION, __progress_info); + curl_easy_setopt(curl_handle, CURLOPT_PROGRESSDATA, NULL); + +#if LIBCURL_VERSION_NUM >= 0x72000 + curl_easy_setopt(curl_handle, CURLOPT_XFERINFOFUNCTION, __xferinfo); + curl_easy_setopt(curl_handle, CURLOPT_XFERINFODATA, (void *)pMultiCurlArg); +#endif + + curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 0L); + + curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L); + + curl_easy_setopt(curl_handle, CURLOPT_PROXY , __proxy_address); + + /* send all data to this function */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, __write_memory_callback); + + /* we want the headers to this file handle */ + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)pMultiCurlArg); + + /* some servers don't like requests that are made without a user-agent field, so we provide one */ + curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); + + pMultiCurlArg->curl_handle = curl_handle; + pMultiCurlArg->req_type = type; + pMultiCurlArg->request_id = req_id; + pMultiCurlArg->user_data = user_data; + strncpy(pMultiCurlArg->url, url, sizeof(pMultiCurlArg->url)-1); + + pthread_mutex_lock(&__MultiCurlArgsLock); + __MultiCurlArgsRemain++; + __add_to_list(pMultiCurlArg, true); + pthread_mutex_unlock(&__MultiCurlArgsLock); + + pthread_mutex_lock(&__CmHandleLock); + curl_multi_add_handle(__cm_handle, curl_handle); + pthread_mutex_unlock(&__CmHandleLock); + + pthread_mutex_lock(&__curl_deliver_mutex); + pthread_cond_signal(&__curl_delivered_cond); + pthread_mutex_unlock(&__curl_deliver_mutex); +#endif + return 0; +} + +static void __post_curl(mapzen_req_type type, MemoryStruct_s *m_chunk, void *user_data) +{ + mapzen_resp_type resp_type = RESP_TYPE_NONE; + switch (type) { + case REQ_TYPE_GEOCODE: + resp_type = RESP_TYPE_GEOCODE; + break; + case REQ_TYPE_REVGEOCODE: + resp_type = RESP_TYPE_REVGEOCODE; + break; + case REQ_TYPE_PLACES: + resp_type = RESP_TYPE_PLACES; + break; + case REQ_TYPE_ROUTE: + resp_type = RESP_TYPE_ROUTE; + break; + default: + resp_type = RESP_TYPE_NONE; + break; + } + + post_curl_response(m_chunk->memory, m_chunk->size, resp_type, user_data); +} + +static void *__curl_thread_handler(void *user_data) +{ + __thread_running_for_curlmulti = true; + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + +#ifdef RESTCURL_USE_MULTI_CURL + CURLMsg *msg; + int Q; + int still_running = -1; + + while (__thread_running_for_curlmulti || __MultiCurlArgsRemain) { + while (__MultiCurlArgsRemain) { + pthread_mutex_lock(&__CmHandleLock); + curl_multi_perform(__cm_handle, &still_running); + pthread_mutex_unlock(&__CmHandleLock); + + if (still_running != __MultiCurlArgsRemain) { + pthread_mutex_lock(&__CmHandleLock); + msg = curl_multi_info_read(__cm_handle, &Q); + pthread_mutex_unlock(&__CmHandleLock); + + if (msg == 0) + break; + + if (msg->msg == CURLMSG_DONE) { + MAP_DEBUG("Transfer completed for one handle"); + CURL *e = msg->easy_handle; + + pthread_mutex_lock(&__MultiCurlArgsLock); + struct MultiCurlArg_List *del = NULL; + if ((del = __delete_from_list(e)) != NULL) { + MAP_DEBUG("Decrementing the handle counter in multiCurl.."); + __MultiCurlArgsRemain--; + } + pthread_mutex_unlock(&__MultiCurlArgsLock); + + if (del && del->mcArg) { + MAP_DEBUG("HTTP Url [%s]", del->mcArg->url); + MAP_DEBUG("Posting the result.."); + __post_curl(del->mcArg->req_type, &(del->mcArg->m_chunk), del->mcArg->user_data); + + if ((del->mcArg->m_chunk).memory) { + g_free((del->mcArg->m_chunk).memory); + (del->mcArg->m_chunk).memory = NULL; + } + + pthread_mutex_lock(&__CmHandleLock); + curl_multi_remove_handle(__cm_handle, del->mcArg->curl_handle); + pthread_mutex_unlock(&__CmHandleLock); + + curl_easy_cleanup(del->mcArg->curl_handle); + + g_free(del->mcArg); + del->mcArg = NULL; + + g_free(del); + del = NULL; + } + } else { + MAP_DEBUG("E: CURLMsg (%d)\n", msg->msg); + } + } + } + + if (__thread_running_for_curlmulti && !__MultiCurlArgsRemain) { + pthread_mutex_lock(&__curl_deliver_mutex); + pthread_cond_wait(&__curl_delivered_cond, &__curl_deliver_mutex); + pthread_mutex_unlock(&__curl_deliver_mutex); + } + } + +#else + /* curl_easy_perform */ +#endif + pthread_exit(NULL); + + return 0; +} + +void cancel_request(int request_id) +{ + if (__cancel_req_list == NULL) + __cancel_req_list = g_list_append(__cancel_req_list, (gpointer) GINT_TO_POINTER(request_id)); + else + __cancel_req_list = g_list_insert_before(__cancel_req_list, NULL, (gpointer) GINT_TO_POINTER(request_id)); +} + +int get_num_running_requests() +{ + MAP_DEBUG("Num of running requests :: >>>> [%d]", __MultiCurlArgsRemain); + return __MultiCurlArgsRemain; +} + +int init_curl() +{ + __cancel_req_list = NULL; + + head = NULL; + curr = NULL; + + __get_proxy_address(); + +#ifdef RESTCURL_USE_MULTI_CURL + pthread_mutex_init(&__MultiCurlArgsLock, NULL); + pthread_mutex_init(&__CmHandleLock, NULL); + pthread_mutex_init(&__curl_deliver_mutex, NULL); + pthread_cond_init(&__curl_delivered_cond, NULL); + + curl_global_init(CURL_GLOBAL_ALL); + + __cm_handle = curl_multi_init(); + curl_multi_setopt(__cm_handle, CURLMOPT_MAXCONNECTS, (long)CURL_MAX_CONNECTS); + + __MultiCurlArgsRemain = 0; + int ret = pthread_create(&__CurlThread, NULL, &__curl_thread_handler, NULL); + __thread_running_for_curlmulti = true; +#endif + + return ret; +} + +int deinit_curl() +{ +#ifdef RESTCURL_USE_MULTI_CURL + __thread_running_for_curlmulti = false; + __MultiCurlArgsRemain = 0; + + pthread_mutex_lock(&__curl_deliver_mutex); + pthread_cond_signal(&__curl_delivered_cond); + pthread_mutex_unlock(&__curl_deliver_mutex); + + pthread_cancel(__CurlThread); + + pthread_join(__CurlThread, NULL); + + curl_multi_cleanup(__cm_handle); + curl_global_cleanup(); + + pthread_mutex_destroy(&__MultiCurlArgsLock); + pthread_mutex_destroy(&__CmHandleLock); + pthread_cond_destroy(&__curl_delivered_cond); + pthread_mutex_destroy(&__curl_deliver_mutex); +#endif + + if (__proxy_address) { + g_free(__proxy_address); + __proxy_address = NULL; + } + + struct MultiCurlArg_List *temp = head; + struct MultiCurlArg_List *next; + + while (temp) { + next = temp->next; + struct MultiCurlArg *curlArg = temp->mcArg; + + if (curlArg) { + if ((curlArg->m_chunk).memory) { + g_free((curlArg->m_chunk).memory); + (curlArg->m_chunk).memory = NULL; + } + + if (curlArg->user_data) { + switch (curlArg->req_type) { + case REQ_TYPE_GEOCODE: + { + MapzenGeocodeQueryData *queryData = (MapzenGeocodeQueryData *)curlArg->user_data; + if (queryData) { + if (queryData->user_data) { + g_free(queryData->user_data); + queryData->user_data = NULL; + } + g_free(queryData); + queryData = NULL; + } + } + break; + case REQ_TYPE_REVGEOCODE: + { + MapzenRevGeocodeQueryData *queryData = (MapzenRevGeocodeQueryData *)curlArg->user_data; + if (queryData) { + if (queryData->user_data) { + g_free(queryData->user_data); + queryData->user_data = NULL; + } + g_free(queryData); + queryData = NULL; + } + } + break; + case REQ_TYPE_PLACES: + { + MapzenPlaceQueryData *queryData = (MapzenPlaceQueryData *)curlArg->user_data; + if (queryData) { + if (queryData->user_data) { + g_free(queryData->user_data); + queryData->user_data = NULL; + } + g_free(queryData); + queryData = NULL; + } + } + break; + case REQ_TYPE_ROUTE: + { + MapzenRouteQueryData *queryData = (MapzenRouteQueryData *)curlArg->user_data; + if (queryData) { + if (queryData->user_data) { + g_free(queryData->user_data); + queryData->user_data = NULL; + } + g_free(queryData); + queryData = NULL; + } + } + break; + default: + break; + } + } + + curl_easy_cleanup(curlArg->curl_handle); + + g_free(curlArg); + curlArg = NULL; + } + g_free(temp); + + temp = next; + } + head = NULL; + + g_list_free(__cancel_req_list); + __cancel_req_list = NULL; + + return 0; +} diff --git a/src/mapzen/mapzen_restcurl.h b/src/mapzen/mapzen_restcurl.h new file mode 100644 index 0000000..897993d --- /dev/null +++ b/src/mapzen/mapzen_restcurl.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MAPZEN_RESTCURL_H_ +#define _MAPZEN_RESTCURL_H_ + +#include "mapzen_server_private.h" + +#define CURL_MAX_CONNECTS 30 + +int init_curl(); + +int deinit_curl(); + +int get_num_running_requests(); + +int add_handle(char *url, mapzen_req_type type, void *user_data); + +void cancel_request(int request_id); + +#endif /* _MAPZEN_RESTCURL_H_ */ diff --git a/src/mapzen/mapzen_revgeocode.c b/src/mapzen/mapzen_revgeocode.c new file mode 100644 index 0000000..ebe173c --- /dev/null +++ b/src/mapzen/mapzen_revgeocode.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include "mapzen_revgeocode.h" +#include "mapzen_types.h" +#include "mapzen_server_private.h" +#include "mapzen_debug.h" +#include "mapzen_queue.h" +#include "mapzen_restcurl.h" +#include "mapzen_util.h" + +#define REVERSE_GEOCODE_URL "https://search.mapzen.com/v1/reverse?size=1&point.lat=%f&point.lon=%f&api_key=%s" + +int query_revgeocode(gchar *maps_key, gdouble latitude, gdouble longitude, gpointer user_data) +{ + char url[1024]; + + if (maps_key != NULL) + snprintf(url, sizeof(url), REVERSE_GEOCODE_URL, latitude, longitude, maps_key); + else + snprintf(url, sizeof(url), REVERSE_GEOCODE_URL, latitude, longitude, "null"); + + add_handle(url, REQ_TYPE_REVGEOCODE, user_data); + + return 0; +} diff --git a/src/mapzen/mapzen_revgeocode.h b/src/mapzen/mapzen_revgeocode.h new file mode 100644 index 0000000..e61546f --- /dev/null +++ b/src/mapzen/mapzen_revgeocode.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MAPZEN_REVGEOCODE_H_ +#define _MAPZEN_REVGEOCODE_H_ + +#include "mapzen_api.h" +#include "mapzen_types.h" + +int query_revgeocode(gchar *maps_key, gdouble latitude, gdouble longitude, gpointer user_data); + +#endif /* _MAPZEN_REVGEOCODE_H_ */ diff --git a/src/mapzen/mapzen_route.c b/src/mapzen/mapzen_route.c new file mode 100644 index 0000000..b1d24ef --- /dev/null +++ b/src/mapzen/mapzen_route.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include "mapzen_route.h" +#include "mapzen_types.h" +#include "mapzen_server_private.h" +#include "mapzen_debug.h" +#include "mapzen_queue.h" +#include "mapzen_restcurl.h" +#include "mapzen_util.h" + +#define ROUTE_URL "https://valhalla.mapzen.com/route?api_key=%s&json=" + +int query_route(gchar *maps_key, coords_s startPoint, coords_s endPoint, costing costing, feature_penalties avoids, route_driving_style style, GList *waypoints, gpointer user_data) +{ + char url[1024] = ""; + char tmpStr[512]; + + if (maps_key != NULL) + snprintf(tmpStr, sizeof(tmpStr), ROUTE_URL, maps_key); + else + snprintf(tmpStr, sizeof(tmpStr), ROUTE_URL, "null"); + + STRCPY(url, tmpStr); + + STRCAT(url, '"directions_options":{"units":"mi"}'); /* Keeping default as miles and conversion will be done later */ + + if (costing == COSTING_AUTO) + STRCAT(url, '"costing":"auto"'); + else if (costing == COSTING_AUTO_SHORTER) + STRCAT(url, '"costing":"auto_shorter"'); + else if (costing == COSTING_PEDESTRIAN) + STRCAT(url, '"costing":"pedestrian"'); + else if (costing == COSTING_MULTIMODAL) + STRCAT(url, '"costing":"multimodal"'); + else if (costing == COSTING_BICYCLE) + STRCAT(url, '"costing":"bicycle"'); + + if (avoids) { + STRCAT(url, '"costing_options":{' + costing + ':{'); + + if (avoids == PENALTY_LIMITED_ACCESS) { + snprintf(tmpStr, sizeof(tmpStr), ""); + STRCAT(url, ""); + } + else if (avoids == PENALTY_TOLL_ROADS) { + snprintf(tmpStr, sizeof(tmpStr), ',"toll_booth_penalty":"1"'); + STRCAT(url, tmpStr); + } + else if (avoids == PENALTY_USE_FERRY){ + snprintf(tmpStr, sizeof(tmpStr), ',"use_ferry":"0"'); + STRCAT(url, tmpStr); + } + else if (avoids == PENALTY_USE_UNPAVED) { + snprintf(tmpStr, sizeof(tmpStr), ""); + STRCAT(url, tmpStr); + } + else if (avoids == PENALTY_SEASONAL_CLOSURE) { + snprintf(tmpStr, sizeof(tmpStr), ""); + STRCAT(url, tmpStr); + } + else if (avoids == PENALTY_COUNTRY_CROSSING) { + snprintf(tmpStr, sizeof(tmpStr), ',"country_crossing_penalty":"1"'); + STRCAT(url, tmpStr); + } + STRCAT(url, '}}'); + } + + if (style == DRIVING_STYLE_NORMAL) + STRCAT(url, ""); + else if (style == DRIVING_STYLE_CAUTIOUS) + STRCAT(url, ""); + else if (style == DRIVING_STYLE_AGGRESSIVE) + STRCAT(url, ""); + + int length = g_list_length(waypoints); + if (length != 0) { + int index = 0; + GList *waypoints_list = NULL; + waypoints_list = g_list_first(waypoints); + + while (waypoints_list) { + + coords_s *data = (coords_s *) waypoints_list->data; + + STRCAT(url, '"locations":[{"'); + + for (i = 0; i < sizeof(data); i++) { + snprintf(tmpStr, sizeof(tmpStr), '"lat":%f,"lon":%f},', data[i].latitude, data[i].longitude); + STRCAT(url, tmpStr); + } + STRCAT(url, ']'); + + waypoints_list = g_list_next(waypoints_list); + index++; + } + } else { + snprintf(tmpStr, sizeof(tmpStr), '"locations":[{"lat":%f,"lon":%f},{"lat":%f,"lon":%f}]', startPoint.latitude, startPoint.longitude, endPoint.latitude, endPoint.longitude); + STRCAT(url, tmpStr); + } + + //TODO: url encode (curl_escape) the json part of the request + + add_handle(url, REQ_TYPE_ROUTE, user_data); + + return 0; +} diff --git a/src/mapzen/mapzen_route.h b/src/mapzen/mapzen_route.h new file mode 100644 index 0000000..810e0b2 --- /dev/null +++ b/src/mapzen/mapzen_route.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MAPZEN_ROUTE_H_ +#define _MAPZEN_ROUTE_H_ + +#include "mapzen_api.h" +#include "mapzen_types.h" + +int query_route(gchar *maps_key, coords_s startPoint, coords_s endPoint, costing costing, feature_penalties avoids, route_driving_style style, GList *waypoints, gpointer user_data); + +#endif /* _MAPZEN_ROUTE_H_ */ diff --git a/src/mapzen/mapzen_server_private.h b/src/mapzen/mapzen_server_private.h new file mode 100644 index 0000000..c688b8e --- /dev/null +++ b/src/mapzen/mapzen_server_private.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MAPZEN_PRIVATE_H_ +#define _MAPZEN_PRIVATE_H_ + +#include "mapzen_api.h" + +typedef enum { + REQ_TYPE_GEOCODE = 0, + REQ_TYPE_REVGEOCODE, + REQ_TYPE_PLACES, + REQ_TYPE_ROUTE, + REQ_TYPE_NONE +} mapzen_req_type; + +typedef enum { + RESP_TYPE_GEOCODE = 0, + RESP_TYPE_REVGEOCODE, + RESP_TYPE_PLACES, + RESP_TYPE_ROUTE, + RESP_TYPE_NONE +} mapzen_resp_type; + +typedef struct { + int requestId; + mapzen_geocode_cb geocode_cb; + void *user_data; +} MapzenGeocodeQueryData; + +typedef struct { + int requestId; + mapzen_reverse_geocode_cb reverse_geocode_cb; + void *user_data; +} MapzenRevGeocodeQueryData; + +typedef struct { + int requestId; + mapzen_route_cb route_cb; + coords_s origin; + coords_s destination; + route_unit unit; + void *user_data; +} MapzenRouteQueryData; + +typedef struct { + int requestId; + mapzen_place_search_cb place_search_cb; + void *user_data; +} MapzenPlaceQueryData; + +typedef struct { + mapzen_error_e error; + int requestId; + mapzen_geocode_cb geocode_cb; + GList *coords; + void *user_data; +} MapzenGeocodeResponseData; + +typedef struct { + mapzen_error_e error; + int requestId; + mapzen_reverse_geocode_cb reverse_geocode_cb; + mapzen_address_resp_s *addressDetails; + void *user_data; +} MapzenRevGeocodeResponseData; + +typedef struct { + mapzen_error_e error; + int requestId; + mapzen_route_cb route_cb; + mapzen_route_resp_s *routeResponse; + void *user_data; +} MapzenRouteResponseData; + +typedef struct { + mapzen_error_e error; + int requestId; + mapzen_place_search_cb place_search_cb; + GList *places; + void *user_data; +} MapzenPlaceResponseData; + +typedef struct { + mapzen_resp_type type; + void *data; +} MapzenQueueData; + +#endif /* _MAPZEN_PRIVATE_H_ */ diff --git a/src/mapzen/mapzen_types.h b/src/mapzen/mapzen_types.h new file mode 100644 index 0000000..356bf52 --- /dev/null +++ b/src/mapzen/mapzen_types.h @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MAPZEN_TYPES_H_ +#define _MAPZEN_TYPES_H_ + +#include + +typedef enum { + MAPZEN_ERROR_NONE = 0, /**< Successful */ + MAPZEN_ERROR_PERMISSION_DENIED, /**< Permission Denied */ + MAPZEN_ERROR_OUT_OF_MEMORY, /**< Out of memory */ + MAPZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */ + MAPZEN_ERROR_NOT_SUPPORTED, /**< Not supported */ + MAPZEN_ERROR_CONNECTION_TIMED_OUT, /**< Timeout error, no answer */ + MAPZEN_ERROR_NETWORK_UNREACHABLE, /**< Network unavailable */ + MAPZEN_ERROR_INVALID_OPERATION, /**< Opeartion is not valid */ + MAPZEN_ERROR_KEY_NOT_AVAILABLE, /**< Invalid key */ + MAPZEN_ERROR_RESOURCE_BUSY, /**< Resource busy */ + MAPZEN_ERROR_CANCELED, /**< Service canceled */ + MAPZEN_ERROR_UNKNOWN, /**< Unknown error */ + MAPZEN_ERROR_SERVICE_NOT_AVAILABLE, /**< Service unavailabe*/ + MAPZEN_ERROR_NOT_FOUND, /**< Result not found */ +} mapzen_error_e; + +typedef enum { + MAPZEN_BOUNDARY_NONE = 0, /* Undefined geographical area type. */ + MAPZEN_BOUNDARY_RECT, /* Rectangular geographical area type. */ + MAPZEN_BOUNDARY_CIRCLE, /* Circle geographical area type. */ +} boundary_type; + +typedef enum { + COSTING_AUTO = 0, + COSTING_AUTO_SHORTER, + COSTING_BICYCLE, + COSTING_MULTIMODAL, + COSTING_PEDESTRIAN +} route_type; + +typedef enum { + UNIT_M = 0, /* for miles */ + UNIT_KM /* for kilometers */ +} route_unit; + +typedef enum { + PENALTY_NONE = 0, //TODO: Mapzen does not have currently + PENALTY_LIMITED_ACCESS, //TODO: Mapzen does not have currently + PENALTY_TOLL_ROADS, //set to > 0 to avoid + PENALTY_USE_FERRY, //This is range of values between 0 and 1. Values near 0 attempt to avoid ferries and + //values near 1 will favor ferries. + PENALTY_USE_UNPAVED, //TODO: Mapzen does not have currently + PENALTY_SEASONAL_CLOSURE, //TODO: Mapzen does not have currently + PENALTY_COUNTRY_CROSSING // set to > 0 to avoid +} route_feature_avoids; + +typedef enum { + DRIVING_STYLE_NORMAL = 0, + DRIVING_STYLE_CAUTIOUS, + DRIVING_STYLE_AGGRESSIVE +} route_driving_style; + +typedef struct { + gdouble latitude; + gdouble longitude; +} coords_s; + +typedef struct { + coords_s top_left; + coords_s bottom_right; +} rectangle_s; + +typedef struct { + coords_s center; + gdouble radius; +} circle_s; + +typedef struct { + boundary_type type; + union { + rectangle_s rect; + circle_s circle; + }; +} mapzen_boundary_s; + +typedef struct { + gchar *maps_key; + gchar *address; + mapzen_boundary_s *boundary; + gint num_res; +} mapzen_geocode_req_s; + +typedef struct { + gchar *maps_key; + gint num_res; + coords_s coordinates; +} mapzen_revgeocode_req_s; + +typedef struct { + gchar *maps_key; + gchar *search_string; + gint num_res; + gchar *country_code; + mapzen_boundary_s *boundary; + GList *excludes; +} mapzen_search_req_s; + +typedef struct { + gchar *maps_key; + coords_s from; + coords_s to; + route_unit unit; + route_type type; + route_feature_avoids avoids; /* List of type strings. (Limited Access, Toll Road, Ferry, Unpaved, Seasonal Closure, Country Crossing) */ + route_driving_style driving_style; /* (1 - cautious, 2 - normal, 3 - aggressive) */ + GList *way_points; /* List of type coords_s */ +} mapzen_route_req_s; + +typedef struct { + gint zoom_level; + coords_s center_coords; +} mapzen_tiledata_req_s; + +typedef struct { + gchar *street_add; + gchar *neighbourhood; + gchar *building_number; + gchar *city; + gchar *county; + gchar *state; + gchar *country; + gchar *country_code; + gchar *postal_code; +} mapzen_address_resp_s; + +typedef struct { + gchar *place_id; + gchar *display_name; + mapzen_address_resp_s *address; + rectangle_s bounding_box; + coords_s coordinates; + gchar *category; + gchar *subcategory; + gchar *icon_url; +} mapzen_place_resp_s; + +typedef struct { + guint type; + guint direction; + guint text; + gchar *icon_url; +} mapzen_route_maneuver_signs; + +typedef struct { + coords_s start_point; + coords_s end_point; + gdouble distance; + guint time; + gchar *formatted_time; + guint attribute; + guint turn_type; + guint direction; + gchar *instruction; + gchar *direction_name; + guint index; + gchar *street_name; +} mapzen_route_maneuver; + +typedef struct { + rectangle_s bounding_box; + gdouble distance; + route_unit distance_unit; + guint time; + gchar *formatted_time; + route_type type; + GList *maneuvers; /* List of type mapzen_route_maneuver */ + GList *shapePoints; +} mapzen_route_resp_s; + +#endif /* _MAPZEN_TYPES_H_ */ diff --git a/src/mapzen/mapzen_util.c b/src/mapzen/mapzen_util.c new file mode 100644 index 0000000..593e32f --- /dev/null +++ b/src/mapzen/mapzen_util.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mapzen_util.h" +#include "mapzen_debug.h" +#include + +#define PI 3.14159265359 +#define EARTH_RADIUS 6371 + +void calculate_point(gdouble Lat1, gdouble Lon1, int dBearing, gdouble dist, coords_s **coord) +{ + Lat1 = (Lat1 / 180.0) * PI; + Lon1 = (Lon1 / 180.0) * PI; + + gdouble dLat = asin(sin(Lat1) * cos(dist / EARTH_RADIUS) + (cos(Lat1) * sin(dist / EARTH_RADIUS) * cos(dBearing))); + + dLat = (180.0 * dLat) / PI; + + gdouble dLon = Lon1 + atan2(sin(dBearing) * sin(dist / EARTH_RADIUS) * cos(Lat1), cos(dist / EARTH_RADIUS) - sin(Lat1) * sin((dLat / 180.0) * PI)); + + dLon = (180.0 * dLon) / PI; + + if (*coord == NULL) + *coord = (coords_s *)g_malloc0(sizeof(coords_s)); + + if (*coord) { + (*coord)->latitude = dLat; + (*coord)->longitude = dLon; + } +} + diff --git a/src/mapzen/mapzen_util.h b/src/mapzen/mapzen_util.h new file mode 100644 index 0000000..36a6ca0 --- /dev/null +++ b/src/mapzen/mapzen_util.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MAPZEN_UTIL_H_ +#define _MAPZEN_UTIL_H_ + +#include "mapzen_types.h" + +#define STRCPY(buffer, string) strncpy(buffer, string, sizeof(buffer)-strlen(buffer)-1) +#define STRCAT(buffer, string) strncat(buffer, string, sizeof(buffer)-strlen(buffer)-1) + +void calculate_point(gdouble Lat1, gdouble Lon1, int dBearing, gdouble dist, coords_s **coord); + +#endif /* _MAPZEN_UTIL_H_ */ diff --git a/src/mapzen_api.cpp b/src/mapzen_api.cpp new file mode 100644 index 0000000..4455f96 --- /dev/null +++ b/src/mapzen_api.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mapzen_api.h" +#include "mapzen_constants.h" +#include "mapzen_utils.h" + +int MapzenPluginRoute(maps_coordinates_h origin, maps_coordinates_h destination, + maps_item_hashtable_h pref, maps_service_search_route_cb callback_func, + void* user_data, int* request_id) +{ + // Make sure pointers are valid + if (!origin || !destination || !callback_func || !request_id) + return ErrorType::kInvalidParameter; + + // Check if origin and destination coordinates are valid + if (!MapzenUtils::IsValid(*(maps_coordinates_s*)origin) || + !MapzenUtils::IsValid(*(maps_coordinates_s*)destination)) + return ErrorType::kInvalidParameter; + + int error = 0; + return error; +} diff --git a/src/mapzen_plugin.c b/src/mapzen_plugin.c new file mode 100644 index 0000000..c00bf8b --- /dev/null +++ b/src/mapzen_plugin.c @@ -0,0 +1,1395 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "mapzen_plugin.h" +#include "mapzen_plugin_internal.h" +#include "mapzen_api.h" +#include "mapzen_util.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_NUM_RESULTS 10 +#define _PROVIDER_KEY_MAX_SIZE 1024 + +static const double LATITUDE_RANGE = 85.05113; +static const double LONGITUDE_RANGE = 180.0; + +static int __request_id = 0; +static maps_plugin_h __plugin = NULL; +static char __provider_key[_PROVIDER_KEY_MAX_SIZE] = { 0 }; + +static maps_item_hashtable_h preference_plugin = NULL; + +int __maps_service_instance_count = 0; + +static int __convert_to_maps_error(int ret) +{ + switch (ret) { + case MAPZEN_ERROR_NONE: + return MAPS_ERROR_NONE; + case MAPZEN_ERROR_PERMISSION_DENIED: + return MAPS_ERROR_PERMISSION_DENIED; + case MAPZEN_ERROR_OUT_OF_MEMORY: + return MAPS_ERROR_OUT_OF_MEMORY; + case MAPZEN_ERROR_INVALID_PARAMETER: + return MAPS_ERROR_INVALID_PARAMETER; + case MAPZEN_ERROR_NOT_SUPPORTED: + return MAPS_ERROR_NOT_SUPPORTED; + case MAPZEN_ERROR_CONNECTION_TIMED_OUT: + return MAPS_ERROR_CONNECTION_TIME_OUT; + case MAPZEN_ERROR_NETWORK_UNREACHABLE: + return MAPS_ERROR_NETWORK_UNREACHABLE; + case MAPZEN_ERROR_INVALID_OPERATION: + return MAPS_ERROR_INVALID_OPERATION; + case MAPZEN_ERROR_KEY_NOT_AVAILABLE: + return MAPS_ERROR_KEY_NOT_AVAILABLE; + case MAPZEN_ERROR_RESOURCE_BUSY: + return MAPS_ERROR_RESOURCE_BUSY; + case MAPZEN_ERROR_CANCELED: + return MAPS_ERROR_CANCELED; + case MAPZEN_ERROR_UNKNOWN: + return MAPS_ERROR_UNKNOWN; + case MAPZEN_ERROR_SERVICE_NOT_AVAILABLE: + return MAPS_ERROR_SERVICE_NOT_AVAILABLE; + case MAPZEN_ERROR_NOT_FOUND: + return MAPS_ERROR_NOT_FOUND; + default: + return MAPS_ERROR_UNKNOWN; + } +} +/* +static maps_route_turn_type_e __convert_route_turn_type(int index) +{ + maps_route_turn_type_e type = MAPS_ROUTE_TURN_TYPE_NONE; + + if (index == 0) + type = MAPS_ROUTE_TURN_TYPE_STRAIGHT; + else if (index == 1) + type = MAPS_ROUTE_TURN_TYPE_LIGHT_RIGHT; + else if (index == 2) + type = MAPS_ROUTE_TURN_TYPE_RIGHT; + else if (index == 3) + type = MAPS_ROUTE_TURN_TYPE_HARD_RIGHT; + else if (index == 5) + type = MAPS_ROUTE_TURN_TYPE_HARD_LEFT; + else if (index == 6) + type = MAPS_ROUTE_TURN_TYPE_LIGHT_LEFT; + else if (index == 7) + type = MAPS_ROUTE_TURN_TYPE_LIGHT_LEFT; + else if (index == 8) + type = MAPS_ROUTE_TURN_TYPE_UTURN_RIGHT; + else if (index == 9) + type = MAPS_ROUTE_TURN_TYPE_UTURN_LEFT; + else if (index == 16) + type = MAPS_ROUTE_TURN_TYPE_RIGHT_FORK; + else if (index == 17) + type = MAPS_ROUTE_TURN_TYPE_LEFT_FORK; + else if (index == 18) + type = MAPS_ROUTE_TURN_TYPE_STRAIGHT_FORK; + else + type = MAPS_ROUTE_TURN_TYPE_NONE; + + return type; +}*/ + +static bool __replace_space(char *place_name, char **modified_place_name) +{ + if (!place_name) return false; + + int new_str_len = 0; + char *ch; + for (ch = place_name; *ch != '\0'; ch++) { + if (*ch == ' ') + new_str_len += 2; + new_str_len++; + } + + if (strlen(place_name) < new_str_len) { + *modified_place_name = (char *)g_malloc((new_str_len + 1) * sizeof(char)); + if (*modified_place_name) { + char *ch1, *ch2; + for (ch1 = place_name, ch2 = *modified_place_name; *ch1 != '\0'; ch1++) { + if (*ch1 == ' ') { + ch2[0] = '%'; + ch2[1] = '2'; + ch2[2] = '0'; + ch2 += 3; + } else { + *ch2 = *ch1; + ch2++; + } + } + *ch2 = '\0'; + + return true; + } + } + return false; +} + +EXPORT_API int maps_plugin_init(maps_plugin_h *plugin) +{ + if (!plugin) + return MAPS_ERROR_INVALID_PARAMETER; + + int ret = MAPS_ERROR_NONE; + if (!__plugin) { + ret = mapzen_init(); + } + + if (ret == MAPS_ERROR_NONE) { + __maps_service_instance_count++; + __plugin = plugin; + } + + return __convert_to_maps_error(ret); +} + +EXPORT_API int maps_plugin_shutdown(maps_plugin_h plugin) +{ + MAPS_LOGD("PLUGIN SHUTDOWN"); + if (!plugin) + return MAPS_ERROR_INVALID_PARAMETER; + + __maps_service_instance_count--; + + int ret = MAPS_ERROR_NONE; + if (__maps_service_instance_count == 0) { + ret = mapzen_shutdown(); + __plugin = NULL; + } + + return __convert_to_maps_error(ret); +} + +EXPORT_API int maps_plugin_is_service_supported(maps_service_e service, bool *supported) +{ + if (!supported) + return MAPS_ERROR_INVALID_PARAMETER; + + switch (service) { + case MAPS_SERVICE_GEOCODE: + case MAPS_SERVICE_GEOCODE_INSIDE_AREA: + case MAPS_SERVICE_GEOCODE_BY_STRUCTURED_ADDRESS: + case MAPS_SERVICE_REVERSE_GEOCODE: + case MAPS_SERVICE_SEARCH_PLACE: + case MAPS_SERVICE_SEARCH_PLACE_BY_AREA: + case MAPS_SERVICE_SEARCH_PLACE_BY_ADDRESS: + case MAPS_SERVICE_SEARCH_ROUTE: + case MAPS_SERVICE_SEARCH_ROUTE_WAYPOINTS: + case MAPS_SERVICE_CANCEL_REQUEST: + *supported = true; + return MAPS_ERROR_NONE; + default: + *supported = false; + return MAPS_ERROR_NOT_SUPPORTED; + } +} + +EXPORT_API int maps_plugin_is_data_supported(maps_service_data_e data, bool *supported) +{ + if (!supported) + return MAPS_ERROR_INVALID_PARAMETER; + + switch (data) { + case MAPS_PLACE_ADDRESS: + case MAPS_PLACE_CATEGORIES: + case MAPS_PLACE_IMAGE: + /* unsupported */ + /* case MAPS_PLACE_RATING: */ + /* case MAPS_PLACE_ATTRIBUTES: */ + /* case MAPS_PLACE_CONTACTS: */ + /* case MAPS_PLACE_EDITORIALS: */ + /* case MAPS_PLACE_REVIEWS: */ + /* case MAPS_PLACE_SUPPLIER: */ + /* case MAPS_PLACE_RELATED: */ + + case MAPS_ROUTE_PATH: + case MAPS_ROUTE_SEGMENTS_PATH: + case MAPS_ROUTE_SEGMENTS_MANEUVERS: + *supported = true; + return MAPS_ERROR_NONE; + default: + *supported = false; + return MAPS_ERROR_NOT_SUPPORTED; + } +} + +EXPORT_API int maps_plugin_get_info(maps_plugin_info_h *info) +{ + if (!info) + return MAPS_ERROR_INVALID_PARAMETER; + + maps_plugin_info_create(info); + maps_plugin_info_set_provider_name(*info, "MAPZEN"); + + return MAPS_ERROR_NONE; +} + +EXPORT_API int maps_plugin_set_provider_key(const char *provider_key) +{ + if (!provider_key) + return MAPS_ERROR_INVALID_PARAMETER; + + g_snprintf(__provider_key, _PROVIDER_KEY_MAX_SIZE, "%s", provider_key); + + return MAPS_ERROR_NONE; +} + +EXPORT_API int maps_plugin_get_provider_key(char **provider_key) +{ + if (!provider_key) + return MAPS_ERROR_INVALID_PARAMETER; + + *provider_key = g_strndup(__provider_key, _PROVIDER_KEY_MAX_SIZE); + + return MAPS_ERROR_NONE; +} + +EXPORT_API int maps_plugin_set_preference(maps_item_hashtable_h preference) +{ + if (!preference) + return MAPS_ERROR_INVALID_PARAMETER; + + maps_item_hashtable_clone(preference, &preference_plugin); + return MAPS_ERROR_NONE; +} + +EXPORT_API int maps_plugin_get_preference(maps_item_hashtable_h *preference) +{ + if (!preference) + return MAPS_ERROR_INVALID_PARAMETER; + + maps_item_hashtable_clone(preference_plugin, preference); + return MAPS_ERROR_NONE; +} + +static void __mapzen_geocode_cb(mapzen_error_e result, int request_id, GList *co_ordinates, void *user_data) +{ + MAPS_LOGD("Got GEOCODE callback from ENGINE"); + + callback_info_geocode *calldata_geocode = (callback_info_geocode *) user_data; + + if ((result != MAPZEN_ERROR_NONE) || (co_ordinates == NULL)) { + MAPS_LOGD(">>>>> Invalid GEOCODE result <<<<<"); + calldata_geocode->callback((maps_error_e)__convert_to_maps_error(result), calldata_geocode->reqID, 0, 0, NULL, calldata_geocode->data); + } else { + int total_count = (int) g_list_length(co_ordinates); + int index = 0; + + GList *coords = NULL; + coords = g_list_first(co_ordinates); + + while (coords) { + MAPS_LOGD("coordinate %d", index); + coords_s *data = (coords_s *) coords->data; + + if (data != NULL) { + maps_coordinates_h resultCoords; + maps_coordinates_create(data->latitude, data->longitude, &resultCoords); + bool b = calldata_geocode->callback(MAPS_ERROR_NONE, calldata_geocode->reqID, index, total_count, resultCoords, calldata_geocode->data); + if (!b) + return; + } + index++; + coords = coords->next; + } + } +} + +EXPORT_API int maps_plugin_geocode(const char *address, const maps_preference_h preference, maps_service_geocode_cb callback, void *user_data, int *request_id) +{ + if (!address || !callback || !request_id) + return MAPS_ERROR_INVALID_PARAMETER; + + callback_info_geocode *calldata_geocode = (callback_info_geocode *)g_malloc0(sizeof(callback_info_geocode)); + if (calldata_geocode == NULL) + MAPS_PRINT_ERROR_CODE_RETURN(MAPS_ERROR_OUT_OF_MEMORY); + + calldata_geocode->callback = callback; + calldata_geocode->data = user_data; + + mapzen_geocode_req_s *geocode_req = (mapzen_geocode_req_s *)g_malloc0(sizeof(mapzen_geocode_req_s)); + if (geocode_req == NULL) { + g_free(calldata_geocode); + calldata_geocode = NULL; + MAPS_PRINT_ERROR_CODE_RETURN(MAPS_ERROR_OUT_OF_MEMORY); + } + + char *modified_address = NULL; + bool b_isAddress_modified = false; + b_isAddress_modified = __replace_space((char *)address, &modified_address); + + if (b_isAddress_modified) + geocode_req->address = g_strdup((gchar *) modified_address); + else + geocode_req->address = g_strdup((gchar *) address); + + if (modified_address) { + g_free(modified_address); + modified_address = NULL; + } + + geocode_req->maps_key = g_strdup((gchar *) __provider_key); + geocode_req->boundary = NULL; + + int max_result = 0; + maps_preference_get_max_results(preference, &max_result); + + if (max_result <= 0) + geocode_req->num_res = DEFAULT_NUM_RESULTS; + else + geocode_req->num_res = max_result; + + *request_id = ++__request_id; + calldata_geocode->reqID = __request_id; + + int ret = mapzen_geocode(geocode_req, __mapzen_geocode_cb, __request_id, (void *) calldata_geocode); + + return __convert_to_maps_error(ret); +} + +EXPORT_API int maps_plugin_geocode_inside_area(const char *address, const maps_area_h bounds, const maps_preference_h preference, maps_service_geocode_cb callback, void *user_data, int *request_id) +{ + if (!bounds || !address || !callback || !request_id) + return MAPS_ERROR_INVALID_PARAMETER; + + callback_info_geocode *calldata_geocode = (callback_info_geocode *)g_malloc0(sizeof(callback_info_geocode)); + if (calldata_geocode == NULL) + MAPS_PRINT_ERROR_CODE_RETURN(MAPS_ERROR_OUT_OF_MEMORY); + + calldata_geocode->callback = callback; + calldata_geocode->data = user_data; + + mapzen_geocode_req_s *geocode_req = (mapzen_geocode_req_s *)g_malloc0(sizeof(mapzen_geocode_req_s)); + if (geocode_req == NULL) { + free(calldata_geocode); + MAPS_PRINT_ERROR_CODE_RETURN(MAPS_ERROR_OUT_OF_MEMORY); + } + + char *modified_address = NULL; + bool b_isAddress_modified = false; + b_isAddress_modified = __replace_space((char *)address, &modified_address); + + if (b_isAddress_modified) + geocode_req->address = g_strdup((gchar *) modified_address); + else + geocode_req->address = g_strdup((gchar *) address); + + if (modified_address) { + g_free(modified_address); + modified_address = NULL; + } + + geocode_req->maps_key = g_strdup((gchar *) __provider_key); + + int max_result = 0; + maps_preference_get_max_results(preference, &max_result); + + if (max_result <= 0) + geocode_req->num_res = DEFAULT_NUM_RESULTS; + else + geocode_req->num_res = max_result; + + geocode_req->boundary = NULL; + geocode_req->boundary = (mapzen_boundary_s *)g_malloc0(sizeof(mapzen_boundary_s)); + + maps_area_s *area = (maps_area_s *) bounds; + + if (area && geocode_req->boundary) { + if (area->type == MAPS_AREA_RECTANGLE) { + geocode_req->boundary->type = MAPZEN_BOUNDARY_RECT; + geocode_req->boundary->rect.top_left.latitude = area->rect.top_left.latitude; + geocode_req->boundary->rect.top_left.longitude = area->rect.top_left.longitude; + geocode_req->boundary->rect.bottom_right.latitude = area->rect.bottom_right.latitude; + geocode_req->boundary->rect.bottom_right.longitude = area->rect.bottom_right.longitude; + } else if (area->type == MAPS_AREA_CIRCLE) { + geocode_req->boundary->type = MAPZEN_BOUNDARY_CIRCLE; + geocode_req->boundary->circle.center.latitude = area->circle.center.latitude; + geocode_req->boundary->circle.center.longitude = area->circle.center.longitude; + geocode_req->boundary->circle.radius = area->circle.radius; + } + } + + *request_id = ++__request_id; + calldata_geocode->reqID = __request_id; + + int ret = mapzen_geocode(geocode_req, __mapzen_geocode_cb, __request_id, (void *) calldata_geocode); + + return __convert_to_maps_error(ret); +} + +EXPORT_API int maps_plugin_geocode_by_structured_address(const maps_address_h address, const maps_preference_h preference, maps_service_geocode_cb callback, void *user_data, int *request_id) +{ + if (!address || !callback || !request_id) + return MAPS_ERROR_INVALID_PARAMETER; + + callback_info_geocode *calldata_geocode = (callback_info_geocode *)g_malloc0(sizeof(callback_info_geocode)); + if (calldata_geocode == NULL) + MAPS_PRINT_ERROR_CODE_RETURN(MAPS_ERROR_OUT_OF_MEMORY); + + calldata_geocode->callback = callback; + calldata_geocode->data = user_data; + + mapzen_geocode_req_s *geocode_req = (mapzen_geocode_req_s *)g_malloc0(sizeof(mapzen_geocode_req_s)); + if (geocode_req == NULL) { + free(calldata_geocode); + MAPS_PRINT_ERROR_CODE_RETURN(MAPS_ERROR_OUT_OF_MEMORY); + } + + char resultAddressQuery[1024] = ""; + + char *street = NULL; + maps_address_get_street(address, &street); + if (street != NULL) + STRCAT(resultAddressQuery, street); + + char *city = NULL; + maps_address_get_city(address, &city); + if ((strlen(resultAddressQuery) > 0) && (city != NULL)) { + STRCAT(resultAddressQuery, ","); + STRCAT(resultAddressQuery, city); + } else if (city != NULL) { + STRCAT(resultAddressQuery, city); + } + + char *state = NULL; + maps_address_get_state(address, &state); + if ((strlen(resultAddressQuery) > 0) && (state != NULL)) { + STRCAT(resultAddressQuery, ","); + STRCAT(resultAddressQuery, state); + } else if (state != NULL) { + STRCAT(resultAddressQuery, state); + } + +#if 0 + char *district = NULL; + maps_address_get_district(address, &district); + if ((strlen(resultAddressQuery) > 0) && (district != NULL)) { + STRCAT(resultAddressQuery, ", "); + STRCAT(resultAddressQuery, district); + } + + char *country = NULL; + maps_address_get_country(address, &country); + if ((strlen(resultAddressQuery) > 0) && (country != NULL)) { + STRCAT(resultAddressQuery, ", "); + STRCAT(resultAddressQuery, country); + } + + char *country_code = NULL; + maps_address_get_country_code(address, &country_code); + if ((strlen(resultAddressQuery) > 0) && (country_code != NULL)) { + STRCAT(resultAddressQuery, ", "); + STRCAT(resultAddressQuery, country_code); + } else if (country_code != NULL) { + STRCAT(resultAddressQuery, country_code); + } + + char *county = NULL; + maps_address_get_county(address, &county); + if ((strlen(resultAddressQuery) > 0) && (county != NULL)) { + STRCAT(resultAddressQuery, ", "); + STRCAT(resultAddressQuery, county); + } +#endif + + char *postal_code = NULL; + maps_address_get_postal_code(address, &postal_code); + if ((strlen(resultAddressQuery) > 0) && (postal_code != NULL)) { + STRCAT(resultAddressQuery, ","); + STRCAT(resultAddressQuery, postal_code); + } else if (postal_code != NULL) { + STRCAT(resultAddressQuery, postal_code); + } + + char *modified_address = NULL; + bool b_isAddress_modified = false; + b_isAddress_modified = __replace_space(resultAddressQuery, &modified_address); + + if (b_isAddress_modified) + geocode_req->address = g_strdup((gchar *) modified_address); + else + geocode_req->address = g_strdup((gchar *) resultAddressQuery); + + if (modified_address) { + g_free(modified_address); + modified_address = NULL; + } + + geocode_req->maps_key = g_strdup((gchar *) __provider_key); + geocode_req->boundary = NULL; + + int max_result = 0; + maps_preference_get_max_results(preference, &max_result); + + if (max_result <= 0) + geocode_req->num_res = DEFAULT_NUM_RESULTS; + else + geocode_req->num_res = max_result; + + *request_id = ++__request_id; + calldata_geocode->reqID = __request_id; + + int ret = mapzen_geocode(geocode_req, __mapzen_geocode_cb, __request_id, (void *) calldata_geocode); + + return __convert_to_maps_error(ret); +} + +static void __mapzen_reverse_geocode_cb(mapzen_error_e result, int request_id, mapzen_address_resp_s *address, void *user_data) +{ + MAPS_LOGD("Got REV GEOCODE callback from ENGINE"); + callback_info_reverse_geocode *calldata_reverse_geocode = (callback_info_reverse_geocode *) user_data; + if (result != MAPZEN_ERROR_NONE || address == NULL) { + calldata_reverse_geocode->callback((maps_error_e) __convert_to_maps_error(result), calldata_reverse_geocode->reqID, 0, 0, NULL, calldata_reverse_geocode->data); + } else { + int total_count = 1; + int index = 0; + + maps_address_h addr = NULL; + maps_address_create(&addr); + + maps_address_set_street(addr, address->street_add); + maps_address_set_city(addr, address->city); + maps_address_set_county(addr, address->county); + maps_address_set_state(addr, address->state); + maps_address_set_country(addr, address->country); + maps_address_set_country_code(addr, address->country_code); + maps_address_set_postal_code(addr, address->postal_code); + + calldata_reverse_geocode->callback(MAPS_ERROR_NONE, calldata_reverse_geocode->reqID, index, total_count, addr, calldata_reverse_geocode->data); + } +} + +EXPORT_API int maps_plugin_reverse_geocode(double latitude, double longitude, const maps_preference_h preference, maps_service_reverse_geocode_cb callback, void *user_data, int *request_id) +{ + if (!callback || !request_id) + return MAPS_ERROR_INVALID_PARAMETER; + + if (latitude > LATITUDE_RANGE || latitude < -LATITUDE_RANGE) + return MAPS_ERROR_INVALID_PARAMETER; + + if (longitude > LONGITUDE_RANGE || longitude < -LONGITUDE_RANGE) + return MAPS_ERROR_INVALID_PARAMETER; + + callback_info_reverse_geocode *calldata_reverse_geocode = (callback_info_reverse_geocode *)g_malloc0(sizeof(callback_info_reverse_geocode)); + if (calldata_reverse_geocode == NULL) + MAPS_PRINT_ERROR_CODE_RETURN(MAPS_ERROR_OUT_OF_MEMORY); + + calldata_reverse_geocode->callback = callback; + calldata_reverse_geocode->data = user_data; + + mapzen_revgeocode_req_s *reverse_geocode_req = (mapzen_revgeocode_req_s *)g_malloc0(sizeof(mapzen_revgeocode_req_s)); + if (reverse_geocode_req == NULL) { + g_free(calldata_reverse_geocode); + calldata_reverse_geocode = NULL; + MAPS_PRINT_ERROR_CODE_RETURN(MAPS_ERROR_OUT_OF_MEMORY); + } + + reverse_geocode_req->maps_key = g_strdup((gchar *) __provider_key); + reverse_geocode_req->coordinates.latitude = latitude; + reverse_geocode_req->coordinates.longitude = longitude; + + *request_id = ++__request_id; + calldata_reverse_geocode->reqID = __request_id; + + int ret = mapzen_reverse_geocode(reverse_geocode_req, __mapzen_reverse_geocode_cb, __request_id, (void *) calldata_reverse_geocode); + + return __convert_to_maps_error(ret); +} + +static void __mapzen_route_cb(mapzen_error_e result, int request_id, mapzen_route_resp_s *route_info, void *user_data) +{ + MAPS_LOGD("__mapzen_route_cb"); + callback_info_route *calldata_route = (callback_info_route *) user_data; + + if (route_info) { +/* maps_route_h route; + maps_route_create(&route); + + maps_coordinates_h top_left; + maps_coordinates_create(route_info->bounding_box.top_left.latitude, route_info->bounding_box.top_left.longitude, &top_left); + + maps_coordinates_h bottom_right; + maps_coordinates_create(route_info->bounding_box.bottom_right.latitude, route_info->bounding_box.bottom_right.longitude, &bottom_right); + + maps_area_h bounds = NULL; + maps_area_create_rectangle(top_left, bottom_right, &bounds); + maps_route_set_bounding_box(route, bounds); + maps_area_destroy(bounds); + + maps_coordinates_destroy(top_left); + maps_coordinates_destroy(bottom_right); + + maps_distance_unit_e unit = MAPS_DISTANCE_UNIT_M; + + switch (route_info->distance_unit) { + case ROUTE_UNIT_M: + unit = MAPS_DISTANCE_UNIT_M; + break; + case ROUTE_UNIT_KM: + unit = MAPS_DISTANCE_UNIT_KM; + break; + case ROUTE_UNIT_FT: + unit = MAPS_DISTANCE_UNIT_FT; + break; + case ROUTE_UNIT_YD: + unit = MAPS_DISTANCE_UNIT_YD; + break; + } + + maps_route_set_distance_unit(route, unit); + maps_route_set_total_distance(route, route_info->distance); + maps_route_set_total_duration(route, (long) route_info->time); + if (route_info->type == ROUTE_TYPE_FASTEST) + maps_route_set_transport_mode(route, MAPS_ROUTE_TRANSPORT_MODE_CAR); + else if (route_info->type == ROUTE_TYPE_PEDESTRIAN) + maps_route_set_transport_mode(route, MAPS_ROUTE_TRANSPORT_MODE_PEDESTRIAN); + else if (route_info->type == ROUTE_TYPE_BICYCLE) + maps_route_set_transport_mode(route, MAPS_ROUTE_TRANSPORT_MODE_BICYCLE); + else if (route_info->type == ROUTE_TYPE_MULTIMODAL) + maps_route_set_transport_mode(route, MAPS_ROUTE_TRANSPORT_MODE_PUBLICTRANSIT); + else + maps_route_set_transport_mode(route, MAPS_ROUTE_TRANSPORT_MODE_CAR); + + maps_item_list_h segment_list = NULL; + maps_item_list_create(&segment_list); + + GList *maneuver_data = NULL; + maneuver_data = g_list_first(route_info->maneuvers); + + while (maneuver_data) { + maps_route_segment_h segment = NULL; + maps_route_segment_create(&segment); + + maps_route_maneuver_h man = NULL; + maps_route_maneuver_create(&man); + mapzen_route_maneuver *maneuver = (mapzen_route_maneuver *) maneuver_data->data; + + // Segment Origin and Destination + maps_coordinates_h segmentStartPoint; + maps_coordinates_create(maneuver->start_point.latitude, maneuver->start_point.longitude, &segmentStartPoint); + maps_route_segment_set_origin(segment, segmentStartPoint); // origin + maps_coordinates_destroy(segmentStartPoint); + + maps_coordinates_h segmentEndPoint; + maps_coordinates_create(maneuver->end_point.latitude, maneuver->end_point.longitude, &segmentEndPoint); + + MAPS_LOGD(">>> Segment start : %f, %f <<<", maneuver->start_point.latitude, maneuver->start_point.longitude); + MAPS_LOGD(">>> Segment end : %f, %f <<<", maneuver->end_point.latitude, maneuver->end_point.longitude); + + maps_route_segment_set_destination(segment, segmentEndPoint); // destination + maps_coordinates_destroy(segmentEndPoint); + + // Segment distance + maps_route_segment_set_distance(segment, maneuver->distance); + maps_route_segment_set_duration(segment, maneuver->time); + + // Maneuver distance + maps_route_maneuver_set_distance_to_next_instruction(man, maneuver->distance); + maps_route_maneuver_set_time_to_next_instruction(man, maneuver->time); + + maps_route_maneuver_set_turn_type(man, __convert_route_turn_type(maneuver->turn_type)); + + // maneuver_set_traffic_direction(man, (traffic_direction_e)action_id); + + // Maneuver Instruction + if (maneuver->instruction) + maps_route_maneuver_set_instruction_text(man, (char *) maneuver->instruction); + + // Maneuver Street Name + if (maneuver->street_name) { + MAPS_LOGD("Street Name >>>> %s", maneuver->street_name); + maps_route_maneuver_set_road_name(man, (char *) maneuver->street_name); + } else { + MAPS_LOGD("Street Name >>>> NIL"); + } + + /// Maneuver start position + maps_coordinates_h coord; + maps_coordinates_create(maneuver->start_point.latitude, maneuver->start_point.longitude, &coord); + + maps_route_maneuver_set_position(man, coord); + maps_coordinates_destroy(coord); + + maps_item_list_h maneuver_list = NULL; + maps_item_list_create(&maneuver_list); + maps_item_list_append(maneuver_list, (gpointer) man, maps_route_maneuver_clone); + maps_route_segment_set_maneuvers(segment, maneuver_list); + + maps_item_list_destroy(maneuver_list); + maps_route_maneuver_destroy(man); + + maps_item_list_append(segment_list, (gpointer) segment, maps_route_segment_clone); + maps_route_segment_destroy(segment); + + // Fetching the next item from Maneuver/Segment list + maneuver_data = g_list_next(maneuver_data); + } + maps_route_set_segments(route, segment_list); + maps_item_list_destroy(segment_list); + + // Shape points - path + maps_item_list_h path_list = NULL; + maps_item_list_create(&path_list); + + GList *shapePoints = NULL; + shapePoints = g_list_first(route_info->shapePoints); + + while (shapePoints) { + coords_s *data = (coords_s *) shapePoints->data; + + maps_coordinates_h shapeCoords; + maps_coordinates_create(data->latitude, data->longitude, &shapeCoords); + + maps_item_list_append(path_list, (gpointer) shapeCoords, maps_coordinates_clone); + + maps_coordinates_destroy(shapeCoords); + + shapePoints = g_list_next(shapePoints); + } + maps_route_set_path(route, path_list); + maps_item_list_destroy(path_list); + + bool b = calldata_route->callback((maps_error_e)__convert_to_maps_error(result), calldata_route->reqID, 0, 1, route, calldata_route->data); + if (!b) + return; + */ + } else { + calldata_route->callback((maps_error_e)__convert_to_maps_error(result), calldata_route->reqID, 0, 0, NULL, calldata_route->data); + } +} + +EXPORT_API int maps_plugin_search_route(const maps_coordinates_h origin, const maps_coordinates_h destination, maps_preference_h preference, maps_service_search_route_cb callback, void *user_data, int *request_id) +{ + if (!origin || !destination || !callback || !request_id) + return MAPS_ERROR_INVALID_PARAMETER; + + callback_info_route *calldata_route = (callback_info_route *)g_malloc0(sizeof(callback_info_route)); + if (calldata_route == NULL) + MAPS_PRINT_ERROR_CODE_RETURN(MAPS_ERROR_OUT_OF_MEMORY); + + calldata_route->callback = callback; + calldata_route->data = user_data; + + mapzen_route_req_s *route_req = (mapzen_route_req_s *)g_malloc0(sizeof(mapzen_route_req_s)); + if (route_req == NULL) { + g_free(calldata_route); + calldata_route = NULL; + MAPS_PRINT_ERROR_CODE_RETURN(MAPS_ERROR_OUT_OF_MEMORY); + } + + route_req->maps_key = g_strdup((gchar *) __provider_key); + + double origin_lat, origin_lon; + double dest_lat, dest_lon; + + maps_coordinates_get_latitude(origin, &origin_lat); + maps_coordinates_get_longitude(origin, &origin_lon); + + maps_coordinates_get_latitude(destination, &dest_lat); + maps_coordinates_get_longitude(destination, &dest_lon); + + route_req->from.latitude = origin_lat; + route_req->from.longitude = origin_lon; + + route_req->to.latitude = dest_lat; + route_req->to.longitude = dest_lon; +/* + MAPS_LOGD("getting transport mode.."); + maps_route_transport_mode_e transport_mode; + maps_preference_get_route_transport_mode(preference, &transport_mode); + + if (transport_mode == MAPS_ROUTE_TRANSPORT_MODE_CAR) + route_req->type = ROUTE_TYPE_FASTEST; + else if (transport_mode == MAPS_ROUTE_TRANSPORT_MODE_PEDESTRIAN) + route_req->type = ROUTE_TYPE_PEDESTRIAN; + else if (transport_mode == MAPS_ROUTE_TRANSPORT_MODE_BICYCLE) + route_req->type = ROUTE_TYPE_BICYCLE; + else if (transport_mode == MAPS_ROUTE_TRANSPORT_MODE_PUBLICTRANSIT) + route_req->type = ROUTE_TYPE_MULTIMODAL; + else + route_req->type = ROUTE_TYPE_FASTEST; // Keeping it as default + + route_req->driving_style = DRIVING_STYLE_NORMAL; // Keeping it as default + + // Unit + maps_distance_unit_e unit; + maps_preference_get_distance_unit(preference, &unit); + + switch (unit) { + case MAPS_DISTANCE_UNIT_M: + route_req->unit = ROUTE_UNIT_M; + break; + case MAPS_DISTANCE_UNIT_KM: + route_req->unit = ROUTE_UNIT_KM; + break; + case MAPS_DISTANCE_UNIT_FT: + route_req->unit = ROUTE_UNIT_FT; + break; + case MAPS_DISTANCE_UNIT_YD: + route_req->unit = ROUTE_UNIT_YD; + break; + } + + route_req->avoids = ROUTE_AVOID_NONE; + maps_route_feature_weight_e routeWeight; + maps_preference_get_route_feature_weight(preference, &routeWeight); + + if (routeWeight == MAPS_ROUTE_FEATURE_WEIGHT_AVOID) { + maps_route_feature_e routeFeature; + maps_preference_get_route_feature(preference, &routeFeature); + + if (routeFeature == MAPS_ROUTE_FEATURE_TOLL) + route_req->avoids = ROUTE_AVOID_TOLL_ROAD; + else if (routeFeature == MAPS_ROUTE_FEATURE_MOTORWAY) + route_req->avoids = ROUTE_AVOID_LIMITED_ACCESS; + else if ((routeFeature == MAPS_ROUTE_FEATURE_BOATFERRY) || (routeFeature == MAPS_ROUTE_FEATURE_RAILFERRY)) + route_req->avoids = ROUTE_AVOID_FERRY; + else if (routeFeature == MAPS_ROUTE_FEATURE_DIRTROAD) + route_req->avoids = ROUTE_AVOID_UNPAVED; + else + route_req->avoids = ROUTE_AVOID_NONE; + } + + route_req->way_points = NULL; + + *request_id = ++__request_id; + calldata_route->reqID = __request_id; +*/ + int ret = mapzen_start_route(route_req, __mapzen_route_cb, __request_id, (void *)calldata_route); + + return __convert_to_maps_error(ret); +} + +EXPORT_API int maps_plugin_search_route_waypoints(const maps_coordinates_h *waypoint_list, int waypoint_num, maps_preference_h preference, maps_service_search_route_cb callback, void *user_data, int *request_id) +{ + if (!waypoint_list || waypoint_num < 2 || !callback || !request_id) + return MAPS_ERROR_INVALID_PARAMETER; + + callback_info_route *calldata_route = (callback_info_route *)g_malloc0(sizeof(callback_info_route)); + if (calldata_route == NULL) + MAPS_PRINT_ERROR_CODE_RETURN(MAPS_ERROR_OUT_OF_MEMORY); + + calldata_route->callback = callback; + calldata_route->data = user_data; + + mapzen_route_req_s *route_req = (mapzen_route_req_s *)g_malloc0(sizeof(mapzen_route_req_s)); + if (route_req == NULL) { + g_free(calldata_route); + calldata_route = NULL; + MAPS_PRINT_ERROR_CODE_RETURN(MAPS_ERROR_OUT_OF_MEMORY); + } + + route_req->maps_key = g_strdup((gchar *) __provider_key); + + route_req->from.latitude = 0.0; + route_req->from.longitude = 0.0; + + route_req->to.latitude = 0.0; + route_req->to.longitude = 0.0; +/* + MAPS_LOGD("getting transport mode.."); + maps_route_transport_mode_e transport_mode; + maps_preference_get_route_transport_mode(preference, &transport_mode); + + if (transport_mode == MAPS_ROUTE_TRANSPORT_MODE_CAR) + route_req->type = ROUTE_TYPE_FASTEST; + else if (transport_mode == MAPS_ROUTE_TRANSPORT_MODE_PEDESTRIAN) + route_req->type = ROUTE_TYPE_PEDESTRIAN; + else if (transport_mode == MAPS_ROUTE_TRANSPORT_MODE_BICYCLE) + route_req->type = ROUTE_TYPE_BICYCLE; + else if (transport_mode == MAPS_ROUTE_TRANSPORT_MODE_PUBLICTRANSIT) + route_req->type = ROUTE_TYPE_MULTIMODAL; + else + route_req->type = ROUTE_TYPE_FASTEST; // Keeping it as default + + route_req->driving_style = DRIVING_STYLE_NORMAL; // Keeping it as default + + // Unit + maps_distance_unit_e unit; + maps_preference_get_distance_unit(preference, &unit); + + switch (unit) { + case MAPS_DISTANCE_UNIT_M: + route_req->unit = ROUTE_UNIT_M; + break; + case MAPS_DISTANCE_UNIT_KM: + route_req->unit = ROUTE_UNIT_KM; + break; + case MAPS_DISTANCE_UNIT_FT: + route_req->unit = ROUTE_UNIT_FT; + break; + case MAPS_DISTANCE_UNIT_YD: + route_req->unit = ROUTE_UNIT_YD; + break; + } + + route_req->avoids = ROUTE_AVOID_NONE; + maps_route_feature_weight_e routeWeight; + maps_preference_get_route_feature_weight(preference, &routeWeight); + + if (routeWeight == MAPS_ROUTE_FEATURE_WEIGHT_AVOID) { + maps_route_feature_e routeFeature; + maps_preference_get_route_feature(preference, &routeFeature); + + if (routeFeature == MAPS_ROUTE_FEATURE_TOLL) + route_req->avoids = ROUTE_AVOID_TOLL_ROAD; + else if (routeFeature == MAPS_ROUTE_FEATURE_MOTORWAY) + route_req->avoids = ROUTE_AVOID_LIMITED_ACCESS; + else if ((routeFeature == MAPS_ROUTE_FEATURE_BOATFERRY) || (routeFeature == MAPS_ROUTE_FEATURE_RAILFERRY)) + route_req->avoids = ROUTE_AVOID_FERRY; + else if (routeFeature == MAPS_ROUTE_FEATURE_DIRTROAD) + route_req->avoids = ROUTE_AVOID_UNPAVED; + else + route_req->avoids = ROUTE_AVOID_NONE; + } + + // Waypoints + route_req->way_points = NULL; + if (waypoint_num != 0) { + int index = 0; + double latitude = 0.0, longitude = 0.0; + for (index = 0; index < waypoint_num; index++) { + if (waypoint_list[index] != NULL) { + maps_coordinates_get_latitude(waypoint_list[index], &latitude); + maps_coordinates_get_longitude(waypoint_list[index], &longitude); + + coords_s *data = (coords_s *)g_malloc0(sizeof(coords_s)); + if (data) { + data->latitude = latitude; + data->longitude = longitude; + + if (route_req->way_points == NULL) + route_req->way_points = g_list_append(route_req->way_points, (gpointer) data); + else + route_req->way_points = g_list_insert_before(route_req->way_points, NULL, (gpointer) data); + } + } + } + } + + *request_id = ++__request_id; + calldata_route->reqID = __request_id; +*/ + int ret = mapzen_start_route(route_req, __mapzen_route_cb, __request_id, (void *)calldata_route); + + return __convert_to_maps_error(ret); +} + +static void __mapzen_place_search_cb(mapzen_error_e result, int request_id, GList *places, void *user_data) +{ + MAPS_LOGD("Got places result from ENGINE..."); + + callback_info_place *calldata_place = (callback_info_place *) user_data; + + if (result != MAPZEN_ERROR_NONE || places == NULL) { + MAPS_LOGD("Got places result from ENGINE...result is NULL"); + calldata_place->callback((maps_error_e) __convert_to_maps_error(result), calldata_place->reqID, 0, 0, NULL, calldata_place->data); + } else { + guint total_count = 0; + int index = 0; + total_count = g_list_length(places); + if (total_count > 0) { + maps_place_h place = NULL; + MAPS_LOGD("Got places result from ENGINE... count -> %d", total_count); + + GList *temp_place = NULL; + temp_place = g_list_first(places); + + while (temp_place) { + maps_place_create(&place); + mapzen_place_resp_s *mapzen_place = (mapzen_place_resp_s *) temp_place->data; + maps_place_set_id(place, mapzen_place->place_id); + maps_place_set_name(place, mapzen_place->display_name); + + MAPS_LOGD("Before address.."); + /* Address */ + if (mapzen_place->address) { + maps_address_h addr = NULL; + maps_address_create(&addr); + + maps_address_set_street(addr, mapzen_place->address->street_add); + maps_address_set_building_number(addr, mapzen_place->address->building_number); + maps_address_set_city(addr, mapzen_place->address->city); + maps_address_set_county(addr, mapzen_place->address->county); + maps_address_set_state(addr, mapzen_place->address->state); + maps_address_set_country(addr, mapzen_place->address->country); + maps_address_set_country_code(addr, mapzen_place->address->country_code); + maps_address_set_postal_code(addr, mapzen_place->address->postal_code); + maps_address_set_freetext(addr, mapzen_place->display_name); + + maps_place_set_address(place, addr); + maps_address_destroy(addr); + } else { + maps_place_set_address(place, NULL); + } + + maps_coordinates_h coord; + maps_coordinates_create(mapzen_place->coordinates.latitude, mapzen_place->coordinates.longitude, &coord); + + maps_place_set_location(place, coord); + maps_coordinates_destroy(coord); + + maps_place_category_h place_cat; + maps_place_category_create(&place_cat); + maps_place_category_set_name(place_cat, mapzen_place->category); + + maps_item_list_h cat_list; + maps_item_list_create(&cat_list); + maps_item_list_append(cat_list, (void *) place_cat, maps_place_category_clone); + maps_place_set_categories(place, cat_list); + + maps_place_category_destroy(place_cat); + maps_item_list_destroy(cat_list); + + maps_place_image_h place_image; + maps_place_image_create(&place_image); + maps_place_image_set_url(place_image, mapzen_place->icon_url); + maps_item_list_h image_list; + maps_item_list_create(&image_list); + maps_item_list_append(image_list, (void *) place_image, maps_place_image_clone); + maps_place_set_images(place, image_list); + + maps_place_image_destroy(place_image); + maps_item_list_destroy(image_list); + + bool b = calldata_place->callback((maps_error_e)__convert_to_maps_error(result), calldata_place->reqID, index, total_count, place, calldata_place->data); + if (!b) + return; + + index++; + + temp_place = temp_place->next; + } + } else { + calldata_place->callback((maps_error_e)__convert_to_maps_error(result), calldata_place->reqID, index, total_count, NULL, calldata_place->data); + } + } +} + +EXPORT_API int maps_plugin_search_place(const maps_coordinates_h position, int distance, const maps_place_filter_h filter, const maps_preference_h preference, maps_service_search_place_cb callback, void *user_data, int *request_id) +{ + if (!position || !filter || !callback || !request_id) + return MAPS_ERROR_INVALID_PARAMETER; + if (distance <= 0) + return MAPS_ERROR_INVALID_PARAMETER; + + callback_info_place *calldata_place = (callback_info_place *)g_malloc0(sizeof(callback_info_place)); + if (calldata_place == NULL) + MAPS_PRINT_ERROR_CODE_RETURN(MAPS_ERROR_OUT_OF_MEMORY); + + calldata_place->callback = callback; + calldata_place->data = user_data; + + mapzen_search_req_s *place_req = (mapzen_search_req_s *)g_malloc0(sizeof(mapzen_search_req_s)); + if (place_req == NULL) { + g_free(calldata_place); + calldata_place = NULL; + MAPS_PRINT_ERROR_CODE_RETURN(MAPS_ERROR_OUT_OF_MEMORY); + } + + place_req->maps_key = g_strdup((gchar *) __provider_key); + + int max_result; + maps_preference_get_max_results(preference, &max_result); + + if (max_result == 0) + place_req->num_res = DEFAULT_NUM_RESULTS; + else + place_req->num_res = max_result; + + MAPS_LOGD("Place Result limit :: %d", place_req->num_res); + + char *categoryName = NULL; + char *place_name = NULL; + + maps_place_category_h category = NULL; + maps_place_filter_get_category(filter, &category); + + if (category) + maps_place_category_get_name(category, &categoryName); + + maps_place_filter_get_place_name(filter, &place_name); + + char *modified_place_name = NULL; + bool b_isPlaceName_modified = false; + if (place_name) + b_isPlaceName_modified = __replace_space(place_name, &modified_place_name); + + MAPS_LOGD("Modified Place String.. "); + MAPS_LOGD(" >>>> %s", modified_place_name); + + if (categoryName && place_name) { + if (b_isPlaceName_modified) + place_req->search_string = g_strdup_printf("%s[%s]", modified_place_name, categoryName); + else + place_req->search_string = g_strdup_printf("%s[%s]", place_name, categoryName); + } else if (categoryName) { + place_req->search_string = g_strdup_printf("[%s]", categoryName); + } else if (place_name) { + if (b_isPlaceName_modified) + place_req->search_string = g_strdup_printf("%s", modified_place_name); + else + place_req->search_string = g_strdup_printf("%s", place_name); + } else { + g_free(calldata_place); + calldata_place = NULL; + g_free(place_req); + place_req = NULL; + return MAPS_ERROR_INVALID_PARAMETER; + } + + if (modified_place_name) { + g_free(modified_place_name); + modified_place_name = NULL; + } + + MAPS_LOGD(">>>>>>>> Place search string :: %s <<<<<<<<<", place_req->search_string); + + place_req->boundary = NULL; + place_req->boundary = (mapzen_boundary_s *)g_malloc0(sizeof(mapzen_boundary_s)); + + if (place_req->boundary) { + place_req->boundary->type = MAPZEN_BOUNDARY_CIRCLE; + double lat, lon; + maps_coordinates_get_latitude(position, &lat); + maps_coordinates_get_longitude(position, &lon); + place_req->boundary->circle.center.latitude = lat; + place_req->boundary->circle.center.longitude = lon; + place_req->boundary->circle.radius = distance; + } + + *request_id = ++__request_id; + calldata_place->reqID = __request_id; + + int ret = mapzen_search_place(place_req, __mapzen_place_search_cb, __request_id, (void *) calldata_place); + + return __convert_to_maps_error(ret); +} + +EXPORT_API int maps_plugin_search_place_by_area(const maps_area_h boundary, const maps_place_filter_h filter, const maps_preference_h preference, maps_service_search_place_cb callback, void *user_data, int *request_id) +{ + if (!boundary || !filter || !callback || !request_id) + return MAPS_ERROR_INVALID_PARAMETER; + + callback_info_place *calldata_place = (callback_info_place *)g_malloc0(sizeof(callback_info_place)); + if (calldata_place == NULL) + MAPS_PRINT_ERROR_CODE_RETURN(MAPS_ERROR_OUT_OF_MEMORY); + + calldata_place->callback = callback; + calldata_place->data = user_data; + + mapzen_search_req_s *place_req = (mapzen_search_req_s *)g_malloc0(sizeof(mapzen_search_req_s)); + if (place_req == NULL) { + g_free(calldata_place); + calldata_place = NULL; + MAPS_PRINT_ERROR_CODE_RETURN(MAPS_ERROR_OUT_OF_MEMORY); + } + + place_req->maps_key = g_strdup((gchar *) __provider_key); + + int max_result; + maps_preference_get_max_results(preference, &max_result); + + if (max_result == 0) + place_req->num_res = DEFAULT_NUM_RESULTS; + else + place_req->num_res = max_result; + + MAPS_LOGD("Place Result limit :: %d", place_req->num_res); + + char *categoryName = NULL; + char *place_name = NULL; + + maps_place_category_h category = NULL; + maps_place_filter_get_category(filter, &category); + + if (category) + maps_place_category_get_name(category, &categoryName); + + maps_place_filter_get_place_name(filter, &place_name); + + char *modified_place_name = NULL; + bool b_isPlaceName_modified = false; + if (place_name) + b_isPlaceName_modified = __replace_space(place_name, &modified_place_name); + + if (categoryName && place_name) { + if (b_isPlaceName_modified) + place_req->search_string = g_strdup_printf("%s[%s]", modified_place_name, categoryName); + else + place_req->search_string = g_strdup_printf("%s[%s]", place_name, categoryName); + } else if (categoryName) { + place_req->search_string = g_strdup_printf("[%s]", categoryName); + } else if (place_name) { + if (b_isPlaceName_modified) + place_req->search_string = g_strdup_printf("%s", modified_place_name); + else + place_req->search_string = g_strdup_printf("%s", place_name); + } else { + g_free(calldata_place); + calldata_place = NULL; + g_free(place_req); + place_req = NULL; + return MAPS_ERROR_INVALID_PARAMETER; + } + + if (modified_place_name) { + g_free(modified_place_name); + modified_place_name = NULL; + } + + MAPS_LOGD(">>>>>>>> Place search string :: %s <<<<<<<<<", place_req->search_string); + place_req->boundary = NULL; + maps_area_s *bound = (maps_area_s *) boundary; + + if (bound->type != MAPS_AREA_NONE) { + place_req->boundary = (mapzen_boundary_s *)g_malloc0(sizeof(mapzen_boundary_s)); + + if (place_req->boundary != NULL) { + if (bound->type == MAPS_AREA_CIRCLE) { + place_req->boundary->type = MAPZEN_BOUNDARY_CIRCLE; + place_req->boundary->circle.center.latitude = bound->circle.center.latitude; + place_req->boundary->circle.center.longitude = bound->circle.center.longitude; + place_req->boundary->circle.radius = bound->circle.radius; + } else if (bound->type == MAPS_AREA_RECTANGLE) { + place_req->boundary->type = MAPZEN_BOUNDARY_RECT; + place_req->boundary->rect.top_left.latitude = bound->rect.top_left.latitude; + place_req->boundary->rect.top_left.longitude = bound->rect.top_left.longitude; + place_req->boundary->rect.bottom_right.latitude = bound->rect.bottom_right.latitude; + place_req->boundary->rect.bottom_right.longitude = bound->rect.bottom_right.longitude; + } + } + } + + *request_id = ++__request_id; + calldata_place->reqID = __request_id; + + int ret = mapzen_search_place(place_req, __mapzen_place_search_cb, __request_id, (void *) calldata_place); + + return __convert_to_maps_error(ret); +} + +EXPORT_API int maps_plugin_search_place_by_address(const char *address, const maps_area_h boundary, const maps_place_filter_h filter, const maps_preference_h preference, maps_service_search_place_cb callback, void *user_data, int *request_id) +{ + if (!address || !boundary || !filter || !callback || !request_id) + return MAPS_ERROR_INVALID_PARAMETER; + + callback_info_place *calldata_place = (callback_info_place *)g_malloc0(sizeof(callback_info_place)); + if (calldata_place == NULL) + MAPS_PRINT_ERROR_CODE_RETURN(MAPS_ERROR_OUT_OF_MEMORY); + + calldata_place->callback = callback; + calldata_place->data = user_data; + + mapzen_search_req_s *place_req = (mapzen_search_req_s *)g_malloc0(sizeof(mapzen_search_req_s)); + if (place_req == NULL) { + g_free(calldata_place); + calldata_place = NULL; + MAPS_PRINT_ERROR_CODE_RETURN(MAPS_ERROR_OUT_OF_MEMORY); + } + + place_req->maps_key = g_strdup((gchar *) __provider_key); + + int max_result; + maps_preference_get_max_results(preference, &max_result); + + if (max_result == 0) + place_req->num_res = DEFAULT_NUM_RESULTS; + else + place_req->num_res = max_result; + + MAPS_LOGD("Place Result limit :: %d", place_req->num_res); + + char *categoryName = NULL; + + maps_place_category_h category = NULL; + maps_place_filter_get_category(filter, &category); + + if (category) + maps_place_category_get_name(category, &categoryName); + + char *modified_address = NULL; + bool b_isAddress_modified = false; + if (address) + b_isAddress_modified = __replace_space((char *) address, &modified_address); + + if (categoryName) { + if (b_isAddress_modified) + place_req->search_string = g_strdup_printf("%s[%s]", modified_address, categoryName); + else + place_req->search_string = g_strdup_printf("%s[%s]", address, categoryName); + } else { + if (b_isAddress_modified) + place_req->search_string = g_strdup_printf("%s", modified_address); + else + place_req->search_string = g_strdup_printf("%s", address); + } + + if (modified_address) { + g_free(modified_address); + modified_address = NULL; + } + + place_req->boundary = NULL; + maps_area_s *bound = (maps_area_s *) boundary; + + if (bound->type != MAPS_AREA_NONE) { + place_req->boundary = (mapzen_boundary_s *)g_malloc0(sizeof(mapzen_boundary_s)); + + if (place_req->boundary != NULL) { + if (bound->type == MAPS_AREA_CIRCLE) { + place_req->boundary->type = MAPZEN_BOUNDARY_CIRCLE; + place_req->boundary->circle.center.latitude = bound->circle.center.latitude; + place_req->boundary->circle.center.longitude = bound->circle.center.longitude; + place_req->boundary->circle.radius = bound->circle.radius; + } else if (bound->type == MAPS_AREA_RECTANGLE) { + place_req->boundary->type = MAPZEN_BOUNDARY_RECT; + place_req->boundary->rect.top_left.latitude = bound->rect.top_left.latitude; + place_req->boundary->rect.top_left.longitude = bound->rect.top_left.longitude; + place_req->boundary->rect.bottom_right.latitude = bound->rect.bottom_right.latitude; + place_req->boundary->rect.bottom_right.longitude = bound->rect.bottom_right.longitude; + } + } + } + + *request_id = ++__request_id; + calldata_place->reqID = __request_id; + + int ret = mapzen_search_place(place_req, __mapzen_place_search_cb, __request_id, (void *) calldata_place); + + return __convert_to_maps_error(ret); +} + +EXPORT_API int maps_plugin_cancel_request(int request_id) +{ + MAPS_LOGD("Plugin_Cancel_Request..."); + if (request_id < 0) + return MAPS_ERROR_INVALID_PARAMETER; + + int ret = mapzen_cancel_request(request_id); + + return __convert_to_maps_error(ret); +} diff --git a/src/mapzen_plugin.cpp b/src/mapzen_plugin.cpp deleted file mode 100644 index 214ab49..0000000 --- a/src/mapzen_plugin.cpp +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include -#include "mapzen_utils.h" - -extern "C" -{ - -EXPORT_API int maps_plugin_init(maps_plugin_h *plugin) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_init_module(maps_plugin_h *plugin, const char *module) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_shutdown(maps_plugin_h plugin) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_get_info(maps_plugin_info_h* info) -{ - int ret = maps_plugin_info_create(info); - - if (ret == MAPS_ERROR_NONE) - ret = maps_plugin_info_set_provider_name(*info, "mapzen"); - - return ret; -} - -EXPORT_API int maps_plugin_set_provider_key(const char* provider_key) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_get_provider_key(char** provider_key) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_set_preference(maps_preference_h preference) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_get_preference(maps_preference_h* preference) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_is_service_supported(maps_service_e service, bool *supported) -{ - return MAPS_ERROR_NONE; -} -EXPORT_API int maps_plugin_is_data_supported(maps_service_data_e service, bool *supported) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_geocode(const char* address, const maps_preference_h preference, - maps_service_geocode_cb callback, void *user_data, int* request_id) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_geocode_inside_area(const char* address, const maps_area_h bounds, - const maps_preference_h preference, maps_service_geocode_cb callback, - void* user_data, int* request_id) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_geocode_by_structured_address(const maps_address_h address, - const maps_preference_h preference, maps_service_geocode_cb callback, - void *user_data, int* request_id) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_reverse_geocode(double latitude, double longitude, - const maps_preference_h preference, maps_service_reverse_geocode_cb callback, - void *user_data, int* request_id) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_multi_reverse_geocode(const maps_coordinates_list_h geocode_list, - const maps_preference_h preference, maps_service_multi_reverse_geocode_cb callback, - void *user_data, int *request_id) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_search_place(const maps_coordinates_h position, int distance, - const maps_place_filter_h filter, maps_preference_h preference, maps_service_search_place_cb callback, - void* user_data, int* request_id) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_search_place_by_area(const maps_area_h boundary, - const maps_place_filter_h filter, maps_preference_h preference, maps_service_search_place_cb callback, - void* user_data, int* request_id) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_search_place_by_address(const char* address, const maps_area_h boundary, - const maps_place_filter_h filter, maps_preference_h preference, maps_service_search_place_cb callback, - void* user_data, int* request_id) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_search_place_list(const maps_area_h boundary, const maps_place_filter_h filter, - maps_preference_h preference, maps_service_search_place_list_cb callback, void* user_data, int* request_id) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_get_place_details(const char* url, - maps_service_get_place_details_cb callback, void* user_data, int* request_id) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_search_route(const maps_coordinates_h origin, const maps_coordinates_h destination, - maps_preference_h preference, maps_service_search_route_cb callback, void* user_data, int* request_id) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_search_route_waypoints(const maps_coordinates_h* waypoint_list, int waypoint_num, - maps_preference_h preference, maps_service_search_route_cb callback, - void* user_data, int* request_id) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_cancel_request(int request_id) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_create_map_view(maps_view_h hView, maps_plugin_map_view_ready_cb pCbFunc) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_destroy_map_view(maps_view_h hView) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_render_map(maps_view_h hView, - const maps_coordinates_h coordinates, double zoom_factor, double rotation_angle, - maps_plugin_render_map_cb callback, void* user_data, int* request_id) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_render_map_area(maps_view_h hView, const maps_area_h area, - double zoom_factor, double rotation_angle, - maps_plugin_render_map_cb callback, void* user_data, int* request_id) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_move_center(maps_view_h hView, int delta_x, int delta_y, - maps_plugin_render_map_cb callback, void* user_data, int* request_id) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_set_scalebar(maps_view_h hView, bool enable) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_get_scalebar(maps_view_h hView, bool *enabled) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_draw_map(maps_view_h hView, Evas* canvas, int x, int y, int w, int h) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_get_center(maps_view_h hView, maps_coordinates_h *center) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_screen_to_geography(maps_view_h hView, int x, int y, maps_coordinates_h *mapsCoord) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_geography_to_screen(maps_view_h hView, const maps_coordinates_h mapsCoord, int* x, int* y) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_get_min_zoom_level(maps_view_h hView, int *min_zoom_level) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_get_max_zoom_level(maps_view_h hView, int *max_zoom_level) -{ - return MAPS_ERROR_NONE; -} - -EXPORT_API int maps_plugin_on_object(maps_view_h hView, const maps_view_object_h object, maps_view_object_operation_e operation) -{ - return MAPS_ERROR_NONE; -} - -} // end of extern "C" - -- 2.7.4