]> git.street.me.uk Git - andy/viking.git/blob - src/vikroutingwebengine.c
SF Features#76: Add ability to handle and name trackpoints.
[andy/viking.git] / src / vikroutingwebengine.c
1 /*
2  * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3  *
4  * Copyright (c) 2013, Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 /**
23  * SECTION:vikroutingwebengine
24  * @short_description: A generic class for WEB based routing engine
25  * 
26  * The #VikRoutingWebEngine class handles WEB based
27  * routing engine.
28  */
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include <string.h>
35
36 #include <glib.h>
37 #include <glib/gstdio.h>
38
39 #include "babel.h"
40
41 #include "vikroutingwebengine.h"
42
43 static void vik_routing_web_engine_finalize ( GObject *gob );
44
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 );
50
51 typedef struct _VikRoutingWebEnginePrivate VikRoutingWebEnginePrivate;
52 struct _VikRoutingWebEnginePrivate
53 {
54         gchar *url_base;
55         
56         /* LatLon */
57         gchar *url_start_ll_fmt;
58         gchar *url_stop_ll_fmt;
59         gchar *url_via_ll_fmt;
60
61         /* Directions */
62         gchar *url_start_dir_fmt;
63         gchar *url_stop_dir_fmt;
64
65         DownloadMapOptions options;
66 };
67
68 #define VIK_ROUTING_WEB_ENGINE_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), VIK_ROUTING_WEB_ENGINE_TYPE, VikRoutingWebEnginePrivate))
69
70 /* properties */
71 enum
72 {
73   PROP_0,
74
75   PROP_URL_BASE,
76   
77   /* LatLon */
78   PROP_URL_START_LL,
79   PROP_URL_STOP_LL,
80   PROP_URL_VIA_LL,
81
82   /* Direction */
83   PROP_URL_START_DIR,
84   PROP_URL_STOP_DIR,
85
86   PROP_REFERER,
87   PROP_FOLLOW_LOCATION,
88 };
89
90 G_DEFINE_TYPE (VikRoutingWebEngine, vik_routing_web_engine, VIK_ROUTING_ENGINE_TYPE)
91
92 static void
93 vik_routing_web_engine_set_property (GObject      *object,
94                           guint         property_id,
95                           const GValue *value,
96                           GParamSpec   *pspec)
97 {
98   VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( object );
99
100   switch (property_id)
101     {
102     case PROP_URL_BASE:
103       g_free (priv->url_base);
104       priv->url_base = g_strdup(g_value_get_string (value));
105       break;
106
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));
110       break;
111
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));
115       break;
116
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));
120       break;
121
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));
125       break;
126
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));
130       break;
131
132     case PROP_REFERER:
133       g_free (priv->options.referer);
134       priv->options.referer = g_value_dup_string (value);
135       break;
136
137     case PROP_FOLLOW_LOCATION:
138       priv->options.follow_location = g_value_get_long (value);
139       break;
140
141     default:
142       /* We don't have any other property... */
143       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
144       break;
145     }
146 }
147
148 static void
149 vik_routing_web_engine_get_property (GObject    *object,
150                           guint       property_id,
151                           GValue     *value,
152                           GParamSpec *pspec)
153 {
154   VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( object );
155
156   switch (property_id)
157     {
158     case PROP_URL_BASE:
159       g_value_set_string (value, priv->url_base);
160       break;
161
162     case PROP_URL_START_LL:
163       g_value_set_string (value, priv->url_start_ll_fmt);
164       break;
165
166     case PROP_URL_STOP_LL:
167       g_value_set_string (value, priv->url_stop_ll_fmt);
168       break;
169
170     case PROP_URL_VIA_LL:
171       g_value_set_string (value, priv->url_via_ll_fmt);
172       break;
173
174     case PROP_URL_START_DIR:
175       g_value_set_string (value, priv->url_start_dir_fmt);
176       break;
177
178     case PROP_URL_STOP_DIR:
179       g_value_set_string (value, priv->url_stop_dir_fmt);
180       break;
181
182     case PROP_REFERER:
183       g_value_set_string (value, priv->options.referer);
184       break;
185
186     case PROP_FOLLOW_LOCATION:
187       g_value_set_long (value, priv->options.follow_location);
188       break;
189
190     default:
191       /* We don't have any other property... */
192       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
193       break;
194     }
195 }
196
197 static void vik_routing_web_engine_class_init ( VikRoutingWebEngineClass *klass )
198 {
199   GObjectClass *object_class;
200   VikRoutingEngineClass *parent_class;
201   GParamSpec *pspec = NULL;
202
203   object_class = G_OBJECT_CLASS (klass);
204
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;
208
209   parent_class = VIK_ROUTING_ENGINE_CLASS (klass);
210
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;
216
217   /**
218    * VikRoutingWebEngine:url-base:
219    *
220    * The base URL of the routing engine.
221    */
222   pspec = g_param_spec_string ("url-base",
223                                "URL's 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);
228   
229
230   /**
231    * VikRoutingWebEngine:url-start-ll:
232    *
233    * The part of the request hosting the end point.
234    */
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);
241     
242
243   /**
244    * VikRoutingWebEngine:url-stop-ll:
245    *
246    * The part of the request hosting the end point.
247    */
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);
254
255
256   /**
257    * VikRoutingWebEngine:url-via-ll:
258    *
259    * The param of the request for setting a via point.
260    */
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);
267
268
269   /**
270    * VikRoutingWebEngine:url-start-dir:
271    *
272    * The part of the request hosting the end point.
273    */
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);
280     
281
282   /**
283    * VikRoutingWebEngine:url-stop-dir:
284    *
285    * The part of the request hosting the end point.
286    */
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);
293
294
295   /**
296    * VikRoutingWebEngine:referer:
297    *
298    * The REFERER string to use in HTTP request.
299    */
300   pspec = g_param_spec_string ("referer",
301                                "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);
306
307
308   /**
309    * VikRoutingWebEngine:follow-location:
310    *
311    * Specifies the number of retries to follow a redirect while downloading a page.
312    */
313   pspec = g_param_spec_long ("follow-location",
314                              "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);
321
322   g_type_class_add_private (klass, sizeof (VikRoutingWebEnginePrivate));
323 }
324
325 static void vik_routing_web_engine_init ( VikRoutingWebEngine *self )
326 {
327   VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( self );
328
329   priv->url_base = NULL;
330   
331   /* LatLon */
332   priv->url_start_ll_fmt = NULL;
333   priv->url_stop_ll_fmt = NULL;
334   priv->url_via_ll_fmt = NULL;
335
336   /* Directions */
337   priv->url_start_dir_fmt = NULL;
338   priv->url_stop_dir_fmt = NULL;
339
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;
345 }
346
347 static void vik_routing_web_engine_finalize ( GObject *gob )
348 {
349   VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( gob );
350
351   g_free (priv->url_base);
352   priv->url_base = NULL;
353   
354   /* LatLon */
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;
361
362   /* Directions */
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;
367
368   g_free (priv->options.referer);
369   priv->options.referer = NULL;
370
371   G_OBJECT_CLASS (vik_routing_web_engine_parent_class)->finalize(gob);
372 }
373
374 static DownloadMapOptions *
375 vik_routing_web_engine_get_download_options ( VikRoutingEngine *self )
376 {
377         g_return_val_if_fail (VIK_IS_ROUTING_WEB_ENGINE(self), NULL);
378         
379         VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE(self);
380         
381         return &(priv->options);
382 }
383
384 static gchar *
385 substitute_latlon ( const gchar *fmt, struct LatLon ll )
386 {
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));
391         return substituted;
392 }
393
394 static gchar *
395 vik_routing_web_engine_get_url_for_coords ( VikRoutingEngine *self, struct LatLon start, struct LatLon end )
396 {
397         gchar *startURL;
398         gchar *endURL;
399         gchar *url;
400         
401         g_return_val_if_fail ( VIK_IS_ROUTING_WEB_ENGINE (self), NULL);
402
403         VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( self );
404
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);
408
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 );
412
413         /* Free memory */
414         g_free ( startURL );
415         g_free ( endURL );
416
417         return url;
418 }
419
420 static int
421 vik_routing_web_engine_find ( VikRoutingEngine *self, VikTrwLayer *vtl, struct LatLon start, struct LatLon end )
422 {
423   gchar *uri;
424   int ret = 0;  /* OK */
425
426   uri = vik_routing_web_engine_get_url_for_coords(self, start, end);
427
428   DownloadMapOptions *options = vik_routing_web_engine_get_download_options(self);
429   
430   gchar *format = vik_routing_engine_get_format ( self );
431   a_babel_convert_from_url ( vtl, uri, format, NULL, NULL, options );
432
433   g_free(uri);
434
435   return ret;
436 }
437
438 static gchar *
439 vik_routing_web_engine_get_cmd_from_directions ( VikRoutingEngine *self, const gchar *start, const gchar *end )
440 {
441   g_return_val_if_fail ( VIK_IS_ROUTING_WEB_ENGINE (self), NULL);
442
443   VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( self );
444
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);
448
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 );
453
454   from_split = g_strsplit( from_quoted, " ", 0);
455   to_split = g_strsplit( to_quoted, " ", 0);
456
457   from_quoted = g_strjoinv( "%20", from_split);
458   to_quoted = g_strjoinv( "%20", to_split);
459
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 );
462
463   g_free ( url_fmt );
464
465   g_free(from_quoted);
466   g_free(to_quoted);
467   g_strfreev(from_split);
468   g_strfreev(to_split);
469
470   return url;
471 }
472
473 static gboolean
474 vik_routing_web_engine_supports_direction ( VikRoutingEngine *self )
475 {
476   g_return_val_if_fail ( VIK_IS_ROUTING_WEB_ENGINE (self), FALSE);
477
478   VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( self );
479
480   return (priv->url_start_dir_fmt) != NULL;
481 }
482
483 struct _append_ctx {
484   VikRoutingWebEnginePrivate *priv;
485   gchar **urlParts;
486   int nb;
487 };
488
489 static void
490 _append_stringified_coords ( gpointer data, gpointer user_data )
491 {
492   VikTrackpoint *vtp = (VikTrackpoint*)data;
493   struct _append_ctx *ctx = (struct _append_ctx*)user_data;
494   
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 );
499   
500   /* Append */
501   ctx->urlParts[ctx->nb] = string;
502   ctx->nb++;
503 }
504
505 static gchar *
506 vik_routing_web_engine_get_url_for_track ( VikRoutingEngine *self, VikTrack *vt )
507 {
508   gchar **urlParts;
509   gchar *url;
510
511   VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( self );
512
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 );
517
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;
523
524   struct _append_ctx ctx;
525   ctx.priv = priv;
526   ctx.urlParts = urlParts;
527   ctx.nb = 1; /* First cell available, previous used for base URL */
528
529   /* Append all trackpoints to URL */
530   g_list_foreach ( vt->trackpoints, _append_stringified_coords, &ctx );
531
532   /* Override first and last positions with associated formats */
533   struct LatLon position;
534   VikTrackpoint *vtp;
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 );
543
544   /* Concat */
545   url = g_strjoinv ( NULL, urlParts );
546   g_debug ( "%s: %s", __FUNCTION__, url );
547
548   /* Free */
549   g_strfreev ( urlParts );
550
551   return url;
552 }
553
554 static int
555 vik_routing_web_engine_refine ( VikRoutingEngine *self, VikTrwLayer *vtl, VikTrack *vt )
556 {
557   gchar *uri;
558   int ret = 0;  /* OK */
559
560   /* Compute URL */
561   uri = vik_routing_web_engine_get_url_for_track ( self, vt );
562
563   /* Download data */
564   DownloadMapOptions *options = vik_routing_web_engine_get_download_options ( self );
565
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 );
569
570   g_free(uri);
571
572   return ret;
573 }
574
575 static gboolean
576 vik_routing_web_engine_supports_refine ( VikRoutingEngine *self )
577 {
578   g_return_val_if_fail ( VIK_IS_ROUTING_WEB_ENGINE (self), FALSE);
579
580   VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( self );
581
582   return priv->url_via_ll_fmt != NULL;
583 }