Fix:Core:Cleaned up map api a bit
[navit-package] / navit / navigation.c
1 /**
2  * Navit, a modular navigation system.
3  * Copyright (C) 2005-2008 Navit Team
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * version 2 as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA  02110-1301, USA.
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <math.h>
24 #include <glib.h>
25 #include <libintl.h>
26 #include "debug.h"
27 #include "profile.h"
28 #include "navigation.h"
29 #include "coord.h"
30 #include "item.h"
31 #include "route.h"
32 #include "transform.h"
33 #include "mapset.h"
34 #include "projection.h"
35 #include "map.h"
36 #include "navit.h"
37 #include "callback.h"
38 #include "plugin.h"
39
40 #define _(STRING)    gettext(STRING)
41
42 struct suffix {
43         char *fullname;
44         char *abbrev;
45         int sex;
46 } suffixes[]= {
47         {"weg",NULL,1},
48         {"platz","pl.",1},
49         {"ring",NULL,1},
50         {"allee",NULL,2},
51         {"gasse",NULL,2},
52         {"straße","str.",2},
53         {"strasse",NULL,2},
54 };
55
56 struct navigation {
57         struct map *map;
58         struct item_hash *hash;
59         struct navigation_itm *first;
60         struct navigation_itm *last;
61         struct navigation_command *cmd_first;
62         struct navigation_command *cmd_last;
63         struct callback_list *callback_speech;
64         struct callback_list *callback;
65         int level_last;
66         struct item item_last;
67         int turn_around;
68         int turn_around_limit;
69         int distance_turn;
70         int distance_last;
71         int announce[route_item_last-route_item_first+1][3];
72 };
73
74
75 struct navigation_command {
76         struct navigation_itm *itm;
77         struct navigation_command *next;
78         int delta;
79 };
80
81 struct navigation *
82 navigation_new(struct attr **attrs)
83 {
84         int i,j;
85         struct navigation *ret=g_new0(struct navigation, 1);
86         ret->hash=item_hash_new();
87         ret->callback=callback_list_new();
88         ret->callback_speech=callback_list_new();
89         ret->level_last=-2;
90         ret->distance_last=-2;
91         ret->distance_turn=50;
92         ret->turn_around_limit=3;
93
94         for (j = 0 ; j <= route_item_last-route_item_first ; j++) {
95                 for (i = 0 ; i < 3 ; i++) {
96                         ret->announce[j][i]=-1;
97                 }
98         }
99
100         return ret;     
101 }
102
103 int
104 navigation_set_announce(struct navigation *this_, enum item_type type, int *level)
105 {
106         int i;
107         if (type < route_item_first || type > route_item_last) {
108                 dbg(0,"street type %d out of range [%d,%d]", type, route_item_first, route_item_last);
109                 return 0;
110         }
111         for (i = 0 ; i < 3 ; i++) 
112                 this_->announce[type-route_item_first][i]=level[i];
113         return 1;
114 }
115
116 static int
117 navigation_get_announce_level(struct navigation *this_, enum item_type type, int dist)
118 {
119         int i;
120
121         if (type < route_item_first || type > route_item_last)
122                 return -1;
123         for (i = 0 ; i < 3 ; i++) {
124                 if (dist <= this_->announce[type-route_item_first][i])
125                         return i;
126         }
127         return i;
128 }
129
130 struct navigation_itm {
131         char *name1;
132         char *name2;
133         struct item item;
134         int angle_start;
135         int angle_end;
136         struct coord c;
137         int time;
138         int length;
139         int dest_time;
140         int dest_length;
141         int told;
142         int dest_count;
143         struct navigation_itm *next;
144         struct navigation_itm *prev;
145 };
146
147 /* 0=N,90=E */
148 static int
149 road_angle(struct coord *c1, struct coord *c2, int dir)
150 {
151         int ret=transform_get_angle_delta(c1, c2, dir);
152         dbg(1, "road_angle(0x%x,0x%x - 0x%x,0x%x)=%d\n", c1->x, c1->y, c2->x, c2->y, ret);
153         return ret;
154 }
155
156 static int
157 round_distance(int dist)
158 {
159         if (dist < 100) {
160                 dist=(dist+5)/10;
161                 return dist*10;
162         }
163         if (dist < 250) {
164                 dist=(dist+13)/25;
165                 return dist*25;
166         }
167         if (dist < 500) {
168                 dist=(dist+25)/50;
169                 return dist*50;
170         }
171         if (dist < 1000) {
172                 dist=(dist+50)/100;
173                 return dist*100;
174         }
175         if (dist < 5000) {
176                 dist=(dist+50)/100;
177                 return dist*100;
178         }
179         if (dist < 100000) {
180                 dist=(dist+500)/1000;
181                 return dist*1000;
182         }
183         dist=(dist+5000)/10000;
184         return dist*10000;
185 }
186
187 static char *
188 get_distance(int dist, enum attr_type type, int is_length)
189 {
190         if (type == attr_navigation_long) {
191                 if (is_length)
192                         return g_strdup_printf(_("%d m"), dist);
193                 else
194                         return g_strdup_printf(_("in %d m"), dist);
195         }
196         if (dist < 1000) {
197                 if (is_length)
198                         return g_strdup_printf(_("%d meters"), dist);
199                 else
200                         return g_strdup_printf(_("in %d meters"), dist);
201         }
202         if (dist < 5000) {
203                 int rem=(dist/100)%10;
204                 if (rem) {
205                         if (is_length)
206                                 return g_strdup_printf(_("%d.%d kilometer"), dist/1000, rem);
207                         else
208                                 return g_strdup_printf(_("in %d.%d kilometers"), dist/1000, rem);
209                 }
210         }
211         if (is_length) 
212                 return g_strdup_printf(ngettext("one kilometer","%d kilometers", dist/1000), dist/1000);
213         else
214                 return g_strdup_printf(ngettext("in one kilometer","in %d kilometers", dist/1000), dist/1000);
215 }
216
217 static void
218 navigation_destroy_itms_cmds(struct navigation *this_, struct navigation_itm *end)
219 {
220         struct navigation_itm *itm;
221         struct navigation_command *cmd;
222         dbg(2,"enter this_=%p this_->first=%p this_->cmd_first=%p end=%p\n", this_, this_->first, this_->cmd_first, end);
223         if (this_->cmd_first)
224                 dbg(2,"this_->cmd_first->itm=%p\n", this_->cmd_first->itm);
225         while (this_->first && this_->first != end) {
226                 itm=this_->first;
227                 dbg(3,"destroying %p\n", itm);
228                 item_hash_remove(this_->hash, &itm->item);
229                 this_->first=itm->next;
230                 if (this_->first)
231                         this_->first->prev=NULL;
232                 if (this_->cmd_first && this_->cmd_first->itm == itm->next) {
233                         cmd=this_->cmd_first;
234                         this_->cmd_first=cmd->next;
235                         g_free(cmd);
236                 }
237                 map_convert_free(itm->name1);
238                 map_convert_free(itm->name2);
239                 g_free(itm);
240         }
241         if (! this_->first)
242                 this_->last=NULL;
243         if (! this_->first && end) 
244                 dbg(0,"end wrong\n");
245         dbg(2,"ret this_->first=%p this_->cmd_first=%p\n",this_->first, this_->cmd_first);
246 }
247
248 static void
249 navigation_itm_update(struct navigation_itm *itm, struct item *ritem)
250 {
251         struct attr length, time;
252         if (! item_attr_get(ritem, attr_length, &length)) {
253                 dbg(0,"no length\n");
254                 return;
255         }
256         if (! item_attr_get(ritem, attr_time, &time)) {
257                 dbg(0,"no time\n");
258                 return;
259         }
260         dbg(1,"length=%d time=%d\n", length.u.num, time.u.num);
261         itm->length=length.u.num;
262         itm->time=time.u.num;
263 }
264
265 static struct navigation_itm *
266 navigation_itm_new(struct navigation *this_, struct item *ritem)
267 {
268         struct navigation_itm *ret=g_new0(struct navigation_itm, 1);
269         int l,i=0;
270         struct item *sitem;
271         struct attr street_item;
272         struct map_rect *mr;
273         struct attr attr;
274         struct coord c[5];
275
276         if (ritem) {
277                 ret->told=0;
278                 if (! item_attr_get(ritem, attr_street_item, &street_item)) {
279                         dbg(0,"no street item\n");
280                         return NULL;
281                 }
282                 sitem=street_item.u.item;
283                 ret->item=*sitem;
284                 item_hash_insert(this_->hash, sitem, ret);
285                 mr=map_rect_new(sitem->map, NULL);
286                 sitem=map_rect_get_item_byid(mr, sitem->id_hi, sitem->id_lo);
287                 if (item_attr_get(sitem, attr_street_name, &attr))
288                         ret->name1=map_convert_string(sitem->map,attr.u.str);
289                 if (item_attr_get(sitem, attr_street_name_systematic, &attr))
290                         ret->name2=map_convert_string(sitem->map,attr.u.str);
291                 navigation_itm_update(ret, ritem);
292                 l=-1;
293                 while (item_coord_get(ritem, &c[i], 1)) {
294                         dbg(1, "coord %d 0x%x 0x%x\n", i, c[i].x ,c[i].y);
295                         l=i;
296                         if (i < 4) 
297                                 i++;
298                         else {
299                                 c[2]=c[3];
300                                 c[3]=c[4];
301                         }
302                 }
303                 dbg(1,"count=%d\n", l);
304                 if (l == 4)
305                         l=3;
306                 ret->angle_start=road_angle(&c[0], &c[1], 0);
307                 ret->angle_end=road_angle(&c[l-1], &c[l], 0);
308                 ret->c=c[0];
309                 dbg(1,"i=%d start %d end %d '%s' '%s'\n", i, ret->angle_start, ret->angle_end, ret->name1, ret->name2);
310                 map_rect_destroy(mr);
311         }
312         if (! this_->first)
313                 this_->first=ret;
314         if (this_->last) {
315                 this_->last->next=ret;
316                 ret->prev=this_->last;
317         }
318         dbg(1,"ret=%p\n", ret);
319         this_->last=ret;
320         return ret;
321 }
322
323 static void
324 calculate_dest_distance(struct navigation *this_, int incr)
325 {
326         int len=0, time=0, count=0;
327         struct navigation_itm *next,*itm=this_->last;
328         dbg(1, "enter this_=%p, incr=%d\n", this_, incr);
329         if (incr) {
330                 if (itm)
331                         dbg(2, "old values: (%p) time=%d lenght=%d\n", itm, itm->dest_length, itm->dest_time);
332                 else
333                         dbg(2, "old values: itm is null\n");
334                 itm=this_->first;
335                 next=itm->next;
336                 dbg(2, "itm values: time=%d lenght=%d\n", itm->length, itm->time);
337                 dbg(2, "next values: (%p) time=%d lenght=%d\n", next, next->dest_length, next->dest_time);
338                 itm->dest_length=next->dest_length+itm->length;
339                 itm->dest_count=next->dest_count+1;
340                 itm->dest_time=next->dest_time+itm->time;
341                 dbg(2, "new values: time=%d lenght=%d\n", itm->dest_length, itm->dest_time);
342                 return;
343         }
344         while (itm) {
345                 len+=itm->length;
346                 time+=itm->time;
347                 itm->dest_length=len;
348                 itm->dest_time=time;
349                 itm->dest_count=count++;
350                 itm=itm->prev;
351         }
352         dbg(1,"len %d time %d\n", len, time);
353 }
354
355 static int
356 is_same_street2(struct navigation_itm *old, struct navigation_itm *new)
357 {
358         if (old->name1 && new->name1 && !strcmp(old->name1, new->name1)) {
359                 dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' yes (1.)\n", old->name2, new->name2, old->name1, new->name1);
360                 return 1;
361         }
362         if (old->name2 && new->name2 && !strcmp(old->name2, new->name2)) {
363                 dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' yes (2.)\n", old->name2, new->name2, old->name1, new->name1);
364                 return 1;
365         }
366         dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' no\n", old->name2, new->name2, old->name1, new->name1);
367         return 0;
368 }
369
370 static int
371 maneuver_required2(struct navigation_itm *old, struct navigation_itm *new, int *delta)
372 {
373         dbg(1,"enter %p %p %p\n",old, new, delta);
374         if (new->item.type == old->item.type || (new->item.type != type_ramp && old->item.type != type_ramp)) {
375                 if (is_same_street2(old, new)) {
376                         return 0;
377                 }
378         } else
379                 dbg(1, "maneuver_required: old or new is ramp\n");
380 #if 0
381         if (old->crossings_end == 2) {
382                 dbg(1, "maneuver_required: only 2 connections: no\n");
383                 return 0;
384         }
385 #endif
386         if (new->item.type == type_highway_land || new->item.type == type_highway_city || old->item.type == type_highway_land || old->item.type == type_highway_city) {
387                 dbg(1, "maneuver_required: highway changed name\n");
388                 return 1;
389         }
390         *delta=new->angle_start-old->angle_end;
391         if (*delta < -180)
392                 *delta+=360;
393         if (*delta > 180)
394                 *delta-=360;
395         dbg(1,"delta=%d-%d=%d\n", new->angle_start, old->angle_end, *delta);
396         if (*delta < 20 && *delta >-20) {
397                 dbg(1, "maneuver_required: delta(%d) < 20: no\n", *delta);
398                 return 0;
399         }
400         dbg(1, "maneuver_required: delta=%d: yes\n", *delta);
401         return 1;
402 }
403
404 static struct navigation_command *
405 command_new(struct navigation *this_, struct navigation_itm *itm, int delta)
406 {
407         struct navigation_command *ret=g_new0(struct navigation_command, 1);
408         dbg(1,"enter this_=%p itm=%p delta=%d\n", this_, itm, delta);
409         ret->delta=delta;
410         ret->itm=itm;
411         if (this_->cmd_last)
412                 this_->cmd_last->next=ret;
413         this_->cmd_last=ret;
414
415         if (!this_->cmd_first)
416                 this_->cmd_first=ret;
417         return ret;
418 }
419
420 static void
421 make_maneuvers(struct navigation *this_)
422 {
423         struct navigation_itm *itm, *last=NULL, *last_itm=NULL;
424         int delta;
425         itm=this_->first;
426         this_->cmd_last=NULL;
427         this_->cmd_first=NULL;
428         while (itm) {
429                 if (last) {
430                         if (maneuver_required2(last_itm, itm, &delta)) {
431                                 command_new(this_, itm, delta);
432                         }
433                 } else
434                         last=itm;
435                 last_itm=itm;
436                 itm=itm->next;
437         }
438 }
439
440 static int
441 contains_suffix(char *name, char *suffix)
442 {
443         if (!suffix)
444                 return 0;
445         if (strlen(name) < strlen(suffix))
446                 return 0;
447         return !strcasecmp(name+strlen(name)-strlen(suffix), suffix);
448 }
449
450 static char *
451 replace_suffix(char *name, char *search, char *replace)
452 {
453         int len=strlen(name)-strlen(search);
454         char *ret=g_malloc(len+strlen(replace)+1);
455         strncpy(ret, name, len);
456         strcpy(ret+len, replace);
457
458         return ret;
459 }
460
461 static char *
462 navigation_item_destination(struct navigation_itm *itm, struct navigation_itm *next, char *prefix)
463 {
464         char *ret=NULL,*name1,*sep,*name2;
465         int i,sex;
466         if (! prefix)
467                 prefix="";
468         if(!itm->name1 && !itm->name2 && itm->item.type == type_ramp) {
469                 dbg(1,">> Next is ramp %lx current is %lx \n", itm->item.type, next->item.type);
470                          
471                 if(next->item.type == type_ramp)
472                         return NULL;
473                 if(itm->item.type == type_highway_city || itm->item.type == type_highway_land )
474                         return g_strdup_printf("%s%s",prefix,_("exit"));                                 
475                 else
476                         return g_strdup_printf("%s%s",prefix,_("ramp"));
477                 
478         }
479         if (!itm->name1 && !itm->name2)
480                 return NULL;
481         if (itm->name1) {
482                 sex=-1;
483                 name1=NULL;
484                 for (i = 0 ; i < sizeof(suffixes)/sizeof(suffixes[0]) ; i++) {
485                         if (contains_suffix(itm->name1,suffixes[i].fullname)) {
486                                 sex=suffixes[i].sex;
487                                 name1=g_strdup(itm->name1);
488                                 break;
489                         }
490                         if (contains_suffix(itm->name1,suffixes[i].abbrev)) {
491                                 sex=suffixes[i].sex;
492                                 name1=replace_suffix(itm->name1, suffixes[i].abbrev, suffixes[i].fullname);
493                                 break;
494                         }
495                 }
496                 if (itm->name2) {
497                         name2=itm->name2;
498                         sep=" ";
499                 } else {
500                         name2="";
501                         sep="";
502                 }
503                 switch (sex) {
504                 case -1:
505                         /* TRANSLATORS: Arguments: 1: Prefix (Space if required) 2: Street Name 3: Separator (Space if required), 4: Systematic Street Name */
506                         ret=g_strdup_printf(_("%sinto the street %s%s%s"),prefix,itm->name1, sep, name2);
507                         break;
508                 case 1:
509                         /* TRANSLATORS: Arguments: 1: Prefix (Space if required) 2: Street Name 3: Separator (Space if required), 4: Systematic Street Name. Male form. The stuff after | doesn't have to be included */
510                         ret=g_strdup_printf(_("%sinto the %s%s%s|male form"),prefix,name1, sep, name2);
511                         break;
512                 case 2:
513                         /* TRANSLATORS: Arguments: 1: Prefix (Space if required) 2: Street Name 3: Separator (Space if required), 4: Systematic Street Name. Female form. The stuff after | doesn't have to be included */
514                         ret=g_strdup_printf(_("%sinto the %s%s%s|female form"),prefix,name1, sep, name2);
515                         break;
516                 case 3:
517                         /* TRANSLATORS: Arguments: 1: Prefix (Space if required) 2: Street Name 3: Separator (Space if required), 4: Systematic Street Name. Neutral form. The stuff after | doesn't have to be included */
518                         ret=g_strdup_printf(_("%sinto the %s%s%s|neutral form"),prefix,name1, sep, name2);
519                         break;
520                 }
521                 g_free(name1);
522                         
523         } else
524                 /* TRANSLATORS: gives the name of the next road to turn into (into the E17) */
525                 ret=g_strdup_printf(_("into the %s"),itm->name2);
526         name1=ret;
527         while (*name1) {
528                 switch (*name1) {
529                 case '|':
530                         *name1='\0';
531                         break;
532                 case '/':
533                         *name1++=' ';
534                         break;
535                 default:
536                         name1++;
537                 }
538         }
539         return ret;
540 }
541
542
543 static char *
544 show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigation_command *cmd, enum attr_type type)
545 {
546         /* TRANSLATORS: right, as in 'Turn right' */
547         char *dir=_("right"),*strength="";
548         int distance=itm->dest_length-cmd->itm->dest_length;
549         char *d,*ret;
550         int delta=cmd->delta;
551         int level;
552         level=1;
553         if (delta < 0) {
554                 /* TRANSLATORS: left, as in 'Turn left' */
555                 dir=_("left");
556                 delta=-delta;
557         }
558         if (delta < 45) {
559                 /* TRANSLATORS: Don't forget the ending space */
560                 strength=_("easily ");
561         } else if (delta < 105) {
562                 strength="";
563         } else if (delta < 165) {
564                 /* TRANSLATORS: Don't forget the ending space */
565                 strength=_("strongly ");
566         } else {
567                 dbg(1,"delta=%d\n", delta);
568                 /* TRANSLATORS: Don't forget the ending space */
569                 strength=_("unknown ");
570         }
571         if (type != attr_navigation_long_exact) 
572                 distance=round_distance(distance);
573         if (type == attr_navigation_speech) {
574                 if (nav->turn_around && nav->turn_around == nav->turn_around_limit) 
575                         return g_strdup(_("When possible, please turn around"));
576                 level=navigation_get_announce_level(nav, itm->item.type, distance);
577                 dbg(1,"distance=%d level=%d type=0x%x\n", distance, level, itm->item.type);
578         }
579         switch(level) {
580         case 3:
581                 d=get_distance(distance, type, 1);
582                 ret=g_strdup_printf(_("Follow the road for the next %s"), d);
583                 g_free(d);
584                 return ret;
585         case 2:
586                 d=g_strdup(_("soon"));
587                 break;
588         case 1:
589                 d=get_distance(distance, type, 0);
590                 break;
591         case 0:
592                 d=g_strdup(_("now"));
593                 break;
594         default:
595                 d=g_strdup(_("error"));
596         }
597         if (cmd->itm->next) {
598                 int tellstreetname = 0;
599                 char *destination = NULL; 
600  
601                 if(type == attr_navigation_speech) { // In voice mode
602                         // In Voice Mode only tell the street name in level 1 or in level 0 if level 1
603                         // was skipped
604
605                         if (level == 1) { // we are close to the intersection
606                                 cmd->itm->told = 1; // remeber to be checked when we turn
607                                 tellstreetname = 1; // Ok so we tell the name of the street 
608                         }
609
610                         if (level == 0) {
611                                 if(cmd->itm->told == 0) // we are write at the intersection
612                                         tellstreetname = 1; 
613                                 else
614                                         cmd->itm->told = 0;  // reset just in case we come to the same street again
615                         }
616
617                 }
618                 else
619                      tellstreetname = 1;
620
621                 if(tellstreetname) 
622                         destination=navigation_item_destination(cmd->itm, itm, " ");
623                 /* TRANSLATORS: The first argument is strength, the second direction, the third distance and the fourth destination Example: 'Turn 'slightly' 'left' in '100 m' 'onto baker street' */
624                 ret=g_strdup_printf(_("Turn %1$s%2$s %3$s%4$s"), strength, dir, d, destination ? destination:"");
625                 g_free(destination);
626         } else
627                 ret=g_strdup_printf(_("You have reached your destination %s"), d);
628         g_free(d);
629         return ret;
630 }
631
632 static void
633 navigation_call_callbacks(struct navigation *this_, int force_speech)
634 {
635         int distance, level = 0;
636         void *p=this_;
637         if (!this_->cmd_first)
638                 return;
639         callback_list_call(this_->callback, 1, &p);
640         dbg(1,"force_speech=%d turn_around=%d turn_around_limit=%d\n", force_speech, this_->turn_around, this_->turn_around_limit);
641         distance=round_distance(this_->first->dest_length-this_->cmd_first->itm->dest_length);
642         if (this_->turn_around_limit && this_->turn_around == this_->turn_around_limit) {
643                 dbg(1,"distance=%d distance_turn=%d\n", distance, this_->distance_turn);
644                 while (distance > this_->distance_turn) {
645                         this_->level_last=4;
646                         level=4;
647                         force_speech=1;
648                         if (this_->distance_turn >= 500)
649                                 this_->distance_turn*=2;
650                         else
651                                 this_->distance_turn=500;
652                 }
653         } else if (!this_->turn_around_limit || this_->turn_around == -this_->turn_around_limit+1) {
654                 this_->distance_turn=50;
655                 level=navigation_get_announce_level(this_, this_->first->item.type, distance);
656                 if (level < this_->level_last) {
657                         dbg(1,"level %d < %d\n", level, this_->level_last);
658                         this_->level_last=level;
659                         force_speech=1;
660                 }
661                 if (!item_is_equal(this_->cmd_first->itm->item, this_->item_last)) {
662                         dbg(1,"item different\n");
663                         this_->item_last=this_->cmd_first->itm->item;
664                         force_speech=1;
665                 }
666         }
667         if (force_speech) {
668                 this_->level_last=level;
669                 dbg(1,"distance=%d level=%d type=0x%x\n", distance, level, this_->first->item.type);
670                 callback_list_call(this_->callback_speech, 1, &p);
671         }
672 }
673
674 void
675 navigation_update(struct navigation *this_, struct route *route)
676 {
677         struct map *map;
678         struct map_rect *mr;
679         struct item *ritem,*sitem;
680         struct attr street_item;
681         struct navigation_itm *itm;
682         int incr=0;
683
684         if (! route)
685                 return;
686         map=route_get_map(route);
687         if (! map)
688                 return;
689         mr=map_rect_new(map, NULL);
690         if (! mr)
691                 return;
692         dbg(1,"enter\n");
693         ritem=map_rect_get_item(mr);
694         if (ritem) {
695                 if (!item_attr_get(ritem, attr_street_item, &street_item)) {
696                         ritem=map_rect_get_item(mr);
697                         if (! ritem) {
698                                 return;
699                         }
700                         if (!item_attr_get(ritem, attr_street_item, &street_item)) {
701                                 dbg(0,"no street item\n");
702                         }       
703                 }
704                 sitem=street_item.u.item;
705                 dbg(1,"sitem=%p\n", sitem);
706                 itm=item_hash_lookup(this_->hash, sitem);
707                 dbg(2,"itm for item with id (0x%x,0x%x) is %p\n", sitem->id_hi, sitem->id_lo, itm);
708                 navigation_destroy_itms_cmds(this_, itm);
709                 if (itm) {
710                         incr=1;
711                         navigation_itm_update(itm, ritem);
712                 } else {
713                         dbg(1,"not on track\n");
714                         do {
715                                 dbg(1,"item\n");
716                                 navigation_itm_new(this_, ritem);
717                                 ritem=map_rect_get_item(mr);
718                         } while (ritem);
719                         itm=navigation_itm_new(this_, NULL);
720                         make_maneuvers(this_);
721                 }
722                 calculate_dest_distance(this_, incr);
723                 dbg(2,"destination distance old=%d new=%d\n", this_->distance_last, this_->first->dest_length);
724                 if (this_->first->dest_length > this_->distance_last && this_->distance_last >= 0) 
725                         this_->turn_around++;
726                 else
727                         this_->turn_around--;
728                 if (this_->turn_around > this_->turn_around_limit)
729                         this_->turn_around=this_->turn_around_limit;
730                 else if (this_->turn_around < -this_->turn_around_limit+1)
731                         this_->turn_around=-this_->turn_around_limit+1;
732                 dbg(2,"turn_around=%d\n", this_->turn_around);
733                 this_->distance_last=this_->first->dest_length;
734                 profile(0,"end");
735                 navigation_call_callbacks(this_, FALSE);
736         } else
737                 navigation_destroy_itms_cmds(this_, NULL);
738         map_rect_destroy(mr);
739         
740 #if 0
741         struct route_path_handle *rph;
742         struct route_path_segment *s;
743         struct navigation_itm *itm;
744         struct route_info *pos,*dst;
745         struct street_data *sd;
746         int *speedlist;
747         int len,end_flag=0;
748         int incr;
749
750         profile(0,NULL);
751         pos=route_get_pos(route);
752         dst=route_get_dst(route);
753         if (! pos || ! dst)
754                 return;
755         speedlist=route_get_speedlist(route);
756         len=route_info_length(pos, dst, 0);
757         dbg(2,"len pos,dst = %d\n", len);
758         if (len == -1) {
759                 len=route_info_length(pos, NULL, 0);
760                 dbg(2,"len pos = %d\n", len);
761                 end_flag=1;
762         }
763         sd=route_info_street(pos);
764         itm=item_hash_lookup(this_->hash, &sd->item);
765         dbg(2,"itm for item with id (0x%x,0x%x) is %p\n", sd->item.id_hi, sd->item.id_lo, itm);
766         navigation_destroy_itms_cmds(this_, itm);
767         if (itm) 
768                 incr=1;
769         else {
770                 itm=navigation_itm_new(this_, &sd->item, route_info_point(pos, -1));
771                 incr=0;
772         }
773         itm->length=len;
774         itm->time=route_time(speedlist, &sd->item, len);
775         dbg(2,"%p time = %d\n", itm, itm->time);
776         if (!incr) {
777                 printf("not on track\n");
778                 rph=route_path_open(route);
779                 if (rph) {
780                         while((s=route_path_get_segment(rph))) {
781                                 itm=navigation_itm_new(this_, route_path_segment_get_item(s),route_path_segment_get_start(s));
782                                 itm->time=route_path_segment_get_time(s);
783                                 itm->length=route_path_segment_get_length(s);
784                         }
785                         route_path_close(rph);
786                 }
787                 if (end_flag) {
788                         len=route_info_length(NULL, dst, 0);
789                         dbg(1, "end %d\n", len);
790                         sd=route_info_street(dst);
791                         itm=navigation_itm_new(this_, &sd->item, route_info_point(pos, 2));
792                         itm->length=len;
793                         itm->time=route_time(speedlist, &sd->item, len);
794                 }
795                 itm=navigation_itm_new(this_, NULL, NULL);
796                 make_maneuvers(this_);
797         }
798         calculate_dest_distance(this_, incr);
799         dbg(2,"destination distance old=%d new=%d\n", this_->distance_last, this_->first->dest_length);
800         if (this_->first->dest_length > this_->distance_last && this_->distance_last >= 0) 
801                 this_->turn_around=1;
802         else
803                 this_->turn_around=0;
804         dbg(2,"turn_around=%d\n", this_->turn_around);
805         this_->distance_last=this_->first->dest_length;
806         profile(0,"end");
807         navigation_call_callbacks(this_, FALSE);
808 #endif
809 }
810
811 void
812 navigation_flush(struct navigation *this_)
813 {
814         navigation_destroy_itms_cmds(this_, NULL);
815 }
816
817
818 void
819 navigation_destroy(struct navigation *this_)
820 {
821         navigation_flush(this_);
822         item_hash_destroy(this_->hash);
823         callback_list_destroy(this_->callback);
824         callback_list_destroy(this_->callback_speech);
825         g_free(this_);
826 }
827
828 int
829 navigation_register_callback(struct navigation *this_, enum attr_type type, struct callback *cb)
830 {
831         if (type == attr_navigation_speech)
832                 callback_list_add(this_->callback_speech, cb);
833         else
834                 callback_list_add(this_->callback, cb);
835         return 1;
836 }
837
838 void
839 navigation_unregister_callback(struct navigation *this_, enum attr_type type, struct callback *cb)
840 {
841         if (type == attr_navigation_speech)
842                 callback_list_remove_destroy(this_->callback_speech, cb);
843         else
844                 callback_list_remove_destroy(this_->callback, cb);
845 }
846
847 struct map *
848 navigation_get_map(struct navigation *this_)
849 {
850         if (! this_->map)
851                 this_->map=map_new((struct attr*[]){
852                         &(struct attr){attr_type,{"navigation"}},
853                         &(struct attr){attr_navigation,.u.navigation=this_},
854                         &(struct attr){attr_data,{""}},
855                         &(struct attr){attr_description,{"Navigation"}},
856                         NULL});
857         return this_->map;
858 }
859
860 struct map_priv {
861         struct navigation *navigation;
862 };
863
864 struct map_rect_priv {
865         struct navigation *nav;
866         struct navigation_command *cmd;
867         struct navigation_command *cmd_next;
868         struct navigation_itm *itm;
869         struct navigation_itm *itm_next;
870         struct navigation_itm *cmd_itm;
871         struct navigation_itm *cmd_itm_next;
872         struct item item;
873         enum attr_type attr_next;
874         int ccount;
875         int debug_idx;
876         int show_all;
877 };
878
879 static int
880 navigation_map_item_coord_get(void *priv_data, struct coord *c, int count)
881 {
882         struct map_rect_priv *this=priv_data;
883         if (this->ccount || ! count)
884                 return 0;
885         *c=this->itm->c;
886         this->ccount=1;
887         return 1;
888 }
889
890 static int
891 navigation_map_item_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
892 {
893         struct map_rect_priv *this_=priv_data;
894         attr->type=attr_type;
895         struct navigation_command *cmd=this_->cmd;
896         if (cmd) {
897                 if (cmd->itm != this_->itm)
898                         cmd=NULL;       
899         }
900         switch(attr_type) {
901         case attr_navigation_short:
902                 this_->attr_next=attr_navigation_long;
903                 if (cmd) {
904                         attr->u.str=show_maneuver(this_->nav, this_->cmd_itm, cmd, attr_type);
905                         return 1;
906                 }
907                 return 0;
908         case attr_navigation_long:
909                 this_->attr_next=attr_navigation_long_exact;
910                 if (cmd) {
911                         attr->u.str=show_maneuver(this_->nav, this_->cmd_itm, cmd, attr_type);
912                         return 1;
913                 }
914                 return 0;
915         case attr_navigation_long_exact:
916                 this_->attr_next=attr_navigation_speech;
917                 if (cmd) {
918                         attr->u.str=show_maneuver(this_->nav, this_->cmd_itm, cmd, attr_type);
919                         return 1;
920                 }
921                 return 0;
922         case attr_navigation_speech:
923                 this_->attr_next=attr_length;
924                 if (cmd) {
925                         attr->u.str=show_maneuver(this_->nav, this_->cmd_itm, this_->cmd, attr_type);
926                         return 1;
927                 }
928                 return 0;
929         case attr_length:
930                 this_->attr_next=attr_time;
931                 if (cmd) {
932                         attr->u.num=this_->cmd_itm->dest_length-cmd->itm->dest_length;
933                         return 1;
934                 }
935                 return 0;
936         case attr_time:
937                 this_->attr_next=attr_destination_length;
938                 if (cmd) {
939                         attr->u.num=this_->cmd_itm->dest_time-cmd->itm->dest_time;
940                         return 1;
941                 }
942                 return 0;
943         case attr_destination_length:
944                 attr->u.num=this_->itm->dest_length;
945                 this_->attr_next=attr_destination_time;
946                 return 1;
947         case attr_destination_time:
948                 attr->u.num=this_->itm->dest_time;
949                 this_->attr_next=attr_street_name;
950                 return 1;
951         case attr_street_name:
952                 attr->u.str=this_->itm->name1;
953                 this_->attr_next=attr_street_name_systematic;
954                 return 1;
955         case attr_street_name_systematic:
956                 attr->u.str=this_->itm->name2;
957                 this_->attr_next=attr_debug;
958                 return 1;
959         case attr_debug:
960                 switch(this_->debug_idx) {
961                 case 0:
962                         attr->u.str=g_strdup_printf("%p vs %p\n", this_->itm,this_->cmd->itm);
963                         this_->attr_next=attr_none;
964                         break;
965                 default:
966                         this_->attr_next=attr_none;
967                         return 0;
968                 }
969                 this_->debug_idx++;
970                 return 1;
971         case attr_any:
972                 while (this_->attr_next != attr_none) {
973                         if (navigation_map_item_attr_get(priv_data, this_->attr_next, attr))
974                                 return 1;
975                 }
976                 return 0;
977         default:
978                 attr->type=attr_none;
979                 return 0;
980         }
981 }
982
983 static struct item_methods navigation_map_item_methods = {
984         NULL,
985         navigation_map_item_coord_get,
986         NULL,
987         navigation_map_item_attr_get,
988 };
989
990
991 static void
992 navigation_map_destroy(struct map_priv *priv)
993 {
994         g_free(priv);
995 }
996
997 static void
998 navigation_map_rect_init(struct map_rect_priv *priv)
999 {
1000         priv->cmd_next=priv->nav->cmd_first;
1001         priv->cmd_itm_next=priv->itm_next=priv->nav->first;
1002 }
1003
1004 static struct map_rect_priv *
1005 navigation_map_rect_new(struct map_priv *priv, struct map_selection *sel)
1006 {
1007         struct navigation *nav=priv->navigation;
1008         struct map_rect_priv *ret=g_new0(struct map_rect_priv, 1);
1009         ret->nav=nav;
1010         navigation_map_rect_init(ret);
1011         ret->item.meth=&navigation_map_item_methods;
1012         ret->item.priv_data=ret;
1013         return ret;
1014 }
1015
1016 static void
1017 navigation_map_rect_destroy(struct map_rect_priv *priv)
1018 {
1019         g_free(priv);
1020 }
1021
1022 static struct item *
1023 navigation_map_get_item(struct map_rect_priv *priv)
1024 {
1025         struct item *ret=&priv->item;
1026         int delta;
1027         if (!priv->itm_next)
1028                 return NULL;
1029         priv->itm=priv->itm_next;
1030         priv->cmd=priv->cmd_next;
1031         priv->cmd_itm=priv->cmd_itm_next;
1032         if (!priv->show_all) {
1033                 if (!priv->cmd)
1034                         return NULL;
1035                 priv->itm=priv->cmd->itm;
1036         }
1037         priv->itm_next=priv->itm->next;
1038         ret->type=type_nav_none;
1039         if (priv->cmd->itm == priv->itm) {
1040                 priv->cmd_itm_next=priv->cmd->itm;
1041                 priv->cmd_next=priv->cmd->next;
1042                 delta=priv->cmd->delta; 
1043                 if (delta < 0) {
1044                         delta=-delta;
1045                         if (delta < 45)
1046                                 ret->type=type_nav_left_1;
1047                         else if (delta < 105)
1048                                 ret->type=type_nav_left_2;
1049                         else if (delta < 165) 
1050                                 ret->type=type_nav_left_3;
1051                         else
1052                                 ret->type=type_none;
1053                 } else {
1054                         if (delta < 45)
1055                                 ret->type=type_nav_right_1;
1056                         else if (delta < 105)
1057                                 ret->type=type_nav_right_2;
1058                         else if (delta < 165) 
1059                                 ret->type=type_nav_right_3;
1060                         else
1061                                 ret->type=type_none;
1062                 }
1063         }
1064         priv->ccount=0;
1065         priv->debug_idx=0;
1066         priv->attr_next=attr_navigation_short;
1067
1068         ret->id_lo=priv->itm->dest_count;
1069         dbg(1,"type=%d\n", ret->type);
1070         return ret;
1071 }
1072
1073 static struct item *
1074 navigation_map_get_item_byid(struct map_rect_priv *priv, int id_hi, int id_lo)
1075 {
1076         struct item *ret;
1077         navigation_map_rect_init(priv);
1078         while ((ret=navigation_map_get_item(priv))) {
1079                 if (ret->id_hi == id_hi && ret->id_lo == id_lo) 
1080                         return ret;
1081         }
1082         return NULL;
1083 }
1084
1085 static struct map_methods navigation_map_meth = {
1086         projection_mg,
1087         "utf-8",
1088         navigation_map_destroy,
1089         navigation_map_rect_new,
1090         navigation_map_rect_destroy,
1091         navigation_map_get_item,
1092         navigation_map_get_item_byid,
1093         NULL,
1094         NULL,
1095         NULL,
1096 };
1097
1098 static struct map_priv *
1099 navigation_map_new(struct map_methods *meth, struct attr **attrs)
1100 {
1101         struct map_priv *ret;
1102         struct attr *navigation_attr;
1103
1104         navigation_attr=attr_search(attrs, NULL, attr_navigation);
1105         if (! navigation_attr)
1106                 return NULL;
1107         ret=g_new0(struct map_priv, 1);
1108         *meth=navigation_map_meth;
1109         ret->navigation=navigation_attr->u.navigation;
1110
1111         return ret;
1112 }
1113
1114
1115 void
1116 navigation_init(void)
1117 {
1118         plugin_register_map_type("navigation", navigation_map_new);
1119 }