diff options
30 files changed, 6176 insertions, 0 deletions
diff --git a/.project b/.project new file mode 100644 index 0000000..b667714 --- /dev/null +++ b/.project @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>Mapquest</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name> + <triggers>clean,full,incremental,</triggers> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name> + <triggers>full,incremental,</triggers> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.tizen.nativecore.apichecker.core.builder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.cdt.core.cnature</nature> + <nature>org.eclipse.cdt.core.ccnature</nature> + <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature> + <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature> + <nature>org.tizen.nativecore.apichecker.core.tizenCppNature</nature> + </natures> +</projectDescription> diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..9263e8e --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,117 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +SET(fw_name "maps-plugin-mapquest") +PROJECT(${fw_name} C CXX) + +SET(CMAKE_INSTALL_PREFIX /usr) +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) + +# Dependencies +SET(dependents "glib-2.0 gmodule-2.0 dlog libcurl capi-network-connection json-glib-1.0 capi-maps-service") + +INCLUDE(FindPkgConfig) +pkg_check_modules(pkgs REQUIRED ${dependents}) +FOREACH(flag ${pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") + SET(EXTRA_CXXFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + + +# Build +SET(CMAKE_INSTALL_PREFIX /usr) +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fvisibility=hidden -fPIC -Wall -Werror") +SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpie ${EXTRA_CFLAGS} -Wall -g -fPIC -std=c++0x -fvisibility=hidden") + +IF("${ARCH}" STREQUAL "arm") + ADD_DEFINITIONS("-DTARGET") +ENDIF("${ARCH}" STREQUAL "arm") + +ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"") +ADD_DEFINITIONS("-DEXPORT_API=__attribute__((visibility(\"default\")))") +ADD_DEFINITIONS("-DTIZEN_DEBUG") + +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=/usr/lib") + + +# Include files +# Maps Service Includes +SET(INC_DIR + include +) + +# Maps Service Implementation +SET(INTERNAL_INC_DIR + src +) + +# Mapquest Engine Implementation +SET(ENGINE_INC_DIR + src/mapquest +) +INCLUDE_DIRECTORIES( +${INC_DIR} ${INTERNAL_INC_DIR} ${ENGINE_INC_DIR} +) + +#This file must be corrected + +# Source Lists +SET(SRCS + # Maps API + src/mapquest_plugin.c + + # Mapquest Engine + src/mapquest/mapquest_api.c + src/mapquest/mapquest_geocode.c + src/mapquest/mapquest_revgeocode.c + src/mapquest/mapquest_route.c + src/mapquest/mapquest_place.c + src/mapquest/mapquest_restcurl.c + src/mapquest/mapquest_jsonparser.c + src/mapquest/mapquest_queue.c + src/mapquest/mapquest_util.c +) + +ADD_LIBRARY(${fw_name} SHARED ${SRCS}) + +SET_TARGET_PROPERTIES(${fw_name} + PROPERTIES + VERSION ${FULLVER} + SOVERSION ${MAJORVER} + CLEAN_DIRECT_OUTPUT 1 +) + +TARGET_LINK_LIBRARIES(${fw_name} ${pkgs_LDFLAGS}) + +SET(PC_NAME ${fw_name}) +SET(PC_DESCRIPTION "Tizen mpaquest plugin Library") +SET(PC_LDFLAGS -l${fw_name}) +SET(PC_INCLUDE /usr/include/maps) + +CONFIGURE_FILE( + ${fw_name}.pc.in + ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc + @ONLY +) + +# Install +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc DESTINATION lib/pkgconfig) +INSTALL(TARGETS ${fw_name} DESTINATION lib/maps/plugins) + +#INCLUDE(FindPkgConfig) +#pkg_check_modules(lib_pkgs REQUIRED +# capi-maps-service +#) + +SET(LIB_APP_ASSIST capi-maps-service) +INSTALL( + DIRECTORY ${INC_DIR}/ DESTINATION include/mapquest-plugin + FILES_MATCHING + PATTERN "*_internal.h" EXCLUDE + PATTERN "${INC_DIR}/mapquest_*.h" +) + +# Test Suite +#IF("${BINTYPE}" STREQUAL "eng") +#ENDIF("${BINTYPE}" STREQUAL "eng") @@ -0,0 +1,204 @@ +Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + 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. + diff --git a/capi-maps-plugin-mapquest.manifest b/capi-maps-plugin-mapquest.manifest new file mode 100644 index 0000000..97e8c31 --- /dev/null +++ b/capi-maps-plugin-mapquest.manifest @@ -0,0 +1,5 @@ +<manifest> + <request> + <domain name="_"/> + </request> +</manifest> diff --git a/include/mapquest_plugin.h b/include/mapquest_plugin.h new file mode 100644 index 0000000..9c4f18c --- /dev/null +++ b/include/mapquest_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 _MAPQUEST_PLUGIN_H_ +#define _MAPQUEST_PLUGIN_H_ + +#include <maps_plugin.h> +#include <glib.h> + +#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 /* _MAPQUEST_PLUGIN_H_ */ diff --git a/include/mapquest_plugin_internal.h b/include/mapquest_plugin_internal.h new file mode 100644 index 0000000..c9f1fa9 --- /dev/null +++ b/include/mapquest_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 __MAPQUEST_PLUGIN_INTERNAL_H__ +#define __MAPQUEST_PLUGIN_INTERNAL_H__ + +#include <dlog.h> + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "MAPQUEST_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 /* __MAPQUEST_PLUGIN_INTERNAL_H__ */ diff --git a/maps-plugin-mapquest.pc.in b/maps-plugin-mapquest.pc.in new file mode 100644 index 0000000..599cd78 --- /dev/null +++ b/maps-plugin-mapquest.pc.in @@ -0,0 +1,14 @@ +#Package Information for pkg-config + +prefix=@PREFIX@ +exec_prefix=/usr +libdir=/usr/lib +includedir=@PC_INCLUDE@ + +Name: @PC_NAME@ +Description: @PC_DESCRIPTION@ +Version: @VERSION@ +Requires: @PC_REQUIRED@ +Libs: -L${libdir} @PC_LDFLAGS@ +Cflags: -I${includedir} + diff --git a/packaging/maps-plugin-mapquest.spec b/packaging/maps-plugin-mapquest.spec new file mode 100644 index 0000000..fafafe9 --- /dev/null +++ b/packaging/maps-plugin-mapquest.spec @@ -0,0 +1,95 @@ +Name: maps-plugin-mapquest +Summary: Tizen MapQuest Maps Plug-in Library +Version: 0.0.3 +Release: 1 +Group: Location/Libraries +License: Apache-2.0 +Source0: %{name}-%{version}.tar.gz + +#Requires(post): eglibc +#Requires(postun): eglibc + +BuildRequires: cmake +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(gmodule-2.0) +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(libcurl) +BuildRequires: pkgconfig(capi-network-connection) +BuildRequires: pkgconfig(capi-maps-service) +BuildRequires: capi-maps-service-plugin-devel +BuildRequires: pkgconfig(json-glib-1.0) +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%ifarch %{arm} +%define ARCH arm +%else +%define ARCH i586 +%endif + +%description +This packages provides Plugin APIs capsulating MapQuest Maps Open APIs for Maps Service Library. + +%prep +%setup -q + +%build +%if 0%{?tizen_build_binary_release_type_eng} +export CFLAGS="$CFLAGS -DTIZEN_ENGINEER_MODE -g" +export CXXFLAGS="$CXXFLAGS -DTIZEN_ENGINEER_MODE -g" +export FFLAGS="$FFLAGS -DTIZEN_ENGINEER_MODE" +%endif + +MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'` +cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} -DMAJORVER=${MAJORVER} -DFULLVER=%{version} +make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} +%make_install + +mkdir -p %{buildroot}/usr/share/license +cp LICENSE %{buildroot}/usr/share/license/%{name} + +%post +/sbin/ldconfig + +%postun +/sbin/ldconfig + +%files +%manifest capi-maps-plugin-mapquest.manifest +%defattr(-,root,root,-) +%{_libdir}/maps/plugins/libmaps-plugin-mapquest.so +%{_libdir}/maps/plugins/libmaps-plugin-mapquest.so.* +%{_libdir}/pkgconfig/maps-plugin-mapquest.pc +/usr/share/license/maps-plugin-mapquest + +%package devel +Summary: Tizen MapsQuest Maps Plug-in Library (Development) +Group: Framework/maps +Requires: %{name} = %{version}-%{release} + +%description devel +This packages provides Plugin APIs capsulating MapQuest Maps Open APIs for Maps Service Library. (Development) + +%post devel +/sbin/ldconfig + +%postun devel +/sbin/ldconfig + +%files devel +%defattr(-,root,root,-) +%{_includedir}/mapquest-plugin/*.h +%{_libdir}/pkgconfig/maps-plugin-mapquest.pc +%{_libdir}/maps/plugins/libmaps-plugin-mapquest.so + +%package test +Summary: Tizen MapQuest Maps Plug-in Library (Internal Dev) +Group: Framework/maps +Requires: capi-maps-service = %{version}-%{release} + +%description test +This packages provides Plugin APIs capsulating MapQuest Maps Open APIs for Maps Service Library. (Internal Dev) + diff --git a/src/mapquest/mapquest_api.c b/src/mapquest/mapquest_api.c new file mode 100644 index 0000000..88f1da9 --- /dev/null +++ b/src/mapquest/mapquest_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 <stdio.h> +#include <stdlib.h> +#include "mapquest_api.h" +#include "mapquest_server_private.h" +#include "mapquest_queue.h" +#include "mapquest_debug.h" + +EXPORT_API int mapquest_init() +{ + int ret = mapquest_init_queue(); + + return ret; +} + +EXPORT_API int mapquest_shutdown() +{ + int ret = mapquest_deinit_queue(); + + return ret; +} + +EXPORT_API int mapquest_geocode(mapquest_geocode_req_s *req_details, mapquest_geocode_cb callback, int request_id, void *user_data) +{ + int ret = MAPQUEST_ERROR_NONE; + ret = start_geocode_service(req_details, callback, request_id, user_data); + + return ret; +} + +EXPORT_API int mapquest_cancel_request(int request_id) +{ + int ret = remove_from_request_list(request_id); + + return ret; +} + +EXPORT_API int mapquest_reverse_geocode(mapquest_revgeocode_req_s *req_details, mapquest_reverse_geocode_cb callback, int request_id, void *user_data) +{ + int ret = MAPQUEST_ERROR_NONE; + ret = start_reversegeocode_service(req_details, callback, request_id, user_data); + + return ret; +} + +EXPORT_API int mapquest_search_place(mapquest_search_req_s *req_details, mapquest_place_search_cb callback, int request_id, void *user_data) +{ + int ret = MAPQUEST_ERROR_NONE; + ret = start_places_service(req_details, callback, request_id, user_data); + + return ret; +} + +EXPORT_API int mapquest_start_route(mapquest_route_req_s *req_details, mapquest_route_cb callback, int request_id, void *user_data) +{ + int ret = MAPQUEST_ERROR_NONE; + ret = start_route_service(req_details, callback, request_id, user_data); + + return ret; +} diff --git a/src/mapquest/mapquest_api.h b/src/mapquest/mapquest_api.h new file mode 100644 index 0000000..479e306 --- /dev/null +++ b/src/mapquest/mapquest_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 _MAPQUEST_API_H_ +#define _MAPQUEST_API_H_ + +#include "mapquest_types.h" +#include <tizen_type.h> + +/** + * @ingroup MAPQUEST_ENGINE_MODULE + * @defgroup MAPQUEST_ENGINE_API_MODULE + * + * @file mapquest_api.h + * @brief This file contains the MapQuest engine API's that should be called by the plugin + * + * @addtogroup MAPQUEST_ENGINE_MODULE + * @{ + * @brief This provides APIs related to MapQuest engine. + */ + +#ifdef __cplusplus +extern "C" { +#endif + + /* Callbacks */ +typedef void (*mapquest_geocode_cb) (mapquest_error_e result, int request_id, GList *co_ordinates, void *user_data); + +typedef void (*mapquest_reverse_geocode_cb) (mapquest_error_e result, int request_id, mapquest_address_resp_s *address, void *user_data); + +typedef void (*mapquest_place_search_cb) (mapquest_error_e result, int request_id, GList *places, void *user_data); + +typedef void (*mapquest_route_cb) (mapquest_error_e result, int request_id, mapquest_route_resp_s *route_info, void *user_data); + +typedef void (*mapquest_maptile_cb) (mapquest_error_e result, int request_id, char *buffer, void *user_data); + +int mapquest_init(); + +int mapquest_shutdown(); + +int mapquest_geocode(mapquest_geocode_req_s *req_details, mapquest_geocode_cb callback, int request_id, void *user_data); + +int mapquest_cancel_request(int request_id); + +int mapquest_reverse_geocode(mapquest_revgeocode_req_s *req_details, mapquest_reverse_geocode_cb callback, int request_id, void *user_data); + +int mapquest_search_place(mapquest_search_req_s *req_details, mapquest_place_search_cb callback, int request_id, void *user_data); + +int mapquest_start_route(mapquest_route_req_s *req_details, mapquest_route_cb callback, int request_id, void *user_data); + +#ifdef __cplusplus +} +#endif + +#endif /* _MAPQUEST_API_H_ */ diff --git a/src/mapquest/mapquest_debug.h b/src/mapquest/mapquest_debug.h new file mode 100644 index 0000000..8bdec35 --- /dev/null +++ b/src/mapquest/mapquest_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 _MAPQUEST_DEBUG_H_ +#define _MAPQUEST_DEBUG_H_ + +#include <dlog.h> +#include <string.h> +#include <assert.h> + +#ifdef LOG_TAG +#undef LOG_TAG +#endif + +#define EXPORT_API __attribute__((visibility("default"))) + +#define LOG_TAG "MAPQUEST_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 /* _MAPQUEST_DEBUG_H_ */ diff --git a/src/mapquest/mapquest_geocode.c b/src/mapquest/mapquest_geocode.c new file mode 100644 index 0000000..553dce2 --- /dev/null +++ b/src/mapquest/mapquest_geocode.c @@ -0,0 +1,77 @@ +/* + * 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 <stdio.h> +#include <glib.h> +#include <pthread.h> +#include "mapquest_geocode.h" +#include "mapquest_types.h" +#include "mapquest_server_private.h" +#include "mapquest_debug.h" +#include "mapquest_queue.h" +#include "mapquest_restcurl.h" + +#define GEOCODE_URL "https://open.mapquestapi.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/mapquest/mapquest_geocode.h b/src/mapquest/mapquest_geocode.h new file mode 100644 index 0000000..85c689e --- /dev/null +++ b/src/mapquest/mapquest_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 _MAPQUEST_GEOCODE_H_ +#define _MAPQUEST_GEOCODE_H_ + +#include "mapquest_api.h" +#include "mapquest_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 /* MAPQUEST_GEOCODE_H_ */ diff --git a/src/mapquest/mapquest_jsonparser.c b/src/mapquest/mapquest_jsonparser.c new file mode 100644 index 0000000..e549a5c --- /dev/null +++ b/src/mapquest/mapquest_jsonparser.c @@ -0,0 +1,1124 @@ +/* + * 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 <stdlib.h> +#include <json-glib/json-glib.h> +#include "mapquest_jsonparser.h" +#include "mapquest_queue.h" +#include "mapquest_debug.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 mapquest_error_e __convert_status(int status) +{ + mapquest_error_e error = MAPQUEST_ERROR_UNKNOWN; + switch (status) { + case 0: + { + /* Successful Geocode call */ + error = MAPQUEST_ERROR_NONE; + break; + } + case 400: + { + /* Error with input - Illegal argument from request */ + error = MAPQUEST_ERROR_INVALID_PARAMETER; + break; + } + case 403: + { + /* Key related error - Invalid key */ + error = MAPQUEST_ERROR_KEY_NOT_AVAILABLE; + break; + } + case 500: + { + /* Unknown error */ + error = MAPQUEST_ERROR_UNKNOWN; + break; + } + case -1: + { + /* Network error */ + error = MAPQUEST_ERROR_NETWORK_UNREACHABLE; + break; + } + } + + return error; +} + +/************ GEOCODE ***************/ + +static void __parse_lat_lng(JsonNode *node, GList **coordsList) +{ + if (!node || !coordsList) return; + + gdouble latitude = 0.0; + gdouble longitude = 0.0; + JsonObject *resultObj = json_node_get_object(node); + + if (resultObj) { + JsonNode *latNode = json_object_get_member(resultObj, "lat"); + + if (latNode) { + latitude = json_node_get_double(latNode); + MAP_DEBUG("Latitude :: >>> %f", latitude); + } + + JsonNode *lngNode = json_object_get_member(resultObj, "lng"); + + if (lngNode) { + longitude = json_node_get_double(lngNode); + MAP_DEBUG("Longitude :: >>> %f", longitude); + } + + coords_s *coords = (coords_s *)g_malloc0(sizeof(coords_s)); + if (coords != NULL) { + MAP_DEBUG("Storing the latitude and longitude data.."); + coords->latitude = latitude; + coords->longitude = longitude; + } + + if (*coordsList == NULL) + *coordsList = g_list_append(*coordsList, coords); + else + *coordsList = g_list_insert_before(*coordsList, NULL, coords); + } +} + +static void __parse_locations(JsonNode *node, GList **coordsList) +{ + if (!node || !coordsList) return; + + JsonArray *resultArray = json_node_get_array(node); + + int length = json_array_get_length(resultArray); + + int index = 0; + for (index = 0; index < length; index++) { + + JsonObject *obj = json_array_get_object_element(resultArray, index); + + if (obj) { + JsonNode *latLngNode = json_object_get_member(obj, "latLng"); + + if (latLngNode) + __parse_lat_lng(latLngNode, coordsList); + } + } +} + +static void __parse_geocode_response(char *response, int size, int *status, GList **coordsList) +{ + if (!response || !status || !coordsList) return; + + *coordsList = NULL; + + JsonParser *parser = NULL; + JsonNode *root = NULL; + JsonNode *node = NULL; + JsonObject *object = NULL; + GError *error = NULL; + char data[size + 1]; + + parser = json_parser_new(); + + strncpy(data, response, size); + data[size] = '\0'; + + if (!json_parser_load_from_data(parser, data, -1, &error)) { + MAP_DEBUG("Error in file parsing JSON.."); + g_error_free(error); + g_object_unref(parser); + return; + } + + root = json_parser_get_root(parser); + + object = json_node_get_object(root); + + node = json_object_get_member(object, "info"); + JsonObject *infoObj = json_node_get_object(node); + if (infoObj) { + JsonNode *statusNode = json_object_get_member(infoObj, "statuscode"); + + if (statusNode) { + *status = json_node_get_int(statusNode); + MAP_DEBUG("status :: >>> %d", *status); + } + } + + if (*status != 0) { /* SUCCESS */ + *coordsList = NULL; + return; + } + + node = json_object_get_member(object, "results"); + JsonArray *resultArray = json_node_get_array(node); + + int length = json_array_get_length(resultArray); + + int index = 0; + for (index = 0; index < length; index++) { + + JsonObject *obj = json_array_get_object_element(resultArray, index); + + if (obj) { + JsonNode *locNode = json_object_get_member(obj, "locations"); + + if (locNode) + __parse_locations(locNode, coordsList); + } + } + + g_object_unref(parser); +} + +/****************** REVERSE GEOCODE *********************/ + +static void __parse_revgeocode_address(JsonNode *node, mapquest_address_resp_s **respAddr) +{ + if (!node || !respAddr) return; + + char *streetAddr = NULL; + char *neighbourhood = NULL; + char *city = NULL; + char *county = NULL; + char *state = NULL; + char *country = NULL; + char *postalCode = NULL; + + JsonArray *resultArray = json_node_get_array(node); + + int length = json_array_get_length(resultArray); + + int index = 0; + for (index = 0; index < length; index++) { + + JsonObject *obj = json_array_get_object_element(resultArray, index); + + if (obj) { + JsonNode *tmp = NULL; + + /* Street */ + tmp = json_object_get_member(obj, "street"); + if (tmp) { + streetAddr = (char *) json_node_get_string(tmp); + if (streetAddr && strlen(streetAddr) <= 0) + streetAddr = NULL; + } else { + streetAddr = NULL; + } + + /* Neighborhood */ + tmp = json_object_get_member(obj, "adminArea6"); + if (tmp) { + neighbourhood = (char *) json_node_get_string(tmp); + if (neighbourhood && strlen(neighbourhood) <= 0) + neighbourhood = NULL; + } else { + neighbourhood = NULL; + } + + /* City */ + tmp = json_object_get_member(obj, "adminArea5"); + if (tmp) { + city = (char *) json_node_get_string(tmp); + if (city && strlen(city) <= 0) + city = NULL; + } else { + city = NULL; + } + + /* State */ + tmp = json_object_get_member(obj, "adminArea3"); + if (tmp) { + state = (char *) json_node_get_string(tmp); + if (state && strlen(state) <= 0) + state = NULL; + } else { + state = NULL; + } + + /* County */ + tmp = json_object_get_member(obj, "adminArea4"); + if (tmp) { + county = (char *) json_node_get_string(tmp); + if (county && strlen(county) <= 0) + county = NULL; + } else { + county = NULL; + } + + /* Country */ + tmp = json_object_get_member(obj, "adminArea1"); + if (tmp) { + country = (char *) json_node_get_string(tmp); + if (country && strlen(country) <= 0) + country = NULL; + } else { + country = NULL; + } + + /* Postal Code */ + tmp = json_object_get_member(obj, "postalCode"); + if (tmp) { + postalCode = (char *) json_node_get_string(tmp); + if (postalCode && strlen(postalCode) <= 0) + postalCode = NULL; + } else { + postalCode = NULL; + } + + if (!streetAddr && !neighbourhood && !city && !state && !county && !country && !postalCode) + continue; + + *respAddr = (mapquest_address_resp_s *)g_malloc(sizeof(mapquest_address_resp_s)); + + if (*respAddr != NULL) { + /* Street Address */ + if (streetAddr != NULL) { + (*respAddr)->street_add = (gchar *)g_malloc(strlen((char *)streetAddr) + 1); + strcpy((*respAddr)->street_add, (char *) streetAddr); + } else { + MAP_DEBUG("street is NULL"); + (*respAddr)->street_add = NULL; + } + + /* Neighbourhood */ + if (neighbourhood != NULL) { + (*respAddr)->neighbourhood = (gchar *)g_malloc(strlen((char *)neighbourhood) + 1); + strcpy((*respAddr)->neighbourhood, (char *) neighbourhood); + } else { + MAP_DEBUG("neighbourhood is NULL"); + (*respAddr)->neighbourhood = NULL; + } + + /* City */ + if (city != NULL) { + (*respAddr)->city = (gchar *)g_malloc(strlen((char *)city) + 1); + strcpy((*respAddr)->city, (char *) city); + } else { + MAP_DEBUG("city is NULL"); + (*respAddr)->city = NULL; + } + + /* County */ + if (county != NULL) { + (*respAddr)->county = (gchar *)g_malloc(strlen((char *)county) + 1); + strcpy((*respAddr)->county, (char *) county); + } else { + MAP_DEBUG("county is NULL"); + (*respAddr)->county = NULL; + } + + /* State */ + if (state != NULL) { + (*respAddr)->state = (gchar *)g_malloc(strlen((char *)state) + 1); + strcpy((*respAddr)->state, (char *) state); + } else { + MAP_DEBUG("state is NULL"); + (*respAddr)->state = NULL; + } + + /* Country */ + if (country != NULL) { + (*respAddr)->country = (gchar *)g_malloc(strlen((char *)country) + 1); + strcpy((*respAddr)->country, (char *) country); + } else { + MAP_DEBUG("country is NULL"); + (*respAddr)->country = NULL; + } + + /* Country code */ + MAP_DEBUG("country code is NULL"); + (*respAddr)->country_code = NULL; + + /* Postal Code */ + if (postalCode != NULL) { + (*respAddr)->postal_code = (gchar *)g_malloc(strlen((char *)postalCode) + 1); + strcpy((*respAddr)->postal_code, (char *) postalCode); + } else { + MAP_DEBUG("postal_code is NULL"); + (*respAddr)->postal_code = NULL; + } + } + } + } +} + +static void __parse_revgeocode_response(char *response, int size, int *status, mapquest_address_resp_s **respAddr) +{ + if (!response || !status || !respAddr) return; + + *respAddr = NULL; + + JsonParser *parser; + JsonNode *root; + JsonNode *node; + JsonObject *object; + GError *error = NULL; + char data[size + 1]; + + parser = json_parser_new(); + + strncpy(data, response, size); + data[size] = '\0'; + + if (!json_parser_load_from_data(parser, data, -1, &error)) { + MAP_DEBUG("Error in file parsing JSON.."); + g_error_free(error); + g_object_unref(parser); + return; + } + + root = json_parser_get_root(parser); + + object = json_node_get_object(root); + + node = json_object_get_member(object, "info"); + JsonObject *infoObj = json_node_get_object(node); + if (infoObj) { + JsonNode *statusNode = json_object_get_member(infoObj, "statuscode"); + + if (statusNode) { + *status = json_node_get_int(statusNode); + MAP_DEBUG("status :: >>> %d", *status); + } + } + + if (*status != 0) { /* SUCCESS */ + *respAddr = NULL; + return; + } + + node = json_object_get_member(object, "results"); + JsonArray *resultArray = json_node_get_array(node); + + int length = json_array_get_length(resultArray); + + int index = 0; + for (index = 0; index < length; index++) { + + JsonObject *obj = json_array_get_object_element(resultArray, index); + + if (obj) { + JsonNode *locNode = json_object_get_member(obj, "locations"); + + if (locNode) + __parse_revgeocode_address(locNode, respAddr); + } + } + + g_object_unref(parser); +} + +/**************** PLACE SEARCH ********************/ + +static void __place_address_foreach(JsonObject *object, const gchar *member_name, JsonNode *member_node, gpointer user_data) +{ + if (!object || !member_name || !member_node || !user_data) return; + + mapquest_address_resp_s **respAddr = (mapquest_address_resp_s **) user_data; + + if (*respAddr) { + JsonNode *tmp = json_object_get_member(object, member_name); + + if (!strcmp(member_name, "road")) + (*respAddr)->street_add = (char *) json_node_dup_string(tmp); + else if (!strcmp(member_name, "neighbourhood")) + (*respAddr)->neighbourhood = (char *) json_node_dup_string(tmp); + else if (!strcmp(member_name, "house_number")) + (*respAddr)->building_number = (char *) json_node_dup_string(tmp); + else if (!strcmp(member_name, "city")) + (*respAddr)->city = (char *) json_node_dup_string(tmp); + else if (!strcmp(member_name, "county")) + (*respAddr)->county = (char *) json_node_dup_string(tmp); + else if (!strcmp(member_name, "state")) + (*respAddr)->state = (char *) json_node_dup_string(tmp); + else if (!strcmp(member_name, "country")) + (*respAddr)->country = (char *) json_node_dup_string(tmp); + else if (!strcmp(member_name, "country_code")) + (*respAddr)->country_code = (char *) json_node_dup_string(tmp); + else if (!strcmp(member_name, "postcode")) + (*respAddr)->postal_code = (char *) json_node_dup_string(tmp); + } else { + *respAddr = NULL; + } +} + +static void __place_foreach(JsonObject *object, const gchar *member_name, JsonNode *member_node, gpointer user_data) +{ + if (!object || !member_name || !member_node || !user_data) return; + + mapquest_place_resp_s **respPlaces = (mapquest_place_resp_s **) user_data; + + JsonNode *tmp = json_object_get_member(object, member_name); + char *str; + + if (!strcmp(member_name, "place_id")) { + (*respPlaces)->place_id = (char *) json_node_get_string(tmp); + } else if (!strcmp(member_name, "lat")) { + str = (char *) json_node_get_string(tmp); + ((*respPlaces)->coordinates).latitude = (str ? atof(str) : 0); + } else if (!strcmp(member_name, "lon")) { + str = (char *) json_node_get_string(tmp); + ((*respPlaces)->coordinates).longitude = (str ? atof(str) : 0); + } else if (!strcmp(member_name, "class")) { + (*respPlaces)->category = (char *) json_node_dup_string(tmp); + } else if (!strcmp(member_name, "type")) { + (*respPlaces)->subcategory = (char *) json_node_dup_string(tmp); + } else if (!strcmp(member_name, "display_name")) { + (*respPlaces)->display_name = (char *) json_node_dup_string(tmp); + } else if (!strcmp(member_name, "address")) { + JsonObject *obj = json_node_get_object(member_node); + + (*respPlaces)->address = (mapquest_address_resp_s *)g_malloc(sizeof(mapquest_address_resp_s)); + if ((*respPlaces)->address) { + (*respPlaces)->address->street_add = NULL; + (*respPlaces)->address->neighbourhood = NULL; + (*respPlaces)->address->building_number = NULL; + (*respPlaces)->address->city = NULL; + (*respPlaces)->address->county = NULL; + (*respPlaces)->address->state = NULL; + (*respPlaces)->address->country = NULL; + (*respPlaces)->address->country_code = NULL; + (*respPlaces)->address->postal_code = NULL; + } + + json_object_foreach_member(obj, __place_address_foreach, &((*respPlaces)->address)); + } else if (!strcmp(member_name, "icon")) { + (*respPlaces)->icon_url = (char *) json_node_get_string(tmp); + } +} + +static void __parse_place_response(char *response, int size, GList **placeList) +{ + if (!response || !placeList) return; + + *placeList = NULL; + + JsonParser *parser; + JsonNode *root; + GError *error = NULL; + char data[size + 1]; + + parser = json_parser_new(); + if (!parser) return; + + strncpy(data, response, size); + data[size] = '\0'; + + if (!json_parser_load_from_data(parser, data, -1, &error)) { + MAP_DEBUG("Error in file parsing JSON.."); + g_error_free(error); + g_object_unref(parser); + return; + } + + root = json_parser_get_root(parser); + + JsonArray *placeArray = json_node_get_array(root); + + int length = json_array_get_length(placeArray); + MAP_DEBUG("Places result count :: %d", length); + + int index = 0; + for (index = 0; index < length; index++) { + + JsonObject *obj = json_array_get_object_element(placeArray, index); + + if (obj) { + mapquest_place_resp_s *respPlaces = (mapquest_place_resp_s *)g_malloc(sizeof(mapquest_place_resp_s)); + + if (respPlaces) { + respPlaces->place_id = NULL; + respPlaces->category = NULL; + respPlaces->subcategory = NULL; + respPlaces->display_name = NULL; + respPlaces->address = NULL; + respPlaces->icon_url = NULL; + + json_object_foreach_member(obj, __place_foreach, &respPlaces); + + if (*placeList == NULL) + *placeList = g_list_append(*placeList, respPlaces); + else + *placeList = g_list_insert_before(*placeList, NULL, respPlaces); + } + } + } + + g_object_unref(parser); +} + +/********************* ROUTE RESPONSE ***********************/ + +static double __convert_distance_unit(double distance) +{ + double val = 0.0; + switch (__route_unit) { + case ROUTE_UNIT_M: + val = ROUTE_UNIT_CONVERSION_MILE_TO_M(distance); + break; + case ROUTE_UNIT_KM: + val = ROUTE_UNIT_CONVERSION_MILE_TO_KM(distance); + break; + case ROUTE_UNIT_FT: + val = ROUTE_UNIT_CONVERSION_MILE_TO_FT(distance); + break; + case ROUTE_UNIT_YD: + val = ROUTE_UNIT_CONVERSION_MILE_TO_YD(distance); + break; + } + + return val; +} + +static void __maneuver_foreach(JsonObject *object, const gchar *member_name, JsonNode *member_node, gpointer user_data) +{ + if (!object || !member_name || !member_node || !user_data) return; + + mapquest_route_maneuver **maneuver = (mapquest_route_maneuver **) user_data; + + JsonNode *tmp = json_object_get_member(object, member_name); + + if (!strcmp(member_name, "startPoint")) { + JsonObject *coordsObj = json_node_get_object(tmp); + + if (coordsObj) { + double latitude = 0.0; + double longitude = 0.0; + JsonNode *latNode = json_object_get_member(coordsObj, "lat"); + + if (latNode) + latitude = json_node_get_double(latNode); + + JsonNode *lngNode = json_object_get_member(coordsObj, "lng"); + + if (lngNode) + longitude = json_node_get_double(lngNode); + + coords_s start_point; + start_point.latitude = latitude; + start_point.longitude = longitude; + + (*maneuver)->start_point = start_point; + } + } else if (!strcmp(member_name, "narrative")) { + (*maneuver)->instruction = (char *) json_node_dup_string(tmp); + } else if (!strcmp(member_name, "distance")) { + double dist = json_node_get_double(tmp); + (*maneuver)->distance = __convert_distance_unit(dist); + } else if (!strcmp(member_name, "time")) { + (*maneuver)->time = json_node_get_int(tmp); + } else if (!strcmp(member_name, "formattedTime")) { + (*maneuver)->formatted_time = (char *) json_node_dup_string(tmp); + } else if (!strcmp(member_name, "attributes")) { + (*maneuver)->attribute = json_node_get_int(tmp); + } else if (!strcmp(member_name, "turnType")) { + (*maneuver)->turn_type = json_node_get_int(tmp); + } else if (!strcmp(member_name, "direction")) { + (*maneuver)->direction = json_node_get_int(tmp); + } else if (!strcmp(member_name, "directionName")) { + (*maneuver)->direction_name = (char *) json_node_dup_string(tmp); + } else if (!strcmp(member_name, "index")) { + (*maneuver)->index = json_node_get_int(tmp); + } else if (!strcmp(member_name, "streets")) { + JsonArray *streetsArray = json_node_get_array(tmp); + + int length = json_array_get_length(streetsArray); + + char street_name[512]; + strcpy(street_name, ""); + int index = 0; + for (index = 0; index < length; index++) { + char *name = (char *) json_array_get_string_element(streetsArray, index); + if (name) { + if (index == 0) { + strncpy(street_name, name, sizeof(street_name)-1); + } else { + strcat(street_name, "/"); + strncat(street_name, name, sizeof(street_name)-strlen(street_name)-1); + } + } + } + + if (strlen(street_name) > 0) { + (*maneuver)->street_name = (gchar *)g_malloc0((strlen((char *)street_name)) + 1); + if ((*maneuver)->street_name) + strcpy((*maneuver)->street_name, (char *) street_name); + } else { + (*maneuver)->street_name = NULL; + } + } +} + +static void __parse_maneuvers(JsonNode *node, mapquest_route_resp_s **routeResp) +{ + if (!node || !routeResp) return; + + JsonArray *resultArray = json_node_get_array(node); + + int length = json_array_get_length(resultArray); + + int index = 0; + for (index = 0; index < length; index++) { + + JsonObject *obj = json_array_get_object_element(resultArray, index); + + if (obj) { + mapquest_route_maneuver *maneuver = (mapquest_route_maneuver *)g_malloc(sizeof(mapquest_route_maneuver)); + + if (maneuver) { + json_object_foreach_member(obj, __maneuver_foreach, &maneuver); + + if (__maneuver_index != 0) { + if (maneuver->distance == 0.0 && maneuver->time == 0) { + maneuver->start_point = __destination_point; + maneuver->end_point = __destination_point; + } else { + + } + + GList *list = NULL; + list = g_list_last((*routeResp)->maneuvers); + if (list) { + mapquest_route_maneuver *tmp = (mapquest_route_maneuver *)list->data; + tmp->end_point = maneuver->start_point; + } + } + + if ((*routeResp)->maneuvers == NULL) + (*routeResp)->maneuvers = g_list_append((*routeResp)->maneuvers, (gpointer)maneuver); + else + (*routeResp)->maneuvers = g_list_insert_before((*routeResp)->maneuvers, NULL, (gpointer)maneuver); + } + __maneuver_index++; + } + } +} + +static void __shape_foreach(JsonObject *object, const gchar *member_name, JsonNode *member_node, gpointer user_data) +{ + if (!object || !member_name || !member_node || !user_data) return; + + mapquest_route_resp_s **routeResp = (mapquest_route_resp_s **) user_data; + + JsonNode *tmp = json_object_get_member(object, member_name); + + if (!strcmp(member_name, "shapePoints")) { + JsonArray *shapePointsArray = json_node_get_array(tmp); + + int length = json_array_get_length(shapePointsArray); + + int index = 0; + double val = 0.0; + coords_s *coords = NULL; + for (index = 0; index < length; index++) { + + val = (double) json_array_get_double_element(shapePointsArray, index); + + if ((index % 2) == 0) { + /* Lat */ + coords = (coords_s *)g_malloc0(sizeof(coords_s)); + if (coords) + coords->latitude = val; + } else { + /* Lon */ + if (coords) { + coords->longitude = val; + if ((*routeResp)->shapePoints == NULL) + (*routeResp)->shapePoints = g_list_append((*routeResp)->shapePoints, (gpointer)coords); + else + (*routeResp)->shapePoints = g_list_insert_before((*routeResp)->shapePoints, NULL, (gpointer)coords); + } + } + } + } + +} + +static void __bbox_foreach(JsonObject *object, const gchar *member_name, JsonNode *member_node, gpointer user_data) +{ + if (!object || !member_name || !member_node || !user_data) return; + + mapquest_route_resp_s **routeResp = (mapquest_route_resp_s **) user_data; + + JsonNode *tmp = json_object_get_member(object, member_name); + + JsonObject *coordsObj = json_node_get_object(tmp); + double latitude = 0.0; + double longitude = 0.0; + + if (coordsObj) { + JsonNode *latNode = json_object_get_member(coordsObj, "lat"); + + if (latNode) + latitude = json_node_get_double(latNode); + + JsonNode *lngNode = json_object_get_member(coordsObj, "lng"); + + if (lngNode) + longitude = json_node_get_double(lngNode); + } + + if (!strcmp(member_name, "ul")) { + ((*routeResp)->bounding_box).top_left.latitude = latitude; + ((*routeResp)->bounding_box).top_left.longitude = longitude; + } else if (!strcmp(member_name, "lr")) { + ((*routeResp)->bounding_box).bottom_right.latitude = latitude; + ((*routeResp)->bounding_box).bottom_right.longitude = longitude; + } +} + +static void __parse_route_response(char *response, int size, int *status, mapquest_route_resp_s **routeResp) +{ + if (!response || !status || !routeResp) return; + + *routeResp = NULL; + + JsonParser *parser; + JsonNode *root; + JsonNode *node; + JsonObject *object; + GError *error = NULL; + char data[size + 1]; + + parser = json_parser_new(); + + strncpy(data, response, size); + data[size] = '\0'; + + if (!json_parser_load_from_data(parser, data, -1, &error)) { + MAP_DEBUG("Error in file parsing JSON.."); + g_error_free(error); + g_object_unref(parser); + return; + } + + root = json_parser_get_root(parser); + + object = json_node_get_object(root); + + node = json_object_get_member(object, "info"); + JsonObject *infoObj = json_node_get_object(node); + if (infoObj) { + JsonNode *statusNode = json_object_get_member(infoObj, "statuscode"); + + if (statusNode) { + *status = json_node_get_int(statusNode); + MAP_DEBUG("status :: >>> %d", *status); + } + } + + if (*status != 0) { /* SUCCESS */ + *routeResp = NULL; + return; + } + + *routeResp = (mapquest_route_resp_s *)g_malloc(sizeof(mapquest_route_resp_s)); + + if (!(*routeResp)) + return; + + (*routeResp)->maneuvers = NULL; + (*routeResp)->shapePoints = NULL; + + node = json_object_get_member(object, "route"); + + if (!node) + return; + + JsonObject *routeObject = json_node_get_object(node); + + JsonNode *tmp = json_object_get_member(routeObject, "distance"); + + if (tmp) { + double dist = json_node_get_double(tmp); + (*routeResp)->distance = __convert_distance_unit(dist); + (*routeResp)->distance_unit = __route_unit; + } + + tmp = json_object_get_member(routeObject, "boundingBox"); + + if (tmp) { + JsonObject *bbox = json_node_get_object(tmp); + + json_object_foreach_member(bbox, __bbox_foreach, routeResp); + } + + tmp = json_object_get_member(routeObject, "formattedTime"); + + if (tmp) + (*routeResp)->formatted_time = (char *) json_node_dup_string(tmp); + + tmp = json_object_get_member(routeObject, "routeType"); + if (tmp) { + (*routeResp)->type = ROUTE_TYPE_BICYCLE; + + char *type = (char *) json_node_get_string(tmp); + if (type) { + if (!strcmp(type, "FASTEST")) + (*routeResp)->type = ROUTE_TYPE_FASTEST; + else if (!strcmp(type, "SHORTEST")) + (*routeResp)->type = ROUTE_TYPE_SHORTEST; + else if (!strcmp(type, "PEDESTRIAN")) + (*routeResp)->type = ROUTE_TYPE_PEDESTRIAN; + else if (!strcmp(type, "MULTIMODAL")) + (*routeResp)->type = ROUTE_TYPE_MULTIMODAL; + } + } + + tmp = json_object_get_member(routeObject, "time"); + + if (tmp) { + int time = json_node_get_int(tmp); + (*routeResp)->time = time; + } + + tmp = json_object_get_member(routeObject, "legs"); + + if (tmp) { + JsonArray *legsArray = json_node_get_array(tmp); + + int length = json_array_get_length(legsArray); + + int index = 0; + for (index = 0; index < length; index++) { + + JsonObject *obj = json_array_get_object_element(legsArray, index); + + if (obj) { + JsonNode *maneuversNode = json_object_get_member(obj, "maneuvers"); + + if (maneuversNode) + __parse_maneuvers(maneuversNode, routeResp); + } + } + } + + tmp = json_object_get_member(routeObject, "shape"); + + if (tmp) { + JsonObject *shape = json_node_get_object(tmp); + + json_object_foreach_member(shape, __shape_foreach, routeResp); + } + + g_object_unref(parser); +} + +void post_curl_response(char *response, int size, mapquest_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; + MapquestGeocodeQueryData *queryData = (MapquestGeocodeQueryData *)user_data; + MapquestGeocodeResponseData *responseData = (MapquestGeocodeResponseData *)g_malloc(sizeof(MapquestGeocodeResponseData)); + + 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; + } + + mapquest_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; + MapquestRevGeocodeQueryData *queryData = (MapquestRevGeocodeQueryData *)user_data; + MapquestRevGeocodeResponseData *responseData = (MapquestRevGeocodeResponseData *)g_malloc(sizeof(MapquestRevGeocodeResponseData)); + + 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 */ + mapquest_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; + } + + mapquest_push_to_queue(type, (gpointer)responseData); + } + + if (queryData) { + g_free(queryData); + queryData = NULL; + } + break; + } + case RESP_TYPE_PLACES: + { + MAP_DEBUG("Inside Places JSON Parsing.."); + MapquestPlaceQueryData *queryData = (MapquestPlaceQueryData *)user_data; + MapquestPlaceResponseData *responseData = (MapquestPlaceResponseData *)g_malloc(sizeof(MapquestPlaceResponseData)); + + 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 = MAPQUEST_ERROR_NONE; + responseData->places = placeList; + } else { + /* REPSONSE PARSING FAILURE */ + MAP_DEBUG("addr Response is NULL"); + responseData->error = MAPQUEST_ERROR_UNKNOWN; + responseData->places = NULL; + } + } else { + responseData->error = MAPQUEST_ERROR_UNKNOWN; + responseData->places = NULL; + } + + mapquest_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; + MapquestRouteQueryData *queryData = (MapquestRouteQueryData *)user_data; + __route_unit = queryData->unit; + __maneuver_index = 0; + __destination_point = queryData->destination; + + MapquestRouteResponseData *responseData = (MapquestRouteResponseData *)g_malloc(sizeof(MapquestRouteResponseData)); + + 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 */ + mapquest_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; + } + + mapquest_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/mapquest/mapquest_jsonparser.h b/src/mapquest/mapquest_jsonparser.h new file mode 100644 index 0000000..19e4f1e --- /dev/null +++ b/src/mapquest/mapquest_jsonparser.h @@ -0,0 +1,24 @@ +/* + * 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 _MAPQUEST_JSONPARSER_H_ +#define _MAPQUEST_JSONPARSER_H_ + +#include "mapquest_server_private.h" + +void post_curl_response(char *response, int size, mapquest_resp_type type, void *user_data); + +#endif /* _MAPQUEST_JSONPARSER_H_ */ diff --git a/src/mapquest/mapquest_place.c b/src/mapquest/mapquest_place.c new file mode 100644 index 0000000..52a05bc --- /dev/null +++ b/src/mapquest/mapquest_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 <stdio.h> +#include <stdlib.h> +#include <glib.h> +#include <pthread.h> +#include "mapquest_place.h" +#include "mapquest_types.h" +#include "mapquest_server_private.h" +#include "mapquest_debug.h" +#include "mapquest_queue.h" +#include "mapquest_restcurl.h" +#include "mapquest_util.h" + +#define PLACES_URL "https://open.mapquestapi.com/nominatim/v1/search.php?format=json" + +int query_places(gchar *maps_key, gchar *search_str, mapquest_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 == MAPQUEST_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 == MAPQUEST_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/mapquest/mapquest_place.h b/src/mapquest/mapquest_place.h new file mode 100644 index 0000000..40812a5 --- /dev/null +++ b/src/mapquest/mapquest_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 _MAPQUEST_PLACES_H_ +#define _MAPQUEST_PLACES_H_ + +#include "mapquest_api.h" +#include "mapquest_types.h" + +int query_places(gchar *maps_key, gchar *search_str, mapquest_boundary_s *boundary, int num_res, gpointer user_data); + +#endif /* _MAPQUEST_PLACES_H_ */ diff --git a/src/mapquest/mapquest_queue.c b/src/mapquest/mapquest_queue.c new file mode 100644 index 0000000..c64ad8b --- /dev/null +++ b/src/mapquest/mapquest_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 <stdio.h> +#include<stdlib.h> +#include "mapquest_queue.h" +#include "mapquest_geocode.h" +#include "mapquest_revgeocode.h" +#include "mapquest_route.h" +#include "mapquest_place.h" +#include "mapquest_restcurl.h" +#include "mapquest_util.h" +#include "mapquest_debug.h" +#include <json-glib/json-glib.h> + +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(mapquest_geocode_req_s *req_details, mapquest_geocode_cb callback, int request_id, void *user_data) +{ + mapquest_request_s *req = (mapquest_request_s *)g_malloc0(sizeof(mapquest_request_s)); + + if (req != NULL) { + + req->type = REQ_TYPE_GEOCODE; + + mapquest_geocode_req *data = (mapquest_geocode_req *)g_malloc0(sizeof(mapquest_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 MAPQUEST_ERROR_NONE; +} + +int add_to_revgeocode_list(mapquest_revgeocode_req_s *req_details, mapquest_reverse_geocode_cb callback, int request_id, void *user_data) +{ + mapquest_request_s *req = (mapquest_request_s *)g_malloc0(sizeof(mapquest_request_s)); + + if (req != NULL) { + + req->type = REQ_TYPE_REVGEOCODE; + + mapquest_revgeocode_req *data = (mapquest_revgeocode_req *)g_malloc0(sizeof(mapquest_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 MAPQUEST_ERROR_NONE; +} + +int add_to_places_list(mapquest_search_req_s *req_details, mapquest_place_search_cb callback, int request_id, void *user_data) +{ + mapquest_request_s *req = (mapquest_request_s *)g_malloc0(sizeof(mapquest_request_s)); + + if (req != NULL) { + + req->type = REQ_TYPE_PLACES; + + mapquest_search_place_req *data = (mapquest_search_place_req *)g_malloc0(sizeof(mapquest_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 MAPQUEST_ERROR_NONE; +} + +int add_to_route_list(mapquest_route_req_s *req_details, mapquest_route_cb callback, int request_id, void *user_data) +{ + mapquest_request_s *req = (mapquest_request_s *)g_malloc0(sizeof(mapquest_request_s)); + + if (req != NULL) { + + req->type = REQ_TYPE_ROUTE; + + mapquest_route_req *data = (mapquest_route_req *)g_malloc0(sizeof(mapquest_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 MAPQUEST_ERROR_NONE; +} + +static int __add_to_cancel_list(int request_id) +{ + if (reqCancelList == NULL) + reqCancelList = g_list_append(reqCancelList, (gpointer)request_id); + else + reqCancelList = g_list_insert_before(reqCancelList, NULL, (gpointer)request_id); + + return MAPQUEST_ERROR_NONE; +} + +static int __remove_from_cancel_list(int request_id) +{ + if (g_list_length(reqCancelList) != 0) + reqCancelList = g_list_remove(reqCancelList, (gpointer)request_id); + + return MAPQUEST_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); + mapquest_request_s *req = NULL; + + while (list != NULL) { + req = (mapquest_request_s *) list->data; + + if (req != NULL) { + if (req->type == REQ_TYPE_GEOCODE) { + mapquest_geocode_req *geocode_req = (mapquest_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); + mapquest_geocode_req_s *geocode_req_details = (mapquest_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) { + mapquest_revgeocode_req *revgeocode_req = (mapquest_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); + mapquest_revgeocode_req_s *reverse_geocode_req_details = (mapquest_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) { + mapquest_route_req *route_req = (mapquest_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); + mapquest_route_req_s *route_req_details = (mapquest_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) { + mapquest_search_place_req *places_req = (mapquest_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); + mapquest_search_req_s *place_req_details = (mapquest_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 MAPQUEST_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) list->data; + + if (id == requestId) { + match_id = true; + break; + } + + list = g_list_next(list); + } + + return match_id; +} + +mapquest_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) { + mapquest_request_s *req = (mapquest_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; + + MapquestQueueData *response = (MapquestQueueData *) data; + + switch (response->type) { + case RESP_TYPE_GEOCODE: + { + MAP_DEBUG("Got geocode response.."); + MapquestGeocodeResponseData *geocodeData = (MapquestGeocodeResponseData *) (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...."); + mapquest_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) { + mapquest_geocode_req *geocode_req = (mapquest_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) { + mapquest_revgeocode_req *revgeocode_req = (mapquest_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) { + mapquest_search_place_req *places_req = (mapquest_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) { + mapquest_route_req *route_req = (mapquest_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: + { + MapquestRevGeocodeResponseData *revGeocodeData = (MapquestRevGeocodeResponseData *) (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...."); + mapquest_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) { + mapquest_geocode_req *geocode_req = (mapquest_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) { + mapquest_revgeocode_req *revgeocode_req = (mapquest_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) { + mapquest_search_place_req *places_req = (mapquest_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) { + mapquest_route_req *route_req = (mapquest_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: + { + MapquestRouteResponseData *routeData = (MapquestRouteResponseData *) (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...."); + mapquest_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) { + mapquest_geocode_req *geocode_req = (mapquest_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) { + mapquest_revgeocode_req *revgeocode_req = (mapquest_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) { + mapquest_search_place_req *places_req = (mapquest_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) { + mapquest_route_req *route_req = (mapquest_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: + { + MapquestPlaceResponseData *placesData = (MapquestPlaceResponseData *) (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...."); + mapquest_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) { + mapquest_geocode_req *geocode_req = (mapquest_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) { + mapquest_revgeocode_req *revgeocode_req = (mapquest_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) { + mapquest_search_place_req *places_req = (mapquest_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) { + mapquest_route_req *route_req = (mapquest_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) +{ + MapquestGeocodeResponseData *geocodeData = (MapquestGeocodeResponseData *) (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) +{ + MapquestRevGeocodeResponseData *revGeocodeData = (MapquestRevGeocodeResponseData *) (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) +{ + MapquestPlaceResponseData *placeData = (MapquestPlaceResponseData *) (ptr); + if (placeData) { + GList *place = NULL; + place = g_list_first(placeData->places); + + while (place) { + mapquest_place_resp_s *mapquest_place = (mapquest_place_resp_s *) place->data; + + if (mapquest_place->address) { + if (mapquest_place->address->street_add) { + g_free(mapquest_place->address->street_add); + mapquest_place->address->street_add = NULL; + } + if (mapquest_place->address->neighbourhood) { + g_free(mapquest_place->address->neighbourhood); + mapquest_place->address->neighbourhood = NULL; + } + if (mapquest_place->address->building_number) { + g_free(mapquest_place->address->building_number); + mapquest_place->address->building_number = NULL; + } + if (mapquest_place->address->city) { + g_free(mapquest_place->address->city); + mapquest_place->address->city = NULL; + } + if (mapquest_place->address->county) { + g_free(mapquest_place->address->county); + mapquest_place->address->county = NULL; + } + if (mapquest_place->address->state) { + g_free(mapquest_place->address->state); + mapquest_place->address->state = NULL; + } + if (mapquest_place->address->country) { + g_free(mapquest_place->address->country); + mapquest_place->address->country = NULL; + } + if (mapquest_place->address->country_code) { + g_free(mapquest_place->address->country_code); + mapquest_place->address->country_code = NULL; + } + if (mapquest_place->address->postal_code) { + g_free(mapquest_place->address->postal_code); + mapquest_place->address->postal_code = NULL; + } + g_free(mapquest_place->address); + mapquest_place->address = NULL; + } + + if (mapquest_place->category) { + g_free(mapquest_place->category); + mapquest_place->category = NULL; + } + if (mapquest_place->subcategory) { + g_free(mapquest_place->subcategory); + mapquest_place->subcategory = NULL; + } + if (mapquest_place->display_name) { + g_free(mapquest_place->display_name); + mapquest_place->display_name = NULL; + } + + placeData->places = g_list_remove(placeData->places, (gpointer)mapquest_place); + + g_free(mapquest_place); + mapquest_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) +{ + MapquestRouteResponseData *routeData = (MapquestRouteResponseData *) (ptr); + if (routeData) { + mapquest_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) { + mapquest_route_maneuver *maneuver = (mapquest_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 mapquest_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 != MAPQUEST_ERROR_NONE) + return MAPQUEST_ERROR_UNKNOWN; + + pthread_mutex_lock(&__requestLock); + requestList = NULL; + pthread_mutex_unlock(&__requestLock); + reqCancelList = NULL; + __ResponseQueueLen = 0; + __response_timer_running = false; + + return MAPQUEST_ERROR_NONE; +} + +int mapquest_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; + } + + MapquestQueueData *response = (MapquestQueueData *) data; + + switch (response->type) { + case RESP_TYPE_GEOCODE: + { + MapquestGeocodeResponseData *geocodeData = (MapquestGeocodeResponseData *) (response->data); + if (geocodeData) { + __free_geocode_response(geocodeData); + + g_free(geocodeData); + geocodeData = NULL; + } + } + break; + case RESP_TYPE_REVGEOCODE: + { + MapquestRevGeocodeResponseData *revGeocodeData = (MapquestRevGeocodeResponseData *) (response->data); + if (revGeocodeData) { + __free_revgeocode_response(revGeocodeData); + + g_free(revGeocodeData); + revGeocodeData = NULL; + } + } + break; + case RESP_TYPE_PLACES: + { + MapquestPlaceResponseData *placeData = (MapquestPlaceResponseData *) (response->data); + if (placeData != NULL) { + __free_place_response(placeData); + + g_free(placeData); + placeData = NULL; + } + } + break; + case RESP_TYPE_ROUTE: + { + MapquestRouteResponseData *routeData = (MapquestRouteResponseData *) (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 MAPQUEST_ERROR_NONE; +} + +int mapquest_push_to_queue(mapquest_resp_type type, gpointer data) +{ + MAP_DEBUG("Pushing to Queue...."); + + MapquestQueueData *queueData = (MapquestQueueData *)g_malloc0(sizeof(MapquestQueueData)); + if (!queueData) return MAPQUEST_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 MAPQUEST_ERROR_NONE; +} + +int start_geocode_service(mapquest_geocode_req_s *req_details, mapquest_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 { + MapquestGeocodeQueryData *queryData = (MapquestGeocodeQueryData *)g_malloc0(sizeof(MapquestGeocodeQueryData)); + + 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 == MAPQUEST_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 == MAPQUEST_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 MAPQUEST_ERROR_NONE; +} + +int start_reversegeocode_service(mapquest_revgeocode_req_s *req_details, mapquest_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 { + MapquestRevGeocodeQueryData *queryData = (MapquestRevGeocodeQueryData *)g_malloc0(sizeof(MapquestRevGeocodeQueryData)); + + 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 MAPQUEST_ERROR_NONE; +} + +int start_route_service(mapquest_route_req_s *req_details, mapquest_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 { + MapquestRouteQueryData *queryData = (MapquestRouteQueryData *)g_malloc0(sizeof(MapquestRouteQueryData)); + + 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 MAPQUEST_ERROR_NONE; +} + +int start_places_service(mapquest_search_req_s *req_details, mapquest_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 { + MapquestPlaceQueryData *queryData = (MapquestPlaceQueryData *)g_malloc0(sizeof(MapquestPlaceQueryData)); + + 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 MAPQUEST_ERROR_NONE; +} diff --git a/src/mapquest/mapquest_queue.h b/src/mapquest/mapquest_queue.h new file mode 100644 index 0000000..587dbb6 --- /dev/null +++ b/src/mapquest/mapquest_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 _MAPQUEST_QUEUE_H_ +#define _MAPQUEST_QUEUE_H_ + +#include <glib.h> +#include "mapquest_server_private.h" + +typedef struct { + mapquest_req_type type; + void *request; +} mapquest_request_s; + +typedef struct { + mapquest_geocode_req_s *req_details; + int requestId; + mapquest_geocode_cb geocode_cb; + void *user_data; +} mapquest_geocode_req; + +typedef struct { + mapquest_revgeocode_req_s *req_details; + int requestId; + mapquest_reverse_geocode_cb revgeocode_cb; + void *user_data; +} mapquest_revgeocode_req; + +typedef struct { + mapquest_route_req_s *req_details; + mapquest_route_cb route_cb; + int requestId; + void *user_data; +} mapquest_route_req; + +typedef struct { + mapquest_search_req_s *req_details; + mapquest_place_search_cb search_place_cb; + int requestId; + void *user_data; +} mapquest_search_place_req; + +int add_to_geocode_list(mapquest_geocode_req_s *req_details, mapquest_geocode_cb callback, int request_id, void *user_data); +int add_to_revgeocode_list(mapquest_revgeocode_req_s *req_details, mapquest_reverse_geocode_cb callback, int request_id, void *user_data); +int add_to_route_list(mapquest_route_req_s *req_details, mapquest_route_cb callback, int request_id, void *user_data); +int add_to_places_list(mapquest_search_req_s *req_details, mapquest_place_search_cb callback, int request_id, void *user_data); + +int remove_from_request_list(int request_id); + +int start_geocode_service(mapquest_geocode_req_s *req_details, mapquest_geocode_cb callback, int request_id, void *user_data); +int start_reversegeocode_service(mapquest_revgeocode_req_s *req_details, mapquest_reverse_geocode_cb callback, int request_id, void *user_data); +int start_route_service(mapquest_route_req_s *req_details, mapquest_route_cb callback, int request_id, void *user_data); +int start_places_service(mapquest_search_req_s *req_details, mapquest_place_search_cb callback, int request_id, void *user_data); + +int mapquest_init_queue(); +int mapquest_deinit_queue(); +int mapquest_push_to_queue(mapquest_resp_type type, gpointer data); + +#endif /* _MAPQUEST_QUEUE_H_ */ diff --git a/src/mapquest/mapquest_restcurl.c b/src/mapquest/mapquest_restcurl.c new file mode 100644 index 0000000..a8fccd3 --- /dev/null +++ b/src/mapquest/mapquest_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 <stdlib.h> +#include <curl/curl.h> +#include <curl/easy.h> +#include <pthread.h> +#include <network/net_connection.h> +#include "mapquest_restcurl.h" +#include "mapquest_types.h" +#include "mapquest_jsonparser.h" +#include "mapquest_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; + mapquest_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; +} + +/*****************************************/ + +mapquest_error_e __get_proxy_address() +{ + mapquest_error_e err = MAPQUEST_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 = MAPQUEST_ERROR_UNKNOWN; + switch (errorCode) { + case CONNECTION_ERROR_INVALID_PARAMETER: + MAP_DEBUG("Invalid parameter"); + err = MAPQUEST_ERROR_INVALID_PARAMETER; + break; + case CONNECTION_ERROR_OUT_OF_MEMORY: + MAP_DEBUG("Out of memory error"); + err = MAPQUEST_ERROR_OUT_OF_MEMORY; + break; + case CONNECTION_ERROR_INVALID_OPERATION: + MAP_DEBUG("Invalid Operation"); + err = MAPQUEST_ERROR_INVALID_OPERATION; + break; + case CONNECTION_ERROR_ADDRESS_FAMILY_NOT_SUPPORTED: + MAP_DEBUG("Address family not supported"); + err = MAPQUEST_ERROR_NOT_SUPPORTED; + break; + /* + case CONNECTION_ERROR_PERMISSION_DENIED: + MAP_DEBUG("Permission denied"); + err = MAPQUEST_ERROR_PERMISSION_DENIED; + break; + */ + case CONNECTION_ERROR_OPERATION_FAILED: + MAP_DEBUG("Operation failed"); + err = MAPQUEST_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 = MAPQUEST_ERROR_NETWORK_UNREACHABLE; + break; + case CONNECTION_ERROR_NOW_IN_PROGRESS: + MAP_DEBUG("Now in progress"); + err = MAPQUEST_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 = MAPQUEST_ERROR_CANCELED; + break; + case CONNECTION_ERROR_DHCP_FAILED: + MAP_DEBUG("DHCP failed"); + break; + case CONNECTION_ERROR_INVALID_KEY: + MAP_DEBUG("Invalid key"); + err = MAPQUEST_ERROR_KEY_NOT_AVAILABLE; + break; + case CONNECTION_ERROR_NO_REPLY: + MAP_DEBUG("No reply"); + err = MAPQUEST_ERROR_RESOURCE_BUSY; + break; + case CONNECTION_ERROR_NOT_SUPPORTED: + MAP_DEBUG("Not Supported"); + err = MAPQUEST_ERROR_NOT_SUPPORTED; + break; + default: + MAP_DEBUG("Unknown"); + break; + } + MAP_DEBUG("errorCode = %ld", (long)errorCode); + } + + if (con) + connection_destroy(con); + + if (err != MAPQUEST_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 MAPQUEST_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) 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)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, mapquest_req_type type, void *user_data) +{ + if (!url || !user_data) return -1; + + int req_id = -1; + + switch (type) { + case REQ_TYPE_GEOCODE: + req_id = ((MapquestGeocodeQueryData *) user_data)->requestId; + break; + case REQ_TYPE_REVGEOCODE: + req_id = ((MapquestRevGeocodeQueryData *) user_data)->requestId; + break; + case REQ_TYPE_PLACES: + req_id = ((MapquestRouteQueryData *) user_data)->requestId; + break; + case REQ_TYPE_ROUTE: + req_id = ((MapquestPlaceQueryData *) 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(mapquest_req_type type, MemoryStruct_s *m_chunk, void *user_data) +{ + mapquest_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)request_id); + else + __cancel_req_list = g_list_insert_before(__cancel_req_list, NULL, (gpointer)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: + { + MapquestGeocodeQueryData *queryData = (MapquestGeocodeQueryData *)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: + { + MapquestRevGeocodeQueryData *queryData = (MapquestRevGeocodeQueryData *)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: + { + MapquestPlaceQueryData *queryData = (MapquestPlaceQueryData *)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: + { + MapquestRouteQueryData *queryData = (MapquestRouteQueryData *)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/mapquest/mapquest_restcurl.h b/src/mapquest/mapquest_restcurl.h new file mode 100644 index 0000000..b1d5a2a --- /dev/null +++ b/src/mapquest/mapquest_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 _MAPQUEST_RESTCURL_H_ +#define _MAPQUEST_RESTCURL_H_ + +#include "mapquest_server_private.h" + +#define CURL_MAX_CONNECTS 30 + +int init_curl(); + +int deinit_curl(); + +int get_num_running_requests(); + +int add_handle(char *url, mapquest_req_type type, void *user_data); + +void cancel_request(int request_id); + +#endif /* _MAPQUEST_RESTCURL_H_ */ diff --git a/src/mapquest/mapquest_revgeocode.c b/src/mapquest/mapquest_revgeocode.c new file mode 100644 index 0000000..246bee6 --- /dev/null +++ b/src/mapquest/mapquest_revgeocode.c @@ -0,0 +1,47 @@ +/* + * 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 <stdio.h> +#include <glib.h> +#include <pthread.h> +#include "mapquest_revgeocode.h" +#include "mapquest_types.h" +#include "mapquest_server_private.h" +#include "mapquest_debug.h" +#include "mapquest_queue.h" +#include "mapquest_restcurl.h" + +#define REVERSE_GEOCODE_URL "https://open.mapquestapi.com/geocoding/v1/reverse?key=%s&outFormat=json" + +int query_revgeocode(gchar *maps_key, gdouble latitude, gdouble longitude, gpointer user_data) +{ + char url[1024]; + char tmpStr[512]; + + if (maps_key != NULL) + snprintf(tmpStr, sizeof(tmpStr), REVERSE_GEOCODE_URL, maps_key); + else + snprintf(tmpStr, sizeof(tmpStr), REVERSE_GEOCODE_URL, "null"); + + strcpy(url, tmpStr); + + snprintf(tmpStr, sizeof(tmpStr), "&location=%f,%f", latitude, longitude); + strcat(url, tmpStr); + + add_handle(url, REQ_TYPE_REVGEOCODE, user_data); + + return 0; +} diff --git a/src/mapquest/mapquest_revgeocode.h b/src/mapquest/mapquest_revgeocode.h new file mode 100644 index 0000000..d337733 --- /dev/null +++ b/src/mapquest/mapquest_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 _MAPQUEST_REVGEOCODE_H_ +#define _MAPQUEST_REVGEOCODE_H_ + +#include "mapquest_api.h" +#include "mapquest_types.h" + +int query_revgeocode(gchar *maps_key, gdouble latitude, gdouble longitude, gpointer user_data); + +#endif /* _MAPQUEST_REVGEOCODE_H_ */ diff --git a/src/mapquest/mapquest_route.c b/src/mapquest/mapquest_route.c new file mode 100644 index 0000000..a4ec225 --- /dev/null +++ b/src/mapquest/mapquest_route.c @@ -0,0 +1,106 @@ +/* + * 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 <stdio.h> +#include <glib.h> +#include <pthread.h> +#include "mapquest_route.h" +#include "mapquest_types.h" +#include "mapquest_server_private.h" +#include "mapquest_debug.h" +#include "mapquest_queue.h" +#include "mapquest_restcurl.h" + +#define ROUTE_URL "https://open.mapquestapi.com/directions/v2/route?key=%s&ambiguities=ignore&outFormat=json&shapeFormat=raw&generalize=0" + +int query_route(gchar *maps_key, coords_s startPoint, coords_s endPoint, route_type type, route_feature_avoids 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, "&unit=m"); /* Keeping default as miles and conversion will be done later */ + + if (type == ROUTE_TYPE_FASTEST) + strcat(url, "&routeType=fastest"); + else if (type == ROUTE_TYPE_SHORTEST) + strcat(url, "&routeType=shortest"); + else if (type == ROUTE_TYPE_PEDESTRIAN) + strcat(url, "&routeType=pedestrian"); + else if (type == ROUTE_TYPE_MULTIMODAL) + strcat(url, "&routeType=multimodal"); + else if (type == ROUTE_TYPE_BICYCLE) + strcat(url, "&routeType=bicycle"); + + if (avoids == ROUTE_AVOID_LIMITED_ACCESS) + strcat(url, "&avoids=Limited Access"); + else if (avoids == ROUTE_AVOID_TOLL_ROAD) + strcat(url, "&avoids=Tollroad"); + else if (avoids == ROUTE_AVOID_FERRY) + strcat(url, "&avoids=Ferry"); + else if (avoids == ROUTE_AVOID_UNPAVED) + strcat(url, "&avoids=Unpaved"); + else if (avoids == ROUTE_AVOID_SEASONAL_CLOSURE) + strcat(url, "&avoids=Approximate Seasonal Closure"); + else if (avoids == ROUTE_AVOID_COUNTRY_BORDER_CROSSING) + strcat(url, "&avoids=Country border crossing"); + + if (style == DRIVING_STYLE_NORMAL) + strcat(url, "&drivingStyle=2"); + else if (style == DRIVING_STYLE_CAUTIOUS) + strcat(url, "&drivingStyle=1"); + else if (style == DRIVING_STYLE_AGGRESSIVE) + strcat(url, "&drivingStyle=3"); + + 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; + + if (data) { + if (index == 0) + snprintf(tmpStr, sizeof(tmpStr), "&from=%f,%f", data->latitude, data->longitude); + else + snprintf(tmpStr, sizeof(tmpStr), "&to=%f,%f", data->latitude, data->longitude); + strcat(url, tmpStr); + } + + waypoints_list = g_list_next(waypoints_list); + index++; + } + } else { + snprintf(tmpStr, sizeof(tmpStr), "&from=%f,%f", startPoint.latitude, startPoint.longitude); + strcat(url, tmpStr); + + snprintf(tmpStr, sizeof(tmpStr), "&to=%f,%f", endPoint.latitude, endPoint.longitude); + strcat(url, tmpStr); + } + + add_handle(url, REQ_TYPE_ROUTE, user_data); + + return 0; +} diff --git a/src/mapquest/mapquest_route.h b/src/mapquest/mapquest_route.h new file mode 100644 index 0000000..8a71d07 --- /dev/null +++ b/src/mapquest/mapquest_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 _MAPQUEST_ROUTE_H_ +#define _MAPQUEST_ROUTE_H_ + +#include "mapquest_api.h" +#include "mapquest_types.h" + +int query_route(gchar *maps_key, coords_s startPoint, coords_s endPoint, route_type type, route_feature_avoids avoids, route_driving_style style, GList *waypoints, gpointer user_data); + +#endif /* _MAPQUEST_ROUTE_H_ */ diff --git a/src/mapquest/mapquest_server_private.h b/src/mapquest/mapquest_server_private.h new file mode 100644 index 0000000..cba948f --- /dev/null +++ b/src/mapquest/mapquest_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 _MAPQUEST_PRIVATE_H_ +#define _MAPQUEST_PRIVATE_H_ + +#include "mapquest_api.h" + +typedef enum { + REQ_TYPE_GEOCODE = 0, + REQ_TYPE_REVGEOCODE, + REQ_TYPE_PLACES, + REQ_TYPE_ROUTE, + REQ_TYPE_NONE +} mapquest_req_type; + +typedef enum { + RESP_TYPE_GEOCODE = 0, + RESP_TYPE_REVGEOCODE, + RESP_TYPE_PLACES, + RESP_TYPE_ROUTE, + RESP_TYPE_NONE +} mapquest_resp_type; + +typedef struct { + int requestId; + mapquest_geocode_cb geocode_cb; + void *user_data; +} MapquestGeocodeQueryData; + +typedef struct { + int requestId; + mapquest_reverse_geocode_cb reverse_geocode_cb; + void *user_data; +} MapquestRevGeocodeQueryData; + +typedef struct { + int requestId; + mapquest_route_cb route_cb; + coords_s origin; + coords_s destination; + route_unit unit; + void *user_data; +} MapquestRouteQueryData; + +typedef struct { + int requestId; + mapquest_place_search_cb place_search_cb; + void *user_data; +} MapquestPlaceQueryData; + +typedef struct { + mapquest_error_e error; + int requestId; + mapquest_geocode_cb geocode_cb; + GList *coords; + void *user_data; +} MapquestGeocodeResponseData; + +typedef struct { + mapquest_error_e error; + int requestId; + mapquest_reverse_geocode_cb reverse_geocode_cb; + mapquest_address_resp_s *addressDetails; + void *user_data; +} MapquestRevGeocodeResponseData; + +typedef struct { + mapquest_error_e error; + int requestId; + mapquest_route_cb route_cb; + mapquest_route_resp_s *routeResponse; + void *user_data; +} MapquestRouteResponseData; + +typedef struct { + mapquest_error_e error; + int requestId; + mapquest_place_search_cb place_search_cb; + GList *places; + void *user_data; +} MapquestPlaceResponseData; + +typedef struct { + mapquest_resp_type type; + void *data; +} MapquestQueueData; + +#endif /* _MAPQUEST_PRIVATE_H_ */ diff --git a/src/mapquest/mapquest_types.h b/src/mapquest/mapquest_types.h new file mode 100644 index 0000000..79ce1fc --- /dev/null +++ b/src/mapquest/mapquest_types.h @@ -0,0 +1,193 @@ +/* + * 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 _MAPQUEST_TYPES_H_ +#define _MAPQUEST_TYPES_H_ + +#include <glib.h> + +typedef enum { + MAPQUEST_ERROR_NONE = 0, /**< Successful */ + MAPQUEST_ERROR_PERMISSION_DENIED, /**< Permission Denied */ + MAPQUEST_ERROR_OUT_OF_MEMORY, /**< Out of memory */ + MAPQUEST_ERROR_INVALID_PARAMETER, /**< Invalid parameter */ + MAPQUEST_ERROR_NOT_SUPPORTED, /**< Not supported */ + MAPQUEST_ERROR_CONNECTION_TIMED_OUT, /**< Timeout error, no answer */ + MAPQUEST_ERROR_NETWORK_UNREACHABLE, /**< Network unavailable */ + MAPQUEST_ERROR_INVALID_OPERATION, /**< Opeartion is not valid */ + MAPQUEST_ERROR_KEY_NOT_AVAILABLE, /**< Invalid key */ + MAPQUEST_ERROR_RESOURCE_BUSY, /**< Resource busy */ + MAPQUEST_ERROR_CANCELED, /**< Service canceled */ + MAPQUEST_ERROR_UNKNOWN, /**< Unknown error */ + MAPQUEST_ERROR_SERVICE_NOT_AVAILABLE, /**< Service unavailabe*/ + MAPQUEST_ERROR_NOT_FOUND, /**< Result not found */ +} mapquest_error_e; + +typedef enum { + MAPQUEST_BOUNDARY_NONE = 0, /* Undefined geographical area type. */ + MAPQUEST_BOUNDARY_RECT, /* Rectangular geographical area type. */ + MAPQUEST_BOUNDARY_CIRCLE, /* Circle geographical area type. */ +} boundary_type; + +typedef enum { + ROUTE_TYPE_FASTEST = 0, + ROUTE_TYPE_SHORTEST, + ROUTE_TYPE_PEDESTRIAN, + ROUTE_TYPE_MULTIMODAL, + ROUTE_TYPE_BICYCLE +} route_type; + +typedef enum { + ROUTE_UNIT_M = 0, /* for Meter */ + ROUTE_UNIT_KM, /* for Kilometer */ + ROUTE_UNIT_FT, /* for Foot */ + ROUTE_UNIT_YD /*for Yard */ +} route_unit; + +typedef enum { + ROUTE_AVOID_NONE = 0, + ROUTE_AVOID_LIMITED_ACCESS, + ROUTE_AVOID_TOLL_ROAD, + ROUTE_AVOID_FERRY, + ROUTE_AVOID_UNPAVED, + ROUTE_AVOID_SEASONAL_CLOSURE, + ROUTE_AVOID_COUNTRY_BORDER_CROSSING +} 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; + }; +} mapquest_boundary_s; + +typedef struct { + gchar *maps_key; + gchar *address; + mapquest_boundary_s *boundary; + gint num_res; +} mapquest_geocode_req_s; + +typedef struct { + gchar *maps_key; + gint num_res; + coords_s coordinates; +} mapquest_revgeocode_req_s; + +typedef struct { + gchar *maps_key; + gchar *search_string; + gint num_res; + gchar *country_code; + mapquest_boundary_s *boundary; + GList *excludes; +} mapquest_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 */ +} mapquest_route_req_s; + +typedef struct { + gint zoom_level; + coords_s center_coords; +} mapquest_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; +} mapquest_address_resp_s; + +typedef struct { + gchar *place_id; + gchar *display_name; + mapquest_address_resp_s *address; + rectangle_s bounding_box; + coords_s coordinates; + gchar *category; + gchar *subcategory; + gchar *icon_url; +} mapquest_place_resp_s; + +typedef struct { + guint type; + guint direction; + guint text; + gchar *icon_url; +} mapquest_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; +} mapquest_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 mapquest_route_maneuver */ + GList *shapePoints; +} mapquest_route_resp_s; + +#endif /* _MAPQUEST_TYPES_H_ */ diff --git a/src/mapquest/mapquest_util.c b/src/mapquest/mapquest_util.c new file mode 100644 index 0000000..fc71d12 --- /dev/null +++ b/src/mapquest/mapquest_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 "mapquest_util.h" +#include "mapquest_debug.h" +#include <math.h> + +#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/mapquest/mapquest_util.h b/src/mapquest/mapquest_util.h new file mode 100644 index 0000000..b62a3d5 --- /dev/null +++ b/src/mapquest/mapquest_util.h @@ -0,0 +1,24 @@ +/* + * 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 _MAPQUEST_UTIL_H_ +#define _MAPQUEST_UTIL_H_ + +#include "mapquest_types.h" + +void calculate_point(gdouble Lat1, gdouble Lon1, int dBearing, gdouble dist, coords_s **coord); + +#endif /* _MAPQUEST_UTIL_H_ */ diff --git a/src/mapquest_plugin.c b/src/mapquest_plugin.c new file mode 100644 index 0000000..9b119f2 --- /dev/null +++ b/src/mapquest_plugin.c @@ -0,0 +1,1394 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> +#include "mapquest_plugin.h" +#include "mapquest_plugin_internal.h" +#include "mapquest_api.h" +#include <maps_error.h> +#include <maps_route_plugin.h> +#include <maps_route_segment_plugin.h> +#include <maps_route_maneuver_plugin.h> +#include <maps_place_plugin.h> +#include <maps_place_category.h> +#include <maps_place_image_plugin.h> +#include <maps_place_rating_plugin.h> + +#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 MAPQUEST_ERROR_NONE: + return MAPS_ERROR_NONE; + case MAPQUEST_ERROR_PERMISSION_DENIED: + return MAPS_ERROR_PERMISSION_DENIED; + case MAPQUEST_ERROR_OUT_OF_MEMORY: + return MAPS_ERROR_OUT_OF_MEMORY; + case MAPQUEST_ERROR_INVALID_PARAMETER: + return MAPS_ERROR_INVALID_PARAMETER; + case MAPQUEST_ERROR_NOT_SUPPORTED: + return MAPS_ERROR_NOT_SUPPORTED; + case MAPQUEST_ERROR_CONNECTION_TIMED_OUT: + return MAPS_ERROR_CONNECTION_TIME_OUT; + case MAPQUEST_ERROR_NETWORK_UNREACHABLE: + return MAPS_ERROR_NETWORK_UNREACHABLE; + case MAPQUEST_ERROR_INVALID_OPERATION: + return MAPS_ERROR_INVALID_OPERATION; + case MAPQUEST_ERROR_KEY_NOT_AVAILABLE: + return MAPS_ERROR_KEY_NOT_AVAILABLE; + case MAPQUEST_ERROR_RESOURCE_BUSY: + return MAPS_ERROR_RESOURCE_BUSY; + case MAPQUEST_ERROR_CANCELED: + return MAPS_ERROR_CANCELED; + case MAPQUEST_ERROR_UNKNOWN: + return MAPS_ERROR_UNKNOWN; + case MAPQUEST_ERROR_SERVICE_NOT_AVAILABLE: + return MAPS_ERROR_SERVICE_NOT_AVAILABLE; + case MAPQUEST_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 = mapquest_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 = mapquest_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, "MAPQUEST"); + + 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 __mapquest_geocode_cb(mapquest_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 != MAPQUEST_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; + + mapquest_geocode_req_s *geocode_req = (mapquest_geocode_req_s *)g_malloc0(sizeof(mapquest_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 = mapquest_geocode(geocode_req, __mapquest_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; + + mapquest_geocode_req_s *geocode_req = (mapquest_geocode_req_s *)g_malloc0(sizeof(mapquest_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 = (mapquest_boundary_s *)g_malloc0(sizeof(mapquest_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 = MAPQUEST_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 = MAPQUEST_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 = mapquest_geocode(geocode_req, __mapquest_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; + + mapquest_geocode_req_s *geocode_req = (mapquest_geocode_req_s *)g_malloc0(sizeof(mapquest_geocode_req_s)); + if (geocode_req == NULL) { + free(calldata_geocode); + MAPS_PRINT_ERROR_CODE_RETURN(MAPS_ERROR_OUT_OF_MEMORY); + } + + char resultAddressQuery[1024]; + strcpy(resultAddressQuery, ""); + + 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 = mapquest_geocode(geocode_req, __mapquest_geocode_cb, __request_id, (void *) calldata_geocode); + + return __convert_to_maps_error(ret); +} + +static void __mapquest_reverse_geocode_cb(mapquest_error_e result, int request_id, mapquest_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 != MAPQUEST_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; + + mapquest_revgeocode_req_s *reverse_geocode_req = (mapquest_revgeocode_req_s *)g_malloc0(sizeof(mapquest_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 = mapquest_reverse_geocode(reverse_geocode_req, __mapquest_reverse_geocode_cb, __request_id, (void *) calldata_reverse_geocode); + + return __convert_to_maps_error(ret); +} + +static void __mapquest_route_cb(mapquest_error_e result, int request_id, mapquest_route_resp_s *route_info, void *user_data) +{ + MAPS_LOGD("__mapquest_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); + mapquest_route_maneuver *maneuver = (mapquest_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; + + mapquest_route_req_s *route_req = (mapquest_route_req_s *)g_malloc0(sizeof(mapquest_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 = mapquest_start_route(route_req, __mapquest_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; + + mapquest_route_req_s *route_req = (mapquest_route_req_s *)g_malloc0(sizeof(mapquest_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 = mapquest_start_route(route_req, __mapquest_route_cb, __request_id, (void *)calldata_route); + + return __convert_to_maps_error(ret); +} + +static void __mapquest_place_search_cb(mapquest_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 != MAPQUEST_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); + mapquest_place_resp_s *mapquest_place = (mapquest_place_resp_s *) temp_place->data; + maps_place_set_id(place, mapquest_place->place_id); + maps_place_set_name(place, mapquest_place->display_name); + + MAPS_LOGD("Before address.."); + /* Address */ + if (mapquest_place->address) { + maps_address_h addr = NULL; + maps_address_create(&addr); + + maps_address_set_street(addr, mapquest_place->address->street_add); + maps_address_set_building_number(addr, mapquest_place->address->building_number); + maps_address_set_city(addr, mapquest_place->address->city); + maps_address_set_county(addr, mapquest_place->address->county); + maps_address_set_state(addr, mapquest_place->address->state); + maps_address_set_country(addr, mapquest_place->address->country); + maps_address_set_country_code(addr, mapquest_place->address->country_code); + maps_address_set_postal_code(addr, mapquest_place->address->postal_code); + maps_address_set_freetext(addr, mapquest_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(mapquest_place->coordinates.latitude, mapquest_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, mapquest_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, mapquest_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; + + mapquest_search_req_s *place_req = (mapquest_search_req_s *)g_malloc0(sizeof(mapquest_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 = (mapquest_boundary_s *)g_malloc0(sizeof(mapquest_boundary_s)); + + if (place_req->boundary) { + place_req->boundary->type = MAPQUEST_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 = mapquest_search_place(place_req, __mapquest_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; + + mapquest_search_req_s *place_req = (mapquest_search_req_s *)g_malloc0(sizeof(mapquest_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 = (mapquest_boundary_s *)g_malloc0(sizeof(mapquest_boundary_s)); + + if (place_req->boundary != NULL) { + if (bound->type == MAPS_AREA_CIRCLE) { + place_req->boundary->type = MAPQUEST_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 = MAPQUEST_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 = mapquest_search_place(place_req, __mapquest_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; + + mapquest_search_req_s *place_req = (mapquest_search_req_s *)g_malloc0(sizeof(mapquest_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 = (mapquest_boundary_s *)g_malloc0(sizeof(mapquest_boundary_s)); + + if (place_req->boundary != NULL) { + if (bound->type == MAPS_AREA_CIRCLE) { + place_req->boundary->type = MAPQUEST_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 = MAPQUEST_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 = mapquest_search_place(place_req, __mapquest_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 = mapquest_cancel_request(request_id); + + return __convert_to_maps_error(ret); +} |