apply new tangram
[platform/core/location/maps-plugin-mapzen.git] / src / mapzen / mapzen_jsonparser.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <maps_coordinates.h>
18
19 #include <stdlib.h>
20
21 #include "mapzen_jsonparser.hpp"
22 #include "rapidjson/document.h"
23
24 extern "C" {
25 #include "mapzen_queue.h"
26 #include "mapzen_debug.h"
27 #include "mapzen_types.h"
28 #include "mapzen_util.h"
29 }
30
31 #include <string>
32 #include <vector>
33
34 #ifdef __cplusplus
35 extern "C" {
36 #endif
37
38 #define ROUTE_UNIT_CONVERSION_MILE_TO_M(x)      (1609.34 * (x))
39 #define ROUTE_UNIT_CONVERSION_MILE_TO_KM(x)     (1.60934 * (x))
40 #define ROUTE_UNIT_CONVERSION_MILE_TO_FT(x)     (5280 * (x))
41 #define ROUTE_UNIT_CONVERSION_MILE_TO_YD(x)     (1760 * (x))
42
43 static route_unit __route_unit = UNIT_KM;
44 static route_type __route_type = COSTING_AUTO;
45 constexpr double kPolylinePrecision = 1E6;
46 constexpr double kInvPolylinePrecision = 1.0 / kPolylinePrecision;
47
48
49 //TODO: port this to c? or port the whole project to c++ or add all the proper externs
50 void decode_shape(const std::string& encoded, std::vector<coords_s>& output) {
51         // what byte are we looking at
52         size_t i = 0;
53
54         // Handy lambda to turn a few bytes of an encoded string into an integer
55         auto deserialize = [&encoded, &i](const int previous) {
56                 // Grab each 5 bits and mask it in where it belongs using the shift
57                 int byte, shift = 0, result = 0;
58                 do {
59                         byte = static_cast<int>(encoded[i++]) - 63;
60                         result |= (byte & 0x1f) << shift;
61                         shift += 5;
62                 } while (byte >= 0x20);
63
64                 // Undo the left shift from above or the bit flipping and add
65                 // to previous since its an offset
66                 return previous + (result & 1 ? ~(result >> 1) : (result >> 1));
67         };
68
69         // Iterate over all characters of the encoded shape string
70         int last_lon = 0, last_lat = 0;
71         while (i < encoded.length())
72         {
73                 // Decode the coordinates, lat first
74                 int lat = deserialize(last_lat);
75                 int lon = deserialize(last_lon);
76
77                 // Shift the decimal point 5 places to the left and add to the output
78                 coords_s ll;
79                 ll.latitude  = static_cast<double>(lat) * kInvPolylinePrecision;
80                 ll.longitude = static_cast<double>(lon) * kInvPolylinePrecision;
81                 output.emplace_back(std::move(ll));
82
83                 // Remember the last one we encountered
84                 last_lat = lat;
85                 last_lon = lon;
86         }
87 }
88
89
90 static mapzen_error_e __convert_status(int status)
91 {
92         mapzen_error_e error = MAPZEN_ERROR_UNKNOWN;
93         switch (status) {
94         case 0:
95                 {
96                         /* Successful Geocode call */
97                         error = MAPZEN_ERROR_NONE;
98                         break;
99                 }
100         case 400:
101                 {
102                         /* Error with input - Illegal argument from request */
103                         error = MAPZEN_ERROR_INVALID_PARAMETER;
104                         break;
105                 }
106         case 403:
107                 {
108                         /* Key related error - Invalid key */
109                         error = MAPZEN_ERROR_KEY_NOT_AVAILABLE;
110                         break;
111                 }
112         case 500:
113                 {
114                         /* Unknown error */
115                         error = MAPZEN_ERROR_UNKNOWN;
116                         break;
117                 }
118         case -1:
119                 {
120                         /* Network error */
121                         error = MAPZEN_ERROR_NETWORK_UNREACHABLE;
122                         break;
123                 }
124         }
125
126         return error;
127 }
128
129 bool __get_string(const rapidjson::Value& obj, const char* key, char** value)
130 {
131         //if we have the key and its not an empty value
132         rapidjson::Value::ConstMemberIterator itr = obj.FindMember(key);
133         if(itr != obj.MemberEnd() && itr->value.GetStringLength()){
134                 (*value) = (gchar *)g_malloc(itr->value.GetStringLength() + sizeof(rapidjson::Document::Ch));
135                 strncpy((*value), itr->value.GetString(), itr->value.GetStringLength());
136                 memset((*value) + itr->value.GetStringLength(), 0, sizeof(rapidjson::Document::Ch));
137         //we had nothing
138         } else {
139                 (*value) = NULL;
140         }
141         //is this something
142         return *value != NULL;
143 }
144
145 /************ GEOCODE ***************/
146
147
148 static void __parse_geocode_response(char *response, int size, int *status, GList **coordsList)
149 {
150         MAP_DEBUG("Inside __parse_geocode_response..");
151
152
153         if (!response || !status || !coordsList) return;
154
155         //so far we have nothing
156         *coordsList = NULL;
157         *status = 500;
158
159         //crack open that json
160         rapidjson::Document document;
161         document.Parse(std::string(response, size).c_str());
162         rapidjson::Value::ConstMemberIterator features = document.FindMember("features");
163         if(features != document.MemberEnd() && features->value.IsArray()) {
164                 //for each feature
165                 for (rapidjson::Value::ConstValueIterator f = features->value.Begin(); f != features->value.End(); ++f) {
166                         //it has to have geometry
167                         rapidjson::Value::ConstMemberIterator geom = f->FindMember("geometry");
168                         if(geom != f->MemberEnd()) {
169                                 //skip non-points
170                                 rapidjson::Value::ConstMemberIterator type = geom->value.FindMember("type");
171                                 if(type == geom->value.MemberEnd() || strcmp(type->value.GetString(), "Point"))
172                                         continue;
173                                 //get actual points
174                                 rapidjson::Value::ConstMemberIterator coords = geom->value.FindMember("coordinates");
175                                 if(coords == geom->value.MemberEnd() || !coords->value.IsArray() || coords->value.Size() != 2)
176                                         continue;
177
178                                 coords_s *coord = (coords_s *)g_malloc0(sizeof(coords_s));
179                                 if (coord != NULL) {
180                                         coord->longitude = coords->value[0].GetDouble();
181                                         coord->latitude = coords->value[1].GetDouble();
182                                 }
183
184                                 if (*coordsList == NULL)
185                                         *coordsList = g_list_append(*coordsList, coord);
186                                 else
187                                         *coordsList = g_list_insert_before(*coordsList, NULL, coord);
188                         }
189                 }
190         }
191         *status = 0;
192 }
193
194 /****************** REVERSE GEOCODE *********************/
195
196 static void __parse_revgeocode_response(char *response, int size, int *status, mapzen_address_resp_s **respAddr)
197 {
198         if (!response || !status || !respAddr) return;
199
200         //so far we have nothing
201         *respAddr = NULL;
202         *status = 500;
203
204         //crack open that json
205         rapidjson::Document document;
206         document.Parse(std::string(response, size).c_str());
207         rapidjson::Value::ConstMemberIterator features = document.FindMember("features");
208         if(features != document.MemberEnd() && features->value.IsArray()) {
209                 //for each feature
210                 for (rapidjson::Value::ConstValueIterator f = features->value.Begin(); f != features->value.End(); ++f) {
211                         //it has to have geometry
212                         rapidjson::Value::ConstMemberIterator geom = f->FindMember("geometry");
213                         if(geom != f->MemberEnd()) {
214                                 //skip non-points
215                                 rapidjson::Value::ConstMemberIterator type = geom->value.FindMember("type");
216                                 if(type == geom->value.MemberEnd() || strcmp(type->value.GetString(), "Point"))
217                                         continue;
218                                 //get actual points
219                                 rapidjson::Value::ConstMemberIterator coords = geom->value.FindMember("coordinates");
220                                 if(coords == geom->value.MemberEnd() || !coords->value.IsArray() || coords->value.Size() != 2)
221                                         continue;
222
223                                 //NOTE: it seems as though the tizen maps plugin api assumes that reverse geocode results will
224                                 //actually be at the coordinates where you requested the reverse geocode. the mapzen api can return
225                                 //POIS which are some distance away from the location and currently this is not accounted for :o(
226
227                                 //get out the address information
228                                 rapidjson::Value::ConstMemberIterator properties = f->FindMember("properties");
229                                 if(properties != f->MemberEnd()) {
230                                         //fill this out as we go
231                                         *respAddr = (mapzen_address_resp_s *)g_malloc(sizeof(mapzen_address_resp_s));
232                                         bool something = false;
233                                         something = __get_string(properties->value, "street", &(*respAddr)->street) || something;
234                                         something = __get_string(properties->value, "neighbourhood", &(*respAddr)->neighbourhood) || something;
235                                         something = __get_string(properties->value, "housenumber", &(*respAddr)->housenumber) || something;
236                                         something = __get_string(properties->value, "localadmin", &(*respAddr)->localadmin) || something;
237                                         something = __get_string(properties->value, "county", &(*respAddr)->county) || something;
238                                         something = __get_string(properties->value, "region", &(*respAddr)->region) || something;
239                                         something = __get_string(properties->value, "country", &(*respAddr)->country) || something;
240                                         something = __get_string(properties->value, "country_a", &(*respAddr)->country_a) || something;
241                                         something = __get_string(properties->value, "postalcode", &(*respAddr)->postalcode) || something;
242                                         //if everything was null thats pretty much unusable
243                                         //TODO: these are pretty weak criteria..
244                                         if(!something) {
245                                                 g_free(*respAddr);
246                                                 (*respAddr) = NULL;
247                                         //forget the rest, we have one with something in it
248                                         } else {
249                                                 break;
250                                         }
251                                 }
252                         }
253                 }
254         }
255         *status = 0;
256 }
257
258 /****************  PLACE SEARCH ********************/
259
260 static void __parse_place_response(char *response, int size, GList **placeList)
261 {
262         MAP_DEBUG("Inside __parse_place_response.");
263
264         if (!response || !placeList) return;
265
266         *placeList = NULL;
267
268         //crack open that json
269         rapidjson::Document document;
270         document.Parse(std::string(response, size).c_str());
271         rapidjson::Value::ConstMemberIterator features = document.FindMember("features");
272         if(features != document.MemberEnd() && features->value.IsArray()) {
273                 //for each feature
274                 for (rapidjson::Value::ConstValueIterator f = features->value.Begin(); f != features->value.End(); ++f) {
275                         //it has to have geometry
276                         rapidjson::Value::ConstMemberIterator geom = f->FindMember("geometry");
277                         if(geom != f->MemberEnd()) {
278                                 //skip non-points
279                                 rapidjson::Value::ConstMemberIterator type = geom->value.FindMember("type");
280                                 if(type == geom->value.MemberEnd() || strcmp(type->value.GetString(), "Point"))
281                                         continue;
282                                 //get actual points
283                                 rapidjson::Value::ConstMemberIterator coords = geom->value.FindMember("coordinates");
284                                 if(coords == geom->value.MemberEnd() || !coords->value.IsArray() || coords->value.Size() != 2)
285                                         continue;
286
287                                 coords_s coordinate;
288                                 coordinate.longitude = coords->value[0].GetDouble();
289                                 coordinate.latitude = coords->value[1].GetDouble();
290
291                                 //get out the address information
292                                 rapidjson::Value::ConstMemberIterator properties = f->FindMember("properties");
293                                 if(properties != f->MemberEnd()) {
294                                         //fill this out as we go
295                                         mapzen_place_resp_s *respPlaces = (mapzen_place_resp_s *)g_malloc0(sizeof(mapzen_place_resp_s));
296                                         if (!respPlaces)
297                                                 return;
298
299                                         respPlaces->place_id = NULL;
300                                         respPlaces->categories = NULL;
301                                         respPlaces->display_name = NULL;
302                                         respPlaces->address = NULL;
303
304                                         bool something = false;
305                                         something = __get_string(properties->value, "gid", &respPlaces->place_id) || something;
306                                         something = __get_string(properties->value, "name", &respPlaces->display_name) || something;
307
308                                         respPlaces->address = (mapzen_address_resp_s *)g_malloc(sizeof(mapzen_address_resp_s));
309
310                                         something = __get_string(properties->value, "housenumber", &respPlaces->address->housenumber) || something;
311                                         something = __get_string(properties->value, "street", &respPlaces->address->street) || something;
312                                         something = __get_string(properties->value, "neighbourhood", &respPlaces->address->neighbourhood) || something;
313                                         something = __get_string(properties->value, "county", &respPlaces->address->county) || something;
314                                         something = __get_string(properties->value, "region", &respPlaces->address->region) || something;
315                                         something = __get_string(properties->value, "country", &respPlaces->address->country) || something;
316                                         something = __get_string(properties->value, "country_a", &respPlaces->address->country_a) || something;
317                                         something = __get_string(properties->value, "locality", &respPlaces->address->localadmin) || something;
318                                         something = __get_string(properties->value, "postalcode", &respPlaces->address->postalcode) || something;
319
320                                         respPlaces->coordinates = coordinate;
321
322                                         respPlaces->categories = NULL;
323                                         rapidjson::Value::ConstMemberIterator categories = properties->value.FindMember("category");
324                                         if (categories != geom->value.MemberEnd() && categories->value.IsArray()) {
325                                                 for (rapidjson::SizeType i = 0; i < categories->value.Size(); i++) {
326                                                         if (respPlaces->categories == NULL)
327                                                                 respPlaces->categories = g_list_append(respPlaces->categories, g_strdup(categories->value[i].GetString()));
328                                                         else
329                                                                 respPlaces->categories = g_list_insert_before(respPlaces->categories, NULL, g_strdup(categories->value[i].GetString()));
330                                                 }
331                                         }
332
333                                         if(!something) {
334                                                 g_free(respPlaces);
335                                                 respPlaces = NULL;
336                                         } else {
337                                                 if (*placeList == NULL)
338                                                         *placeList = g_list_append(*placeList, respPlaces);
339                                                 else
340                                                         *placeList = g_list_insert_before(*placeList, NULL, respPlaces);
341                                         }
342                                 }
343                         }
344                 }
345         }
346 }
347
348 /********************* ROUTE RESPONSE ***********************/
349
350 static void __process_shape(std::vector<coords_s>& decoded_shape, GList **shapePoints)
351 {
352         MAP_DEBUG(">>>>> START __process_shape");
353
354         for (auto& shape_pt : decoded_shape) {
355                 coords_s *coords = (coords_s *)g_malloc0(sizeof(coords_s));
356                 if (coords) {
357                         coords->latitude = shape_pt.latitude;
358                         coords->longitude = shape_pt.longitude;
359                         if ((*shapePoints) == NULL)
360                                 (*shapePoints) = g_list_append((*shapePoints), (gpointer)coords);
361                         else
362                                 (*shapePoints) = g_list_insert_before((*shapePoints), NULL, (gpointer)coords);
363         //              MAP_DEBUG(">>>>> PROCESS __process_shape: lat,lon=%f,%f", coords->latitude, coords->longitude);
364                 }
365         }
366         MAP_DEBUG(">>>>> END __process_shape");
367 }
368
369 static void __set_bounding_box(rapidjson::Value::ConstMemberIterator& summary, rectangle_s& bounding_box)
370 {
371         rapidjson::Value::ConstMemberIterator min_lat = summary->value.FindMember("min_lat");
372         rapidjson::Value::ConstMemberIterator min_lon = summary->value.FindMember("min_lon");
373         rapidjson::Value::ConstMemberIterator max_lat = summary->value.FindMember("max_lat");
374         rapidjson::Value::ConstMemberIterator max_lon = summary->value.FindMember("max_lon");
375         if ((min_lat != summary->value.MemberEnd())
376                         && (min_lon != summary->value.MemberEnd())
377                         && (max_lat != summary->value.MemberEnd())
378                         && (max_lon != summary->value.MemberEnd())) {
379                 bounding_box.top_left.latitude = max_lat->value.GetDouble();
380                 bounding_box.top_left.longitude = min_lon->value.GetDouble();
381                 bounding_box.bottom_right.latitude = min_lat->value.GetDouble();
382                 bounding_box.bottom_right.longitude = max_lon->value.GetDouble();
383         }
384 }
385
386 static void __parse_maneuvers(rapidjson::Value::ConstMemberIterator maneuvers, mapzen_route_segment *segment_resp, std::vector<coords_s>& segment_shape)
387 {
388         MAP_DEBUG(">>>>> START __parse_maneuvers");
389
390         rapidjson::Value::ConstMemberIterator begin_shape_index, end_shape_index, maneuver_time,
391                 maneuver_distance, type, travel_type, travel_mode, street_names_resp;
392         rapidjson::Value::ConstValueIterator street_name;
393
394         for (rapidjson::Value::ConstValueIterator maneuver =
395                         maneuvers->value.Begin(); maneuver != maneuvers->value.End();
396                         ++maneuver) {
397                 mapzen_route_maneuver *maneuver_resp = (mapzen_route_maneuver *)g_malloc(sizeof(mapzen_route_maneuver));
398
399
400                 // Set maneuver start point
401                 begin_shape_index = maneuver->FindMember("begin_shape_index");
402                 if (begin_shape_index != maneuver->MemberEnd()) {
403                         maneuver_resp->start_point = segment_shape.at(begin_shape_index->value.GetInt());
404                         MAP_DEBUG(">>>>> PROCESS __parse_maneuvers: maneuver_resp->start_point=%f,%f", maneuver_resp->start_point.latitude, maneuver_resp->start_point.longitude);
405                 }
406
407                 // Set maneuver end point
408                 end_shape_index = maneuver->FindMember("end_shape_index");
409                 if (end_shape_index != maneuver->MemberEnd()) {
410                         maneuver_resp->end_point = segment_shape.at(end_shape_index->value.GetInt());
411                         MAP_DEBUG(">>>>> PROCESS __parse_maneuvers: maneuver_resp->end_point=%f,%f", maneuver_resp->end_point.latitude, maneuver_resp->end_point.longitude);
412                 }
413
414                 // Set maneuver distance
415                 maneuver_distance = maneuver->FindMember("length");
416                 if (maneuver_distance != maneuver->MemberEnd()) {
417                         MAP_DEBUG(">>>>> __parse_maneuvers: PROCESS maneuver_distance: %f", maneuver_distance->value.GetDouble());
418                         maneuver_resp->distance = maneuver_distance->value.GetDouble();
419                 }
420
421                 // Set maneuver time
422                 maneuver_time = maneuver->FindMember("time");
423                 if (maneuver_time != maneuver->MemberEnd()) {
424                         MAP_DEBUG(">>>>> __parse_maneuvers: PROCESS maneuver_time: %d", maneuver_time->value.GetInt());
425                         maneuver_resp->time = maneuver_time->value.GetInt();
426                 }
427
428                 // Set maneuver type
429                 type = maneuver->FindMember("type");
430                 if (type != maneuver->MemberEnd()) {
431                         maneuver_resp->type = convert_int_to_mapzen_maneuver_type(type->value.GetInt());
432                         MAP_DEBUG(">>>>> PROCESS __parse_maneuvers: type=%d", maneuver_resp->type);
433                 }
434
435                 // Set maneuver instruction
436                 __get_string((*maneuver), "instruction", &maneuver_resp->instruction);
437
438                 // Set maneuver street names
439                 maneuver_resp->street_name = NULL;
440                 street_names_resp = maneuver->FindMember("street_names");
441                 if (street_names_resp != maneuver->MemberEnd() && street_names_resp->value.IsArray()) {
442                         std::string street_name;
443
444                         for (rapidjson::Value::ConstValueIterator street_name_resp = street_names_resp->value.Begin();
445                                         street_name_resp != street_names_resp->value.End(); ++street_name_resp) {
446                                 street_name += std::string(street_name.size()? "/": "");
447                                 street_name += street_name_resp->GetString();
448                         }
449
450                         if (street_name.size() > 0) {
451                                 MAP_DEBUG(">>>>> PROCESS __parse_maneuvers: street_name=%s", street_name.c_str());
452                                 maneuver_resp->street_name = (gchar *)g_malloc0(street_name.size() + 1);
453                                 if (maneuver_resp->street_name) {
454                                         strncpy (maneuver_resp->street_name, street_name.c_str(), sizeof(gchar) * street_name.size());
455                                         MAP_DEBUG(">>>>> PROCESS __parse_maneuvers: maneuver_resp->street_name=%s", maneuver_resp->street_name);
456                                 }
457                         }
458                 }
459
460                 // Append maneuver to maneuver list
461                 if (segment_resp->maneuvers == NULL) {
462                         MAP_DEBUG(">>>>> __parse_route_response: PROCESS segment_resp->maneuvers == NULL) - append");
463                         segment_resp->maneuvers = g_list_append(segment_resp->maneuvers, (gpointer)maneuver_resp);
464                 } else {
465                         MAP_DEBUG(">>>>> __parse_route_response: PROCESS segment_resp->maneuvers != NULL) - insert before");
466                         segment_resp->maneuvers = g_list_insert_before(segment_resp->maneuvers, NULL, (gpointer)maneuver_resp);
467                 }
468         } // end process each maneuver
469
470         MAP_DEBUG(">>>>> END __parse_maneuvers");
471 }
472
473 static bool __determine_segment_origin_destination(const rapidjson::Value& locations,
474                 rapidjson::SizeType& location_index, coords_s& origin,
475                 coords_s& destination) {
476         bool origin_set = false;
477         bool destination_set = false;
478
479         // Set origin
480         for (rapidjson::SizeType i = location_index; i < locations.Size(); i++) {
481                 auto& location = locations[i];
482                 if (location["type"] == "break") {
483                         origin.latitude = location["lat"].GetDouble();
484                         origin.longitude = location["lon"].GetDouble();
485                         origin_set = true;
486                         // Increment location index to find segment destination
487                         location_index = ++i;
488                         break;
489                 }
490         }
491
492         // Set destination
493         for (rapidjson::SizeType i = location_index; i < locations.Size(); i++) {
494                 auto& location = locations[i];
495                 if (location["type"] == "break") {
496                         destination.latitude = location["lat"].GetDouble();
497                         destination.longitude = location["lon"].GetDouble();
498                         destination_set = true;
499                         // Assign location index for next segment origin
500                         location_index = i;
501                         break;
502                 }
503         }
504
505         // Validate that both origin and destination are set
506         if (origin_set and destination_set) {
507                 return true;
508         }
509
510         return false;
511 }
512
513 static void __parse_route_response(char *response, int size, int *status, mapzen_route_resp_s **routeResp) {
514         MAP_DEBUG(">>>>> START __parse_route_response");
515
516         if (!response || !status || !routeResp)
517                 return;
518         *routeResp = NULL;
519         MAP_DEBUG(">>>>> PROCESS __parse_route_response: ROUTE RESPONSE returned=%s", response);
520
521         rapidjson::Document document;
522         document.Parse(std::string(response, size).c_str());
523         rapidjson::Value::MemberIterator trip = document.FindMember("trip");
524         if (trip == document.MemberEnd()) {
525                 MAP_DEBUG(">>>>> PROCESS __parse_route_response: trip object not found in response");
526                 return;
527         }
528
529         // Process status
530         rapidjson::Value::ConstMemberIterator trip_status = trip->value.FindMember("status");
531         if (trip_status != trip->value.MemberEnd()) {
532                 *status = trip_status->value.GetInt();
533                 MAP_DEBUG(">>>>> PROCESS __parse_route_response: trip_status=%d", *status);
534         }
535         if (*status != 0) {
536                 MAP_DEBUG(">>>>> PROCESS __parse_route_response: invalid status in response");
537                 return;
538         }
539
540         // Create route response object and initialize lists to NULL
541         *routeResp = (mapzen_route_resp_s *) g_malloc(sizeof(mapzen_route_resp_s));
542         if (!(*routeResp))
543                 return;
544         (*routeResp)->segments = NULL;
545         (*routeResp)->shapePoints = NULL;
546
547         // Get trip locations
548         rapidjson::SizeType location_index = 0;
549         rapidjson::Value& locations = trip->value["locations"];
550         MAP_DEBUG(">>>>> PROCESS __parse_route_response: locations.Size(): %d", locations.Size());
551
552         // Set trip origin
553         rapidjson::Value& mapzen_origin = locations[0];
554         (*routeResp)->origin.latitude = mapzen_origin["lat"].GetDouble();
555         (*routeResp)->origin.longitude = mapzen_origin["lon"].GetDouble();
556         MAP_DEBUG(">>>>> PROCESS __parse_route_response: trip origin: %f,%f", (*routeResp)->origin.latitude, (*routeResp)->origin.longitude);
557
558         // Set trip destination
559         rapidjson::Value& mapzen_destination = locations[locations.Size()-1];
560         (*routeResp)->destination.latitude = mapzen_destination["lat"].GetDouble();
561         (*routeResp)->destination.longitude = mapzen_destination["lon"].GetDouble();
562         MAP_DEBUG(">>>>> PROCESS __parse_route_response: trip destination: %f,%f", (*routeResp)->destination.latitude, (*routeResp)->destination.longitude);
563
564         // Set language
565     __get_string(trip->value, "language", &(*routeResp)->language);
566
567         // Set distance units
568     // TODO maybe just read units from response and set value
569         (*routeResp)->distance_unit = __route_unit;
570         MAP_DEBUG(">>>>> PROCESS __parse_route_response: distance_unit=%d", (*routeResp)->distance_unit);
571
572         // Process trip summary
573         rapidjson::Value::ConstMemberIterator trip_summary = trip->value.FindMember("summary");
574         if (trip_summary != trip->value.MemberEnd()) {
575                 // Set trip distance
576                 rapidjson::Value::ConstMemberIterator trip_distance = trip_summary->value.FindMember("length");
577                 if (trip_distance != trip_summary->value.MemberEnd()) {
578                         (*routeResp)->distance = trip_distance->value.GetDouble();
579                         MAP_DEBUG(">>>>> PROCESS __parse_route_response: trip length : %f", (*routeResp)->distance);
580                 }
581
582                 // Set trip time
583                 rapidjson::Value::ConstMemberIterator trip_time = trip_summary->value.FindMember("time");
584                 if (trip_time != trip_summary->value.MemberEnd()) {
585                         (*routeResp)->time = trip_time->value.GetInt();
586                         MAP_DEBUG(">>>>> PROCESS __parse_route_response: trip time: %d", trip_time->value.GetInt());
587                 }
588
589                 // Set trip bounding box
590                 __set_bounding_box(trip_summary, (*routeResp)->bounding_box);
591                 MAP_DEBUG(">>>>> PROCESS __parse_route_response: trip_bounding_box.top_left =%f,%f", (*routeResp)->bounding_box.top_left.latitude, (*routeResp)->bounding_box.top_left.longitude);
592                 MAP_DEBUG(">>>>> PROCESS __parse_route_response: trip_bounding_box.bottom_right =%f,%f", (*routeResp)->bounding_box.bottom_right.latitude, (*routeResp)->bounding_box.bottom_right.longitude);
593         }
594
595         // Type
596         (*routeResp)->type = __route_type;
597         MAP_DEBUG(">>>>> PROCESS __parse_route_response: route_type=%d", (*routeResp)->type);
598
599         ///////////////////////////////////////////////////////////////////////////
600         // Process segments (legs)
601         rapidjson::Value::MemberIterator legs = trip->value.FindMember("legs");
602         if (legs == trip->value.MemberEnd() || !legs->value.IsArray()) {
603                 MAP_DEBUG(">>>>> PROCESS __parse_route_response: invalid legs in response");
604                 return;
605         }
606         for (rapidjson::Value::ConstValueIterator leg = legs->value.Begin(); leg != legs->value.End(); ++leg) {
607                 // Determine segment origin and destination
608                 coords_s segment_origin;
609                 coords_s segment_destination;
610                 if (!__determine_segment_origin_destination(locations, location_index, segment_origin, segment_destination)) {
611                         MAP_DEBUG(">>>>> PROCESS __parse_route_response: invalid segment origin and destination");
612                         return;
613                 }
614
615                 // Create segment response
616                 mapzen_route_segment *segment_resp = (mapzen_route_segment *)g_malloc(sizeof(mapzen_route_segment));
617                 segment_resp->maneuvers = NULL;
618                 segment_resp->shapePoints = NULL;
619
620                 // Set segment origin
621                 segment_resp->origin = segment_origin;
622                 MAP_DEBUG(">>>>> PROCESS __parse_route_response: segment_origin: %f,%f", segment_origin.latitude, segment_origin.longitude);
623
624                 // Set segment destination
625                 segment_resp->destination = segment_destination;
626                 MAP_DEBUG(">>>>> PROCESS __parse_route_response: segment_destination: %f,%f", segment_destination.latitude, segment_destination.longitude);
627
628                 // Process segment summary
629                 rapidjson::Value::ConstMemberIterator leg_summary = leg->FindMember("summary");
630                 if (leg_summary != leg->MemberEnd()) {
631                         // Set segment distance
632                         rapidjson::Value::ConstMemberIterator leg_distance = leg_summary->value.FindMember("length");
633                         if (leg_distance != leg_summary->value.MemberEnd()) {
634                                 segment_resp->distance = leg_distance->value.GetDouble();
635                                 MAP_DEBUG(">>>>> PROCESS __parse_route_response: leg length=%f", segment_resp->distance);
636                         }
637
638                         // Set segment time
639                         rapidjson::Value::ConstMemberIterator leg_time = leg_summary->value.FindMember("time");
640                         if (leg_time != leg_summary->value.MemberEnd()) {
641                                 segment_resp->time = leg_time->value.GetInt();
642                                 MAP_DEBUG(">>>>> PROCESS __parse_route_response: leg time=%d", segment_resp->time);
643                         }
644
645                         // Set segment bounding box
646                         __set_bounding_box(leg_summary, segment_resp->bounding_box);
647                         MAP_DEBUG(">>>>> PROCESS __parse_route_response: segment_bounding_box.top_left =%f,%f", segment_resp->bounding_box.top_left.latitude, segment_resp->bounding_box.top_left.longitude);
648                         MAP_DEBUG(">>>>> PROCESS __parse_route_response: segment_bounding_box.bottom_right =%f,%f", segment_resp->bounding_box.bottom_right.latitude, segment_resp->bounding_box.bottom_right.longitude);
649                 }
650
651                 // Get segment encoded shape and decode
652                 auto encoded_shape = leg->FindMember("shape");
653                 MAP_DEBUG(">>>>> PROCESS __parse_route_response: ENCODED SHAPE=%s", encoded_shape->value.GetString());
654                 std::vector<coords_s> decoded_shape;
655                 decode_shape(encoded_shape->value.GetString(), decoded_shape);
656                 MAP_DEBUG(">>>>> PROCESS __parse_route_response: Segment shape point count=%d", decoded_shape.size());
657
658                 // Append shape for route trip and segment
659                 // TODO - optimize/improve
660                 // TODO - duplicated points between route trip and segments
661                 // TODO - currently no generalization - test application has 500 point limit
662                 MAP_DEBUG(">>>>> PROCESS __parse_route_response: PRE __process_shape");
663                 __process_shape(decoded_shape, &((*routeResp)->shapePoints));
664                 __process_shape(decoded_shape, &(segment_resp->shapePoints));
665                 MAP_DEBUG(">>>>> PROCESS __parse_route_response: POST __process_shape");
666
667                 rapidjson::Value::ConstMemberIterator maneuvers = leg->FindMember("maneuvers");
668                 if (maneuvers == leg->MemberEnd() || !maneuvers->value.IsArray()) {
669                         g_free(segment_resp);
670                         return;
671                 }
672
673                 ///////////////////////////////////////////////////////////////////////
674                 // Process each maneuver
675                 MAP_DEBUG(">>>>> PROCESS __parse_route_response: PRE __parse_maneuvers");
676                 __parse_maneuvers(maneuvers, segment_resp, decoded_shape);
677                 MAP_DEBUG(">>>>> PROCESS __parse_route_response: POST __parse_maneuvers");
678                 ///////////////////////////////////////////////////////////////////////
679
680                 // Add segment to segment list
681                 if ((*routeResp)->segments == NULL) {
682                         MAP_DEBUG(">>>>> PROCESS __parse_route_response: (*routeResp)->maneuvers == NULL) - append");
683                         (*routeResp)->segments = g_list_append((*routeResp)->segments, (gpointer)segment_resp);
684                 } else {
685                         MAP_DEBUG(">>>>> PROCESS __parse_route_response: (*routeResp)->maneuvers != NULL) - insert before");
686                         (*routeResp)->segments = g_list_insert_before((*routeResp)->segments, NULL, (gpointer)segment_resp);
687                 }
688         } // end process each leg
689         ///////////////////////////////////////////////////////////////////////////
690
691         MAP_DEBUG(">>>>> END __parse_route_response");
692 }
693
694 void post_curl_response(char *response, int size, mapzen_resp_type type, void *user_data)
695 {
696         MAP_DEBUG(">>>>> START post_curl_response");
697         if (!response) return;
698
699         if (!user_data) {
700                 MAP_DEBUG("Response data is NULL");
701                 return;
702         }
703
704         MAP_DEBUG("Response received from Curl. [Size=%d]", size);
705         switch (type) {
706         case RESP_TYPE_GEOCODE:
707                 {
708                         MAP_DEBUG("Inside Geocode JSON Parsing..");
709                         int status = -1;
710                         MapzenGeocodeQueryData *queryData = (MapzenGeocodeQueryData *)user_data;
711                         MapzenGeocodeResponseData *responseData = (MapzenGeocodeResponseData *)g_malloc(sizeof(MapzenGeocodeResponseData));
712
713                         if (responseData) {
714                                 responseData->requestId = queryData->requestId;
715                                 responseData->geocode_cb = queryData->geocode_cb;
716                                 responseData->user_data = queryData->user_data;
717
718                                 if (response && (size > 0)) {
719                                         GList *coordsList = NULL;
720                                         __parse_geocode_response(response, size, &status, &coordsList);
721
722                                         if (coordsList != NULL) {
723                                                 /* Put the response in queue */
724                                                 responseData->error = __convert_status(status);
725                                                 responseData->coords = coordsList;
726                                         } else {
727                                                 /* Response parsing failure */
728                                                 responseData->error = __convert_status(status);
729                                                 responseData->coords = NULL;
730                                         }
731                                 } else {
732                                         responseData->error = __convert_status(status);
733                                         responseData->coords = NULL;
734                                 }
735
736                                 mapzen_push_to_queue(type, (gpointer)responseData);
737                         }
738
739                         if (queryData) {
740                                 g_free(queryData);
741                                 queryData = NULL;
742                         }
743                         break;
744                 }
745         case RESP_TYPE_REVGEOCODE:
746                 {
747                         MAP_DEBUG("Inside Rev Geocode JSON Parsing..");
748                         int status = -1;
749                         MapzenRevGeocodeQueryData *queryData = (MapzenRevGeocodeQueryData *)user_data;
750                         MapzenRevGeocodeResponseData *responseData = (MapzenRevGeocodeResponseData *)g_malloc(sizeof(MapzenRevGeocodeResponseData));
751
752                         if (responseData) {
753                                 responseData->requestId = queryData->requestId;
754                                 responseData->reverse_geocode_cb = queryData->reverse_geocode_cb;
755                                 responseData->user_data = queryData->user_data;
756
757                                 if (response && (size > 0)) {
758                                         /* Coords Result GList */
759                                         mapzen_address_resp_s *addrResponse = NULL;
760
761                                         MAP_DEBUG("Rev Geocode :- Parsing json Response");
762                                         __parse_revgeocode_response(response, size, &status, &addrResponse);
763
764                                         if (addrResponse != NULL) {
765                                                 /* Put the response in queue */
766                                                 responseData->error = __convert_status(status);
767                                                 responseData->addressDetails = addrResponse;
768                                         } else {
769                                                 /* REPSONSE PARSING FAILURE */
770                                                 MAP_DEBUG("addr Response is NULL");
771                                                 responseData->error = __convert_status(status);
772                                                 responseData->addressDetails = NULL;
773                                         }
774                                 } else {
775                                         MAP_DEBUG("JSON Response is NULL..");
776                                         responseData->error = __convert_status(status);
777                                         responseData->addressDetails = NULL;
778                                 }
779                                 mapzen_push_to_queue(type, (gpointer)responseData);
780                         }
781
782                         if (queryData) {
783                                 g_free(queryData);
784                                 queryData = NULL;
785                         }
786                         break;
787                 }
788         case RESP_TYPE_PLACES:
789                 {
790                         MAP_DEBUG("Inside Places JSON Parsing..");
791                         MapzenPlaceQueryData *queryData = (MapzenPlaceQueryData *)user_data;
792                         MapzenPlaceResponseData *responseData = (MapzenPlaceResponseData *)g_malloc(sizeof(MapzenPlaceResponseData));
793
794                         if (responseData) {
795                                 responseData->requestId = queryData->requestId;
796                                 responseData->place_search_cb = queryData->place_search_cb;
797                                 responseData->user_data = queryData->user_data;
798
799                                 if (response && (size > 0)) {
800                                         /* Coords Result GList */
801                                         GList *placeList = NULL;
802
803                                         MAP_DEBUG("Search Places :- Parsing Json Response");
804                                         __parse_place_response(response, size, &placeList);
805
806                                         if (placeList != NULL) {
807                                                 /* Put the response in queue */
808                                                 responseData->error = MAPZEN_ERROR_NONE;
809                                                 responseData->places = placeList;
810                                         } else {
811                                                 /* REPSONSE PARSING FAILURE */
812                                                 MAP_DEBUG("addr Response is NULL");
813                                                 responseData->error = MAPZEN_ERROR_UNKNOWN;
814                                                 responseData->places = NULL;
815                                         }
816                                 } else {
817                                         responseData->error = MAPZEN_ERROR_UNKNOWN;
818                                         responseData->places = NULL;
819                                 }
820
821                                 mapzen_push_to_queue(type, (gpointer)responseData);
822                         }
823
824                         if (queryData) {
825                                 g_free(queryData);
826                                 queryData = NULL;
827                         }
828
829                         break;
830                 }
831         case RESP_TYPE_PLACES_DETAILS:
832                 {
833                         MAP_DEBUG("Inside Places Details JSON Parsing..");
834                         MapzenPlaceDetailsQueryData *queryData = (MapzenPlaceDetailsQueryData *)user_data;
835                         MapzenPlaceDetailsResponseData *responseData = (MapzenPlaceDetailsResponseData *)g_malloc(sizeof(MapzenPlaceDetailsResponseData));
836
837                         if (responseData) {
838                                 responseData->requestId = queryData->requestId;
839                                 responseData->get_place_details_cb = queryData->get_place_details_cb;
840                                 responseData->user_data = queryData->user_data;
841
842                                 if (response && (size > 0)) {
843                                         /* Coords Result GList */
844                                         GList *placeList = NULL;
845
846                                         MAP_DEBUG("Search Places Details :- Parsing Json Response");
847                                         __parse_place_response(response, size, &placeList);
848
849                                         if (placeList != NULL) {
850                                                 /* Put the response in queue */
851                                                 responseData->error = MAPZEN_ERROR_NONE;
852                                                 responseData->places = placeList;
853                                         } else {
854                                                 /* REPSONSE PARSING FAILURE */
855                                                 MAP_DEBUG("addr Response is NULL");
856                                                 responseData->error = MAPZEN_ERROR_UNKNOWN;
857                                                 responseData->places = NULL;
858                                         }
859                                 } else {
860                                         responseData->error = MAPZEN_ERROR_UNKNOWN;
861                                         responseData->places = NULL;
862                                 }
863
864                                 mapzen_push_to_queue(type, (gpointer)responseData);
865                         }
866
867                         if (queryData) {
868                                 g_free(queryData);
869                                 queryData = NULL;
870                         }
871
872                         break;
873                 }
874         case RESP_TYPE_PLACES_LIST:
875                 {
876                         MAP_DEBUG("Inside Places List JSON Parsing..");
877                         MapzenPlaceListQueryData *queryData = (MapzenPlaceListQueryData *)user_data;
878                         MapzenPlaceListResponseData *responseData = (MapzenPlaceListResponseData *)g_malloc(sizeof(MapzenPlaceListResponseData));
879
880                         if (responseData) {
881                                 responseData->requestId = queryData->requestId;
882                                 responseData->place_list_search_cb = queryData->place_list_search_cb;
883                                 responseData->user_data = queryData->user_data;
884
885                                 if (response && (size > 0)) {
886                                         /* Coords Result GList */
887                                         GList *placeList = NULL;
888
889                                         MAP_DEBUG("Search Places :- Parsing Json Response");
890                                         __parse_place_response(response, size, &placeList);
891
892                                         if (placeList != NULL) {
893                                                 /* Put the response in queue */
894                                                 responseData->error = MAPZEN_ERROR_NONE;
895                                                 responseData->places = placeList;
896                                         } else {
897                                                 /* REPSONSE PARSING FAILURE */
898                                                 MAP_DEBUG("addr Response is NULL");
899                                                 responseData->error = MAPZEN_ERROR_UNKNOWN;
900                                                 responseData->places = NULL;
901                                         }
902                                 } else {
903                                         responseData->error = MAPZEN_ERROR_UNKNOWN;
904                                         responseData->places = NULL;
905                                 }
906
907                                 mapzen_push_to_queue(type, (gpointer)responseData);
908                         }
909
910                         if (queryData) {
911                                 g_free(queryData);
912                                 queryData = NULL;
913                         }
914
915                         break;
916                 }
917         case RESP_TYPE_ROUTE:
918         {
919                 MAP_DEBUG(">>>>> RESP_TYPE_ROUTE");
920                 int status = -1;
921                 MapzenRouteQueryData *queryData = (MapzenRouteQueryData *)user_data;
922                 MAP_DEBUG(">>>>> PROCESS post_curl_response set the following: __route_unit and __route_type");
923                 __route_unit = queryData->unit;
924                 __route_type = queryData->type;
925                 MAP_DEBUG(">>>>> PROCESS post_curl_response __route_unit=%d", __route_unit);
926                 MAP_DEBUG(">>>>> PROCESS post_curl_response __route_type=%d", __route_type);
927
928                 MAP_DEBUG(">>>>> PROCESS post_curl_response: prepare MapzenRouteResponseData");
929                 MapzenRouteResponseData *responseData = (MapzenRouteResponseData *)g_malloc(sizeof(MapzenRouteResponseData));
930
931                 if (responseData) {
932                         responseData->requestId = queryData->requestId;
933                         responseData->route_cb = queryData->route_cb;
934                         responseData->user_data = queryData->user_data;
935
936                         if (response && (size > 0)) {
937                                 /* Coords Result GList */
938                                 mapzen_route_resp_s *routeResponse = NULL;
939
940                                 MAP_DEBUG(">>>>> PROCESS post_curl_response: PRE __parse_route_response");
941                                 __parse_route_response(response, size, &status, &routeResponse);
942                                 MAP_DEBUG(">>>>> PROCESS post_curl_response: POST __parse_route_response");
943
944                                 if (routeResponse != NULL) {
945                                         MAP_DEBUG(">>>>> PROCESS post_curl_response: (routeResponse != NULL)");
946                                         MAP_DEBUG(">>>>> PROCESS post_curl_response: status=%d", status);
947                                         MAP_DEBUG(">>>>> PROCESS post_curl_response: __convert_status(status)=%d", __convert_status(status));
948                                         /* Put the response in queue */
949                                         responseData->error = __convert_status(status);
950                                         responseData->routeResponse = routeResponse;
951                                 } else {
952                                         /* REPSONSE PARSING FAILURE */
953                                         MAP_DEBUG(">>>>> PROCESS post_curl_response: routeResponse is NULL");
954                                         responseData->error = __convert_status(status);
955                                         responseData->routeResponse = NULL;
956                                 }
957                         } else {
958                                 MAP_DEBUG(">>>>> PROCESS post_curl_response: JSON response is NULL");
959                                 responseData->error = __convert_status(status);
960                                 responseData->routeResponse = NULL;
961                         }
962
963                         MAP_DEBUG(">>>>> PROCESS post_curl_response: PRE mapzen_push_to_queue");
964                         mapzen_push_to_queue(type, (gpointer)responseData);
965                         MAP_DEBUG(">>>>> PROCESS post_curl_response: POST mapzen_push_to_queue");
966                 }
967
968                 if (queryData) {
969                         g_free(queryData);
970                         queryData = NULL;
971                 }
972
973                 break;
974         }
975         default:
976                 {
977                         MAP_DEBUG("Inside default JSON Parsing..");
978                         break;
979                 }
980         }
981         MAP_DEBUG(">>>>> END post_curl_response");
982 }
983
984 #ifdef __cplusplus
985 }
986 #endif