2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4 * Copyright (c) 2013, Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * SECTION:vikroutingwebengine
24 * @short_description: A generic class for WEB based routing engine
26 * The #VikRoutingWebEngine class handles WEB based
37 #include <glib/gstdio.h>
41 #include "vikroutingwebengine.h"
43 static void vik_routing_web_engine_finalize ( GObject *gob );
45 static int vik_routing_web_engine_find ( VikRoutingEngine *self, VikTrwLayer *vtl, struct LatLon start, struct LatLon end );
46 static gchar *vik_routing_web_engine_get_cmd_from_directions(VikRoutingEngine *self, const gchar *start, const gchar *end);
47 static gboolean vik_routing_web_engine_supports_direction(VikRoutingEngine *self);
48 static int vik_routing_web_engine_refine ( VikRoutingEngine *self, VikTrwLayer *vtl, VikTrack *vt );
49 static gboolean vik_routing_web_engine_supports_refine ( VikRoutingEngine *self );
51 typedef struct _VikRoutingWebEnginePrivate VikRoutingWebEnginePrivate;
52 struct _VikRoutingWebEnginePrivate
57 gchar *url_start_ll_fmt;
58 gchar *url_stop_ll_fmt;
59 gchar *url_via_ll_fmt;
62 gchar *url_start_dir_fmt;
63 gchar *url_stop_dir_fmt;
65 DownloadMapOptions options;
68 #define VIK_ROUTING_WEB_ENGINE_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), VIK_ROUTING_WEB_ENGINE_TYPE, VikRoutingWebEnginePrivate))
90 G_DEFINE_TYPE (VikRoutingWebEngine, vik_routing_web_engine, VIK_ROUTING_ENGINE_TYPE)
93 vik_routing_web_engine_set_property (GObject *object,
98 VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( object );
103 g_free (priv->url_base);
104 priv->url_base = g_strdup(g_value_get_string (value));
107 case PROP_URL_START_LL:
108 g_free (priv->url_start_ll_fmt);
109 priv->url_start_ll_fmt = g_strdup(g_value_get_string (value));
112 case PROP_URL_STOP_LL:
113 g_free (priv->url_stop_ll_fmt);
114 priv->url_stop_ll_fmt = g_strdup(g_value_get_string (value));
117 case PROP_URL_VIA_LL:
118 g_free (priv->url_via_ll_fmt);
119 priv->url_via_ll_fmt = g_strdup(g_value_get_string (value));
122 case PROP_URL_START_DIR:
123 g_free (priv->url_start_dir_fmt);
124 priv->url_start_dir_fmt = g_strdup(g_value_get_string (value));
127 case PROP_URL_STOP_DIR:
128 g_free (priv->url_stop_dir_fmt);
129 priv->url_stop_dir_fmt = g_strdup(g_value_get_string (value));
133 g_free (priv->options.referer);
134 priv->options.referer = g_value_dup_string (value);
137 case PROP_FOLLOW_LOCATION:
138 priv->options.follow_location = g_value_get_long (value);
142 /* We don't have any other property... */
143 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
149 vik_routing_web_engine_get_property (GObject *object,
154 VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( object );
159 g_value_set_string (value, priv->url_base);
162 case PROP_URL_START_LL:
163 g_value_set_string (value, priv->url_start_ll_fmt);
166 case PROP_URL_STOP_LL:
167 g_value_set_string (value, priv->url_stop_ll_fmt);
170 case PROP_URL_VIA_LL:
171 g_value_set_string (value, priv->url_via_ll_fmt);
174 case PROP_URL_START_DIR:
175 g_value_set_string (value, priv->url_start_dir_fmt);
178 case PROP_URL_STOP_DIR:
179 g_value_set_string (value, priv->url_stop_dir_fmt);
183 g_value_set_string (value, priv->options.referer);
186 case PROP_FOLLOW_LOCATION:
187 g_value_set_long (value, priv->options.follow_location);
191 /* We don't have any other property... */
192 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
197 static void vik_routing_web_engine_class_init ( VikRoutingWebEngineClass *klass )
199 GObjectClass *object_class;
200 VikRoutingEngineClass *parent_class;
201 GParamSpec *pspec = NULL;
203 object_class = G_OBJECT_CLASS (klass);
205 object_class->set_property = vik_routing_web_engine_set_property;
206 object_class->get_property = vik_routing_web_engine_get_property;
207 object_class->finalize = vik_routing_web_engine_finalize;
209 parent_class = VIK_ROUTING_ENGINE_CLASS (klass);
211 parent_class->find = vik_routing_web_engine_find;
212 parent_class->supports_direction = vik_routing_web_engine_supports_direction;
213 parent_class->get_cmd_from_directions = vik_routing_web_engine_get_cmd_from_directions;
214 parent_class->refine = vik_routing_web_engine_refine;
215 parent_class->supports_refine = vik_routing_web_engine_supports_refine;
218 * VikRoutingWebEngine:url-base:
220 * The base URL of the routing engine.
222 pspec = g_param_spec_string ("url-base",
224 "The base URL of the routing engine",
225 "<no-set>" /* default value */,
226 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
227 g_object_class_install_property (object_class, PROP_URL_BASE, pspec);
231 * VikRoutingWebEngine:url-start-ll:
233 * The part of the request hosting the end point.
235 pspec = g_param_spec_string ("url-start-ll",
236 "Start part of the URL",
237 "The part of the request hosting the start point",
238 "<no-set>" /* default value */,
239 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
240 g_object_class_install_property (object_class, PROP_URL_START_LL, pspec);
244 * VikRoutingWebEngine:url-stop-ll:
246 * The part of the request hosting the end point.
248 pspec = g_param_spec_string ("url-stop-ll",
249 "Stop part of the URL",
250 "The part of the request hosting the end point",
251 "<no-set>" /* default value */,
252 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
253 g_object_class_install_property (object_class, PROP_URL_STOP_LL, pspec);
257 * VikRoutingWebEngine:url-via-ll:
259 * The param of the request for setting a via point.
261 pspec = g_param_spec_string ("url-via-ll",
262 "Via part of the URL",
263 "The param of the request for setting a via point",
264 NULL /* default value */,
265 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
266 g_object_class_install_property (object_class, PROP_URL_VIA_LL, pspec);
270 * VikRoutingWebEngine:url-start-dir:
272 * The part of the request hosting the end point.
274 pspec = g_param_spec_string ("url-start-dir",
275 "Start part of the URL",
276 "The part of the request hosting the start point",
277 NULL /* default value */,
278 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
279 g_object_class_install_property (object_class, PROP_URL_START_DIR, pspec);
283 * VikRoutingWebEngine:url-stop-dir:
285 * The part of the request hosting the end point.
287 pspec = g_param_spec_string ("url-stop-dir",
288 "Stop part of the URL",
289 "The part of the request hosting the end point",
290 NULL /* default value */,
291 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
292 g_object_class_install_property (object_class, PROP_URL_STOP_DIR, pspec);
296 * VikRoutingWebEngine:referer:
298 * The REFERER string to use in HTTP request.
300 pspec = g_param_spec_string ("referer",
302 "The REFERER string to use in HTTP request",
303 NULL /* default value */,
304 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
305 g_object_class_install_property (object_class, PROP_REFERER, pspec);
309 * VikRoutingWebEngine:follow-location:
311 * Specifies the number of retries to follow a redirect while downloading a page.
313 pspec = g_param_spec_long ("follow-location",
315 "Specifies the number of retries to follow a redirect while downloading a page",
316 0 /* minimum value */,
317 G_MAXLONG /* maximum value */,
318 0 /* default value */,
319 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
320 g_object_class_install_property (object_class, PROP_FOLLOW_LOCATION, pspec);
322 g_type_class_add_private (klass, sizeof (VikRoutingWebEnginePrivate));
325 static void vik_routing_web_engine_init ( VikRoutingWebEngine *self )
327 VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( self );
329 priv->url_base = NULL;
332 priv->url_start_ll_fmt = NULL;
333 priv->url_stop_ll_fmt = NULL;
334 priv->url_via_ll_fmt = NULL;
337 priv->url_start_dir_fmt = NULL;
338 priv->url_stop_dir_fmt = NULL;
340 priv->options.referer = NULL;
341 priv->options.follow_location = 0;
342 priv->options.check_file = NULL;
343 priv->options.check_file_server_time = FALSE;
344 priv->options.use_etag = FALSE;
347 static void vik_routing_web_engine_finalize ( GObject *gob )
349 VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( gob );
351 g_free (priv->url_base);
352 priv->url_base = NULL;
355 g_free (priv->url_start_ll_fmt);
356 priv->url_start_ll_fmt = NULL;
357 g_free (priv->url_stop_ll_fmt);
358 priv->url_stop_ll_fmt = NULL;
359 g_free (priv->url_via_ll_fmt);
360 priv->url_via_ll_fmt = NULL;
363 g_free (priv->url_start_dir_fmt);
364 priv->url_start_dir_fmt = NULL;
365 g_free (priv->url_stop_dir_fmt);
366 priv->url_stop_dir_fmt = NULL;
368 g_free (priv->options.referer);
369 priv->options.referer = NULL;
371 G_OBJECT_CLASS (vik_routing_web_engine_parent_class)->finalize(gob);
374 static DownloadMapOptions *
375 vik_routing_web_engine_get_download_options ( VikRoutingEngine *self )
377 g_return_val_if_fail (VIK_IS_ROUTING_WEB_ENGINE(self), NULL);
379 VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE(self);
381 return &(priv->options);
385 substitute_latlon ( const gchar *fmt, struct LatLon ll )
387 gchar lat[G_ASCII_DTOSTR_BUF_SIZE], lon[G_ASCII_DTOSTR_BUF_SIZE];
388 gchar *substituted = g_strdup_printf(fmt,
389 g_ascii_dtostr (lat, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) ll.lat),
390 g_ascii_dtostr (lon, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) ll.lon));
395 vik_routing_web_engine_get_url_for_coords ( VikRoutingEngine *self, struct LatLon start, struct LatLon end )
401 g_return_val_if_fail ( VIK_IS_ROUTING_WEB_ENGINE (self), NULL);
403 VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( self );
405 g_return_val_if_fail ( priv->url_base != NULL, NULL);
406 g_return_val_if_fail ( priv->url_start_ll_fmt != NULL, NULL);
407 g_return_val_if_fail ( priv->url_stop_ll_fmt != NULL, NULL);
409 startURL = substitute_latlon ( priv->url_start_ll_fmt, start );
410 endURL = substitute_latlon ( priv->url_stop_ll_fmt, end );
411 url = g_strconcat ( priv->url_base, startURL, endURL, NULL );
421 vik_routing_web_engine_find ( VikRoutingEngine *self, VikTrwLayer *vtl, struct LatLon start, struct LatLon end )
424 int ret = 0; /* OK */
426 uri = vik_routing_web_engine_get_url_for_coords(self, start, end);
428 DownloadMapOptions *options = vik_routing_web_engine_get_download_options(self);
430 gchar *format = vik_routing_engine_get_format ( self );
431 a_babel_convert_from_url ( vtl, uri, format, NULL, NULL, options );
439 vik_routing_web_engine_get_cmd_from_directions ( VikRoutingEngine *self, const gchar *start, const gchar *end )
441 g_return_val_if_fail ( VIK_IS_ROUTING_WEB_ENGINE (self), NULL);
443 VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( self );
445 g_return_val_if_fail ( priv->url_base != NULL, NULL);
446 g_return_val_if_fail ( priv->url_start_dir_fmt != NULL, NULL);
447 g_return_val_if_fail ( priv->url_stop_dir_fmt != NULL, NULL);
449 gchar *from_quoted, *to_quoted;
450 gchar **from_split, **to_split;
451 from_quoted = g_shell_quote ( start );
452 to_quoted = g_shell_quote ( end );
454 from_split = g_strsplit( from_quoted, " ", 0);
455 to_split = g_strsplit( to_quoted, " ", 0);
457 from_quoted = g_strjoinv( "%20", from_split);
458 to_quoted = g_strjoinv( "%20", to_split);
460 gchar *url_fmt = g_strconcat ( priv->url_base, priv->url_start_dir_fmt, priv->url_stop_dir_fmt, NULL );
461 gchar *url = g_strdup_printf ( url_fmt, from_quoted, to_quoted );
467 g_strfreev(from_split);
468 g_strfreev(to_split);
474 vik_routing_web_engine_supports_direction ( VikRoutingEngine *self )
476 g_return_val_if_fail ( VIK_IS_ROUTING_WEB_ENGINE (self), FALSE);
478 VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( self );
480 return (priv->url_start_dir_fmt) != NULL;
484 VikRoutingWebEnginePrivate *priv;
490 _append_stringified_coords ( gpointer data, gpointer user_data )
492 VikTrackpoint *vtp = (VikTrackpoint*)data;
493 struct _append_ctx *ctx = (struct _append_ctx*)user_data;
495 /* Stringify coordinate */
496 struct LatLon position;
497 vik_coord_to_latlon ( &(vtp->coord), &position );
498 gchar *string = substitute_latlon ( ctx->priv->url_via_ll_fmt, position );
501 ctx->urlParts[ctx->nb] = string;
506 vik_routing_web_engine_get_url_for_track ( VikRoutingEngine *self, VikTrack *vt )
511 VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( self );
513 g_return_val_if_fail ( priv->url_base != NULL, NULL );
514 g_return_val_if_fail ( priv->url_start_ll_fmt != NULL, NULL );
515 g_return_val_if_fail ( priv->url_stop_ll_fmt != NULL, NULL );
516 g_return_val_if_fail ( priv->url_via_ll_fmt != NULL, NULL );
518 /* Init temporary storage */
519 gsize len = 1 + g_list_length ( vt->trackpoints ) + 1; /* base + trackpoints + NULL */
520 urlParts = g_malloc ( sizeof(gchar*)*len );
521 urlParts[0] = g_strdup ( priv->url_base );
522 urlParts[len-1] = NULL;
524 struct _append_ctx ctx;
526 ctx.urlParts = urlParts;
527 ctx.nb = 1; /* First cell available, previous used for base URL */
529 /* Append all trackpoints to URL */
530 g_list_foreach ( vt->trackpoints, _append_stringified_coords, &ctx );
532 /* Override first and last positions with associated formats */
533 struct LatLon position;
535 g_free ( urlParts[1] );
536 vtp = g_list_first ( vt->trackpoints )->data;
537 vik_coord_to_latlon ( &(vtp->coord ), &position );
538 urlParts[1] = substitute_latlon ( priv->url_start_ll_fmt, position );
539 g_free ( urlParts[len-2] );
540 vtp = g_list_last ( vt->trackpoints )->data;
541 vik_coord_to_latlon ( &(vtp->coord), &position );
542 urlParts[len-2] = substitute_latlon ( priv->url_stop_ll_fmt, position );
545 url = g_strjoinv ( NULL, urlParts );
546 g_debug ( "%s: %s", __FUNCTION__, url );
549 g_strfreev ( urlParts );
555 vik_routing_web_engine_refine ( VikRoutingEngine *self, VikTrwLayer *vtl, VikTrack *vt )
558 int ret = 0; /* OK */
561 uri = vik_routing_web_engine_get_url_for_track ( self, vt );
564 DownloadMapOptions *options = vik_routing_web_engine_get_download_options ( self );
566 /* Convert and insert data in model */
567 gchar *format = vik_routing_engine_get_format ( self );
568 a_babel_convert_from_url ( vtl, uri, format, NULL, NULL, options );
576 vik_routing_web_engine_supports_refine ( VikRoutingEngine *self )
578 g_return_val_if_fail ( VIK_IS_ROUTING_WEB_ENGINE (self), FALSE);
580 VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( self );
582 return priv->url_via_ll_fmt != NULL;