Fix:maptool:Another name for faroe islands
[navit-package] / navit / navigation.c
index 3cd9e3b..ce01152 100644 (file)
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
+#include <ctype.h>
 #include <glib.h>
 #include "debug.h"
 #include "profile.h"
@@ -37,6 +38,8 @@
 #include "plugin.h"
 #include "navit_nls.h"
 
+/* #define DEBUG */
+
 struct suffix {
        char *fullname;
        char *abbrev;
@@ -52,6 +55,7 @@ struct suffix {
 };
 
 struct navigation {
+       struct route *route;
        struct map *map;
        struct item_hash *hash;
        struct navigation_itm *first;
@@ -60,34 +64,95 @@ struct navigation {
        struct navigation_command *cmd_last;
        struct callback_list *callback_speech;
        struct callback_list *callback;
+       struct navit *navit;
        int level_last;
        struct item item_last;
        int turn_around;
        int turn_around_limit;
        int distance_turn;
-       int distance_last;
+       struct callback *route_cb;
        int announce[route_item_last-route_item_first+1][3];
+       int tell_street_name;
 };
 
 
 struct navigation_command {
        struct navigation_itm *itm;
        struct navigation_command *next;
+       struct navigation_command *prev;
        int delta;
+       int roundabout_delta;
+       int length;
 };
 
+static void navigation_flush(struct navigation *this_);
+
+/**
+ * @brief Calculates the delta between two angles
+ * @param angle1 The first angle
+ * @param angle2 The second angle
+ * @return The difference between the angles: -179..-1=angle2 is left of angle1,0=same,1..179=angle2 is right of angle1,180=angle1 is opposite of angle2
+ */ 
+
+static int
+angle_delta(int angle1, int angle2)
+{
+       int delta=angle2-angle1;
+       if (delta <= -180)
+               delta+=360;
+       if (delta > 180)
+               delta-=360;
+       return delta;
+}
+
+static int
+angle_median(int angle1, int angle2)
+{
+       int delta=angle_delta(angle1, angle2);
+       int ret=angle1+delta/2;
+       if (ret < 0)
+               ret+=360;
+       if (ret > 360)
+               ret-=360;
+       return ret;
+}
+
+static int
+angle_opposite(int angle)
+{
+       return ((angle+180)%360);
+}
+
+int
+navigation_get_attr(struct navigation *this_, enum attr_type type, struct attr *attr, struct attr_iter *iter)
+{
+       dbg(0,"enter %s\n", attr_to_name(type));
+       switch (type) {
+       case attr_map:
+               attr->u.map=this_->map;
+               break;
+       default:
+               return 0;       
+       }
+       attr->type=type;
+       return 1;
+}
+
+
 struct navigation *
-navigation_new(struct attr **attrs)
+navigation_new(struct attr *parent, struct attr **attrs)
 {
        int i,j;
+       struct attr * attr;
        struct navigation *ret=g_new0(struct navigation, 1);
        ret->hash=item_hash_new();
        ret->callback=callback_list_new();
        ret->callback_speech=callback_list_new();
        ret->level_last=-2;
-       ret->distance_last=-2;
        ret->distance_turn=50;
        ret->turn_around_limit=3;
+       ret->navit=parent->u.navit;
+       ret->tell_street_name=1;
 
        for (j = 0 ; j <= route_item_last-route_item_first ; j++) {
                for (i = 0 ; i < 3 ; i++) {
@@ -95,6 +160,10 @@ navigation_new(struct attr **attrs)
                }
        }
 
+       if ((attr=attr_search(attrs, NULL, attr_tell_street_name))) {
+               ret->tell_street_name = attr->u.num;
+       }
+
        return ret;     
 }
 
@@ -130,8 +199,12 @@ navigation_get_announce_level(struct navigation *this_, enum item_type type, int
  */
 struct navigation_way {
        struct navigation_way *next;            /**< Pointer to a linked-list of all navigation_ways from this navigation item */ 
-       int angle2;                     /**< The angle one has to steer to drive from the old item to this street */
+       short dir;                      /**< The direction -1 or 1 of the way */
+       short angle2;                   /**< The angle one has to steer to drive from the old item to this street */
+       int flags;                      /**< The flags of the way */
        struct item item;               /**< The item of the way */
+       char *name1;
+       char *name2;
 };
 
 struct navigation_itm {
@@ -146,8 +219,10 @@ struct navigation_itm {
        int length;
        int dest_time;
        int dest_length;
-       int told;
+       int told;                                                       /**< Indicates if this item's announcement has been told earlier and should not be told again*/
+       int streetname_told;                            /**< Indicates if this item's streetname has been told in speech navigation*/
        int dest_count;
+       int flags;
        struct navigation_itm *next;
        struct navigation_itm *prev;
        struct navigation_way *ways;            /**< Pointer to all ways one could drive from here */
@@ -162,6 +237,51 @@ road_angle(struct coord *c1, struct coord *c2, int dir)
        return ret;
 }
 
+static char
+*get_count_str(int n) 
+{
+       switch (n) {
+       case 0:
+               return _("zeroth"); // Not sure if this exists, neither if it will ever be needed
+       case 1:
+               return _("first");
+       case 2:
+               return _("second");
+       case 3:
+               return _("third");
+       case 4:
+               return _("fourth");
+       case 5:
+               return _("fifth");
+       case 6:
+               return _("sixth");
+       default: 
+               return NULL;
+       }
+}
+
+static char
+*get_exit_count_str(int n) 
+{
+       switch (n) {
+       case 0:
+               return _("zeroth exit"); // Not sure if this exists, neither if it will ever be needed
+       case 1:
+               return _("first exit");
+       case 2:
+               return _("second exit");
+       case 3:
+               return _("third exit");
+       case 4:
+               return _("fourth exit");
+       case 5:
+               return _("fifth exit");
+       case 6:
+               return _("sixth exit");
+       default: 
+               return NULL;
+       }
+}
 static int
 round_distance(int dist)
 {
@@ -212,7 +332,7 @@ get_distance(int dist, enum attr_type type, int is_length)
                int rem=(dist/100)%10;
                if (rem) {
                        if (is_length)
-                               return g_strdup_printf(_("%d.%d kilometer"), dist/1000, rem);
+                               return g_strdup_printf(_("%d.%d kilometers"), dist/1000, rem);
                        else
                                return g_strdup_printf(_("in %d.%d kilometers"), dist/1000, rem);
                }
@@ -234,39 +354,51 @@ get_distance(int dist, enum attr_type type, int is_length)
  * This is meant to be used with items from a route graph map
  * With other items this will probably not be optimal...
  *
- * @param itm The item to get the start/end angle of
- * @param reverse Set this to true to get the end instead of the start
- * @return The angle the item starts/ends with or 361 on error
+ * @param w The way which should be calculated
  */ 
-static int
-calculate_angle(struct item *itm, int reverse)
+static void
+calculate_angle(struct navigation_way *w)
 {
        struct coord cbuf[2];
        struct item *ritem; // the "real" item
        struct coord c;
        struct map_rect *mr;
+       struct attr attr;
 
-       mr = map_rect_new(itm->map, NULL);
+       w->angle2=361;
+       mr = map_rect_new(w->item.map, NULL);
        if (!mr)
-               return 361;
+               return;
 
-       ritem = map_rect_get_item_byid(mr, itm->id_hi, itm->id_lo);
+       ritem = map_rect_get_item_byid(mr, w->item.id_hi, w->item.id_lo);
        if (!ritem) {
                dbg(1,"Item from segment not found on map!\n");
                map_rect_destroy(mr);
-               return 361;
+               return;
        }
 
        if (ritem->type < type_line || ritem->type >= type_area) {
                map_rect_destroy(mr);
-               return 361;
+               return;
        }
-       
-       if (reverse) {
+       if (item_attr_get(ritem, attr_flags, &attr))
+               w->flags=attr.u.num;
+       else
+               w->flags=0;
+       if (item_attr_get(ritem, attr_street_name, &attr))
+               w->name1=map_convert_string(ritem->map,attr.u.str);
+       else
+               w->name1=NULL;
+       if (item_attr_get(ritem, attr_street_name_systematic, &attr))
+               w->name2=map_convert_string(ritem->map,attr.u.str);
+       else
+               w->name2=NULL;
+               
+       if (w->dir < 0) {
                if (item_coord_get(ritem, cbuf, 2) != 2) {
                        dbg(1,"Using calculate_angle() with a less-than-two-coords-item?\n");
                        map_rect_destroy(mr);
-                       return 361; 
+                       return;
                }
                        
                while (item_coord_get(ritem, &c, 1)) {
@@ -278,7 +410,7 @@ calculate_angle(struct item *itm, int reverse)
                if (item_coord_get(ritem, cbuf, 2) != 2) {
                        dbg(1,"Using calculate_angle() with a less-than-two-coords-item?\n");
                        map_rect_destroy(mr);
-                       return 361; 
+                       return;
                }
                c = cbuf[0];
                cbuf[0] = cbuf[1];
@@ -287,7 +419,41 @@ calculate_angle(struct item *itm, int reverse)
 
        map_rect_destroy(mr);
 
-       return road_angle(&cbuf[1],&cbuf[0],0);
+       w->angle2=road_angle(&cbuf[1],&cbuf[0],0);
+}
+
+/**
+ * @brief Returns the time (in seconds) one will drive between two navigation items
+ *
+ * This function returns the time needed to drive between two items, including both of them,
+ * in seconds.
+ *
+ * @param from The first item
+ * @param to The last item
+ * @return The travel time in seconds, or -1 on error
+ */
+static int
+navigation_time(struct navigation_itm *from, struct navigation_itm *to)
+{
+       struct navigation_itm *cur;
+       int time;
+
+       time = 0;
+       cur = from;
+       while (cur) {
+               time += cur->time;
+
+               if (cur == to) {
+                       break;
+               }
+               cur = cur->next;
+       }
+
+       if (!cur) {
+               return -1;
+       }
+
+       return time;
 }
 
 /**
@@ -303,6 +469,8 @@ navigation_itm_ways_clear(struct navigation_itm *itm)
        c = itm->ways;
        while (c) {
                n = c->next;
+               map_convert_free(c->name1);
+               map_convert_free(c->name2);
                g_free(c);
                c = n;
        }
@@ -325,7 +493,6 @@ navigation_itm_ways_update(struct navigation_itm *itm, struct map *graph_map)
        struct map_selection coord_sel;
        struct map_rect *g_rect; // Contains a map rectangle from the route graph's map
        struct item *i,*sitem;
-       int angle;
        struct attr sitem_attr,direction_attr;
        struct navigation_way *w,*l;
 
@@ -373,10 +540,10 @@ navigation_itm_ways_update(struct navigation_itm *itm, struct map *graph_map)
 
                l = w;
                w = g_new(struct navigation_way, 1);
-               angle = calculate_angle(sitem,(direction_attr.u.num <= 0));
+               w->dir = direction_attr.u.num;
                w->item = *sitem;
-               w->angle2 = angle;
                w->next = l;
+               calculate_angle(w);
        }
 
        map_rect_destroy(g_rect);
@@ -402,6 +569,9 @@ navigation_destroy_itms_cmds(struct navigation *this_, struct navigation_itm *en
                if (this_->cmd_first && this_->cmd_first->itm == itm->next) {
                        cmd=this_->cmd_first;
                        this_->cmd_first=cmd->next;
+                       if (cmd->next) {
+                               cmd->next->prev = NULL;
+                       }
                        g_free(cmd);
                }
                map_convert_free(itm->name1);
@@ -420,6 +590,7 @@ static void
 navigation_itm_update(struct navigation_itm *itm, struct item *ritem)
 {
        struct attr length, time;
+
        if (! item_attr_get(ritem, attr_length, &length)) {
                dbg(0,"no length\n");
                return;
@@ -434,6 +605,61 @@ navigation_itm_update(struct navigation_itm *itm, struct item *ritem)
        itm->time=time.u.num;
 }
 
+/**
+ * @brief This check if an item is part of a roundabout
+ *
+ * @param itm The item to be checked
+ * @return True if the item is part of a roundabout
+ */ 
+static int
+check_roundabout(struct navigation_itm *itm, struct map *graph_map)
+{
+       struct map_selection coord_sel;
+       struct map_rect *g_rect; // Contains a map rectangle from the route graph's map
+       struct item *i,*sitem;
+       struct attr sitem_attr,flags_attr;
+
+       // These values cause the code in route.c to get us only the route graph point and connected segments
+       coord_sel.next = NULL;
+       coord_sel.u.c_rect.lu = itm->start;
+       coord_sel.u.c_rect.rl = itm->start;
+       // the selection's order is ignored
+       
+       g_rect = map_rect_new(graph_map, &coord_sel);
+       
+       i = map_rect_get_item(g_rect);
+       if (!i || i->type != type_rg_point) { // probably offroad? 
+               return 0;
+       }
+
+       while (1) {
+               i = map_rect_get_item(g_rect);
+
+               if (!i) {
+                       break;
+               }
+               
+               if (i->type != type_rg_segment) {
+                       continue;
+               }
+               
+               if (!item_attr_get(i,attr_street_item,&sitem_attr)) {
+                       continue;
+               }               
+
+               sitem = sitem_attr.u.item;
+               if (item_is_equal(itm->item,*sitem)) {
+                       if (item_attr_get(i,attr_flags,&flags_attr) && (flags_attr.u.num & AF_ROUNDABOUT)) {
+                               map_rect_destroy(g_rect);
+                               return 1;
+                       }
+               }
+       }
+
+       map_rect_destroy(g_rect);
+       return 0;
+}
+
 static struct navigation_itm *
 navigation_itm_new(struct navigation *this_, struct item *ritem)
 {
@@ -447,9 +673,9 @@ navigation_itm_new(struct navigation *this_, struct item *ritem)
        struct coord c[5];
 
        if (ritem) {
-               ret->told=0;
+               ret->streetname_told=0;
                if (! item_attr_get(ritem, attr_street_item, &street_item)) {
-                       dbg(0,"no street item\n");
+                       dbg(1, "no street item\n");
                        return NULL;
                }
                if (item_attr_get(ritem, attr_direction, &direction))
@@ -457,14 +683,12 @@ navigation_itm_new(struct navigation *this_, struct item *ritem)
                else
                        ret->direction=0;
 
-               item_attr_get(ritem, attr_route, &route_attr);
-               graph_map = route_get_graph_map(route_attr.u.route);
-
                sitem=street_item.u.item;
                ret->item=*sitem;
                item_hash_insert(this_->hash, sitem, ret);
                mr=map_rect_new(sitem->map, NULL);
-               sitem=map_rect_get_item_byid(mr, sitem->id_hi, sitem->id_lo);
+               if (! (sitem=map_rect_get_item_byid(mr, sitem->id_hi, sitem->id_lo)))
+                       return NULL;
                if (item_attr_get(sitem, attr_street_name, &attr))
                        ret->name1=map_convert_string(sitem->map,attr.u.str);
                if (item_attr_get(sitem, attr_street_name_systematic, &attr))
@@ -489,6 +713,13 @@ navigation_itm_new(struct navigation *this_, struct item *ritem)
 
                ret->start=c[0];
                ret->end=c[i];
+
+               item_attr_get(ritem, attr_route, &route_attr);
+               graph_map = route_get_graph_map(route_attr.u.route);
+               if (check_roundabout(ret, graph_map)) {
+                       ret->flags |= AF_ROUNDABOUT;
+               }
+
                dbg(1,"i=%d start %d end %d '%s' '%s'\n", i, ret->angle_start, ret->angle_end, ret->name1, ret->name2);
                map_rect_destroy(mr);
        } else {
@@ -510,6 +741,54 @@ navigation_itm_new(struct navigation *this_, struct item *ritem)
 }
 
 /**
+ * @brief Counts how many times a driver could turn right/left 
+ *
+ * This function counts how many times the driver theoretically could
+ * turn right/left between two navigation items, not counting the final
+ * turn itself.
+ *
+ * @param from The navigation item which should form the start
+ * @param to The navigation item which should form the end
+ * @param direction Set to < 0 to count turns to the left >= 0 for turns to the right
+ * @return The number of possibilities to turn or -1 on error
+ */
+static int
+count_possible_turns(struct navigation_itm *from, struct navigation_itm *to, int direction)
+{
+       int count;
+       struct navigation_itm *curr;
+       struct navigation_way *w;
+
+       count = 0;
+       curr = from->next;
+       while (curr && (curr != to)) {
+               w = curr->ways;
+
+               while (w) {
+                       if (direction < 0) {
+                               if (angle_delta(curr->prev->angle_end, w->angle2) < 0) {
+                                       count++;
+                                       break;
+                               }
+                       } else {
+                               if (angle_delta(curr->prev->angle_end, w->angle2) > 0) {
+                                       count++;
+                                       break;
+                               }                               
+                       }
+                       w = w->next;
+               }
+               curr = curr->next;
+       }
+
+       if (!curr) { // from does not lead to to?
+               return -1;
+       }
+
+       return count;
+}
+
+/**
  * @brief Calculates distance and time to the destination
  *
  * This function calculates the distance and the time to the destination of a
@@ -564,20 +843,21 @@ calculate_dest_distance(struct navigation *this_, int incr)
  * @return True if both old and new are on the same street
  */
 static int
-is_same_street2(struct navigation_itm *old, struct navigation_itm *new)
+is_same_street2(char *old_name1, char *old_name2, char *new_name1, char *new_name2)
 {
-       if (old->name1 && new->name1 && !strcmp(old->name1, new->name1)) {
-               dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' yes (1.)\n", old->name2, new->name2, old->name1, new->name1);
+       if (old_name1 && new_name1 && !strcmp(old_name1, new_name1)) {
+               dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' yes (1.)\n", old_name2, new_name2, old_name1, new_name1);
                return 1;
        }
-       if (old->name2 && new->name2 && !strcmp(old->name2, new->name2)) {
-               dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' yes (2.)\n", old->name2, new->name2, old->name1, new->name1);
+       if (old_name2 && new_name2 && !strcmp(old_name2, new_name2)) {
+               dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' yes (2.)\n", old_name2, new_name2, old_name1, new_name1);
                return 1;
        }
-       dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' no\n", old->name2, new->name2, old->name1, new->name1);
+       dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' no\n", old_name2, new_name2, old_name1, new_name1);
        return 0;
 }
 
+#if 0
 /**
  * @brief Checks if two navigation items are on the same street
  *
@@ -615,7 +895,7 @@ is_same_street_systematic(struct navigation_itm *old, struct navigation_itm *new
  * @return True if there are multiple streets
  */
 static int 
-check_multiple_streets(struct navigation_itm *new)
+maneuver_multiple_streets(struct navigation_itm *new)
 {
        if (new->ways) {
                return 1;
@@ -624,6 +904,7 @@ check_multiple_streets(struct navigation_itm *new)
        }
 }
 
+
 /**
  * @brief Check if the new item is entered "straight"
  *
@@ -631,42 +912,79 @@ check_multiple_streets(struct navigation_itm *new)
  * is no other street one could take from the old item on with less steering.
  *
  * @param new The navigation item we're driving to
- * @param delta2 The angle one needs to steer to drive to this item
+ * @param diff The absolute angle one needs to steer to drive to this item
  * @return True if the new item is entered "straight"
  */
 static int 
-entering_straight(struct navigation_itm *new, int delta2)
+maneuver_straight(struct navigation_itm *new, int diff)
 {
-       int diff,curr_diff,delta;
+       int curr_diff;
        struct navigation_way *w;
 
-       if (delta2 < 0) {
-               diff = delta2 * -1;
-       } else {
-               diff = delta2;
-       }
-
-       // We never turn more than 180 degrees
-       diff = diff % 180;
-
        w = new->ways;
+       dbg(1,"diff=%d\n", diff);
        while (w) {
-               delta=w->angle2-new->prev->angle_end;
-               if (delta < 0) {
-                       curr_diff = delta * -1;
-               } else {
-                       curr_diff = delta;
-               }
-
-               curr_diff = curr_diff % 180;
-               
+               curr_diff=abs(angle_delta(new->prev->angle_end, w->angle2));
+               dbg(1,"curr_diff=%d\n", curr_diff);
                if (curr_diff < diff) {
                        return 0;
                }
-
                w = w->next;
        }
+       return 1;
+}
+#endif
+
+static int maneuver_category(enum item_type type)
+{
+       switch (type) {
+       case type_street_0:
+               return 1;
+       case type_street_1_city:
+               return 2;
+       case type_street_2_city:
+               return 3;
+       case type_street_3_city:
+               return 4;
+       case type_street_4_city:
+               return 5;
+       case type_highway_city:
+               return 7;
+       case type_street_1_land:
+               return 2;
+       case type_street_2_land:
+               return 3;
+       case type_street_3_land:
+               return 4;
+       case type_street_4_land:
+               return 5;
+       case type_street_n_lanes:
+               return 6;
+       case type_highway_land:
+               return 7;
+       case type_ramp:
+               return 0;
+       case type_roundabout:
+               return 0;
+       case type_ferry:
+               return 0;
+       default:
+               return 0;
+       }
+       
        
+}
+
+static int
+is_way_allowed(struct navigation_way *way)
+{
+       if (way->dir > 0) {
+               if (way->flags & AF_ONEWAYREV)
+                       return 0;
+       } else {
+               if (way->flags & AF_ONEWAY)
+                       return 0;
+       }
        return 1;
 }
 
@@ -679,34 +997,132 @@ entering_straight(struct navigation_itm *new, int delta2)
  * @param old The old navigation item, where we're coming from
  * @param new The new navigation item, where we're going to
  * @param delta The angle the user has to steer to navigate from old to new
+ * @param reason A text string explaining how the return value resulted
  * @return True if navit should guide the user, false otherwise
  */
 static int
-maneuver_required2(struct navigation_itm *old, struct navigation_itm *new, int *delta)
+maneuver_required2(struct navigation_itm *old, struct navigation_itm *new, int *delta, char **reason)
 {
+       int ret=0,d,dw,dlim;
+       char *r=NULL;
+       struct navigation_way *w;
+       int cat,ncat,wcat,maxcat,left=-180,right=180,is_unambigous=0,is_same_street;
+
        dbg(1,"enter %p %p %p\n",old, new, delta);
-       *delta=new->angle_start-old->angle_end;
-       if (*delta < -180)
-               *delta+=360;
-       if (*delta > 180)
-               *delta-=360;
+       d=angle_delta(old->angle_end, new->angle_start);
+       if (!new->ways) {
+               /* No announcement necessary */
+               r="no: Only one possibility";
+       } else if (!new->ways->next && new->ways->item.type == type_ramp && !is_way_allowed(new->ways)) {
+               /* If the other way is only a ramp and it is one-way in the wrong direction, no announcement necessary */
+               r="no: Only ramp";
+       }
+       if (! r) {
+               if ((old->flags & AF_ROUNDABOUT) && ! (new->flags & AF_ROUNDABOUT)) {
+                       r="yes: leaving roundabout";
+                       ret=1;
+               } else  if (!(old->flags & AF_ROUNDABOUT) && (new->flags & AF_ROUNDABOUT)) 
+                       r="no: entering roundabout";
+               else if ((old->flags & AF_ROUNDABOUT) && (new->flags & AF_ROUNDABOUT)) 
+                       r="no: staying in roundabout";
+       }
+       if (!r && abs(d) > 75) {
+               /* always make an announcement if you have to make a sharp turn */
+               r="yes: delta over 75";
+               ret=1;
+       }
+       cat=maneuver_category(old->item.type);
+       ncat=maneuver_category(new->item.type);
+       if (!r) {
+               /* Check whether the street keeps its name */
+               is_same_street=is_same_street2(old->name1, old->name2, new->name1, new->name2);
+               w = new->ways;
+               maxcat=-1;
+               while (w) {
+                       dw=angle_delta(old->angle_end, w->angle2);
+                       if (dw < 0) {
+                               if (dw > left)
+                                       left=dw;
+                       } else {
+                               if (dw < right)
+                                       right=dw;
+                       }
+                       wcat=maneuver_category(w->item.type);
+                       /* If any other street has the same name but isn't a highway (a highway might split up temporarily), then
+                          we can't use the same name criterium  */
+                       if (is_same_street && is_same_street2(old->name1, old->name2, w->name1, w->name2) && (cat != 7 || wcat != 7) && is_way_allowed(w))
+                               is_same_street=0;
+                       /* Mark if the street has a higher or the same category */
+                       if (wcat > maxcat)
+                               maxcat=wcat;
+                       w = w->next;
+               }
+               /* get the delta limit for checking for other streets. It is lower if the street has no other
+                  streets of the same or higher category */
+               if (ncat < cat)
+                       dlim=80;
+               else
+                       dlim=120;
+               /* if the street is really straight, the others might be closer to straight */
+               if (abs(d) < 20)
+                       dlim/=2;
+               if ((maxcat == ncat && maxcat == cat) || (ncat == 0 && cat == 0)) 
+                       dlim=abs(d)*620/256;
+               else if (maxcat < ncat && maxcat < cat)
+                       dlim=abs(d)*128/256;
+               if (left < -dlim && right > dlim) 
+                       is_unambigous=1;
+               if (!is_same_street && is_unambigous < 1) {
+                       ret=1;
+                       r="yes: not same street or ambigous";
+               } else
+                       r="no: same street and unambigous";
+#ifdef DEBUG
+               r=g_strdup_printf("yes: d %d left %d right %d dlim=%d cat old:%d new:%d max:%d unambigous=%d same_street=%d", d, left, right, dlim, cat, ncat, maxcat, is_unambigous, is_same_street);
+#endif
+       }
+       *delta=d;
+       if (reason)
+               *reason=r;
+       return ret;
+       
 
+#if 0
        if (new->item.type == old->item.type || (new->item.type != type_ramp && old->item.type != type_ramp)) {
                if (is_same_street2(old, new)) {
-                       if (! entering_straight(new, *delta)) {
+                       if (! entering_straight(new, abs(*delta))) {
                                dbg(1, "maneuver_required: Not driving straight: yes\n");
+                               if (reason)
+                                       *reason="yes: Not driving straight";
                                return 1;
                        }
 
-                       dbg(1, "maneuver_required: Staying on the same street: no\n");
-                       return 0;
+                       if (check_multiple_streets(new)) {
+                               if (entering_straight(new,abs(*delta)*2)) {
+                                       if (reason)
+                                               *reason="no: delta < ext_limit for same name";
+                                       return 0;
+                               }
+                               if (reason)     
+                                       *reason="yes: delta > ext_limit for same name";
+                               return 1;
+                       } else {
+                               dbg(1, "maneuver_required: Staying on the same street: no\n");
+                               if (reason)
+                                       *reason="no: Staying on same street";
+                               return 0;
+                       }
                }
        } else
                dbg(1, "maneuver_required: old or new is ramp\n");
+#if 0
        if (old->item.type == type_ramp && (new->item.type == type_highway_city || new->item.type == type_highway_land)) {
                dbg(1, "no_maneuver_required: old is ramp new is highway\n");
+               if (reason)
+                       *reason="no: old is ramp new is highway";
                return 0;
        }
+#endif
 #if 0
        if (old->crossings_end == 2) {
                dbg(1, "maneuver_required: only 2 connections: no\n");
@@ -716,25 +1132,43 @@ maneuver_required2(struct navigation_itm *old, struct navigation_itm *new, int *
        dbg(1,"delta=%d-%d=%d\n", new->angle_start, old->angle_end, *delta);
        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) && (!is_same_street_systematic(old, new) || (old->name2 != NULL && new->name2 == NULL))) {
                dbg(1, "maneuver_required: highway changed name\n");
+               if (reason)
+                       *reason="yes: highway changed name";
                return 1;
        }
-       if (*delta < 20 && *delta >-20) {
-               if (! entering_straight(new,*delta)) {
+       if (abs(*delta) < straight_limit) {
+               if (! entering_straight(new,abs(*delta))) {
+                       if (reason)
+                               *reason="yes: not straight";
                        dbg(1, "maneuver_required: not driving straight: yes\n");
                        return 1;
                }
 
-               dbg(1, "maneuver_required: delta(%d) < 20: no\n", *delta);              
+               dbg(1, "maneuver_required: delta(%d) < %d: no\n", *delta, straight_limit);
+               if (reason)
+                       *reason="no: delta < limit";
                return 0;
        }
+       if (abs(*delta) < ext_straight_limit) {
+               if (entering_straight(new,abs(*delta)*2)) {
+                       if (reason)
+                               *reason="no: delta < ext_limit";
+                       return 0;
+               }
+       }
 
        if (! check_multiple_streets(new)) {
                dbg(1, "maneuver_required: only one possibility: no\n");
+               if (reason)
+                       *reason="no: only one possibility";
                return 0;
        }
 
        dbg(1, "maneuver_required: delta=%d: yes\n", *delta);
+       if (reason)
+               *reason="yes: delta >= limit";
        return 1;
+#endif
 }
 
 static struct navigation_command *
@@ -744,8 +1178,34 @@ command_new(struct navigation *this_, struct navigation_itm *itm, int delta)
        dbg(1,"enter this_=%p itm=%p delta=%d\n", this_, itm, delta);
        ret->delta=delta;
        ret->itm=itm;
-       if (this_->cmd_last)
+       if (itm && itm->prev && itm->ways && itm->prev->ways && !(itm->flags & AF_ROUNDABOUT) && (itm->prev->flags & AF_ROUNDABOUT)) {
+               int len=0;
+               int angle=0;
+               int entry_angle;
+               struct navigation_itm *itm2=itm->prev;
+               int exit_angle=angle_median(itm->prev->angle_end, itm->ways->angle2);
+               dbg(1,"exit %d median from %d,%d\n", exit_angle,itm->prev->angle_end, itm->ways->angle2);
+               while (itm2 && (itm2->flags & AF_ROUNDABOUT)) {
+                       len+=itm2->length;
+                       angle=itm2->angle_end;
+                       itm2=itm2->prev;
+               }
+               if (itm2 && itm2->next && itm2->next->ways) {
+                       itm2=itm2->next;
+                       entry_angle=angle_median(angle_opposite(itm2->angle_start), itm2->ways->angle2);
+                       dbg(1,"entry %d median from %d(%d),%d\n", entry_angle,angle_opposite(itm2->angle_start), itm2->angle_start, itm2->ways->angle2);
+               } else {
+                       entry_angle=angle_opposite(angle);
+               }
+               dbg(0,"entry %d exit %d\n", entry_angle, exit_angle);
+               ret->roundabout_delta=angle_delta(entry_angle, exit_angle);
+               ret->length=len;
+               
+       }
+       if (this_->cmd_last) {
                this_->cmd_last->next=ret;
+               ret->prev = this_->cmd_last;
+       }
        this_->cmd_last=ret;
 
        if (!this_->cmd_first)
@@ -763,7 +1223,7 @@ make_maneuvers(struct navigation *this_, struct route *route)
        this_->cmd_first=NULL;
        while (itm) {
                if (last) {
-                       if (maneuver_required2(last_itm, itm,&delta)) {
+                       if (maneuver_required2(last_itm, itm,&delta,NULL)) {
                                command_new(this_, itm, delta);
                        }
                } else
@@ -771,6 +1231,7 @@ make_maneuvers(struct navigation *this_, struct route *route)
                last_itm=itm;
                itm=itm->next;
        }
+       command_new(this_, last_itm, 0);
 }
 
 static int
@@ -790,6 +1251,9 @@ replace_suffix(char *name, char *search, char *replace)
        char *ret=g_malloc(len+strlen(replace)+1);
        strncpy(ret, name, len);
        strcpy(ret+len, replace);
+       if (isupper(name[len])) {
+               ret[len]=toupper(ret[len]);
+       }
 
        return ret;
 }
@@ -809,7 +1273,7 @@ navigation_item_destination(struct navigation_itm *itm, struct navigation_itm *n
                if(itm->item.type == type_highway_city || itm->item.type == type_highway_land )
                        return g_strdup_printf("%s%s",prefix,_("exit"));        /* %FIXME Can this even be reached? */                   
                else
-                       return g_strdup_printf("%s%s",prefix,_("ramp"));
+                       return g_strdup_printf("%s%s",prefix,_("into the ramp"));
                
        }
        if (!itm->name1 && !itm->name2)
@@ -858,9 +1322,9 @@ navigation_item_destination(struct navigation_itm *itm, struct navigation_itm *n
                        
        } else
                /* TRANSLATORS: gives the name of the next road to turn into (into the E17) */
-               ret=g_strdup_printf(_("into the %s"),itm->name2);
+               ret=g_strdup_printf(_("%sinto the %s"),prefix,itm->name2);
        name1=ret;
-       while (*name1) {
+       while (name1 && *name1) {
                switch (*name1) {
                case '|':
                        *name1='\0';
@@ -876,22 +1340,31 @@ navigation_item_destination(struct navigation_itm *itm, struct navigation_itm *n
 }
 
 static char *
-show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigation_command *cmd, enum attr_type type)
+show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigation_command *cmd, enum attr_type type, int connect)
 {
        /* TRANSLATORS: right, as in 'Turn right' */
        char *dir=_("right"),*strength="";
        int distance=itm->dest_length-cmd->itm->dest_length;
-       char *d,*ret;
+       char *d,*ret=NULL;
        int delta=cmd->delta;
        int level;
        int strength_needed;
+       int skip_roads;
+       int count_roundabout;
+       struct navigation_itm *cur;
        struct navigation_way *w;
        
+       if (connect) {
+               level = -2; // level = -2 means "connect to another maneuver via 'then ...'"
+       } else {
+               level=1;
+       }
+
        w = itm->next->ways;
        strength_needed = 0;
-       if ((itm->next->angle_start - itm->angle_end) < 0) {
+       if (angle_delta(itm->next->angle_start,itm->angle_end) < 0) {
                while (w) {
-                       if (w->angle2-itm->next->angle_start < 0) {
+                       if (angle_delta(w->angle2,itm->angle_end) < 0) {
                                strength_needed = 1;
                                break;
                        }
@@ -899,7 +1372,7 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
                }
        } else {
                while (w) {
-                       if (w->angle2-itm->next->angle_start > 0) {
+                       if (angle_delta(w->angle2,itm->angle_end) > 0) {
                                strength_needed = 1;
                                break;
                        }
@@ -907,7 +1380,6 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
                }
        }
 
-       level=1;
        if (delta < 0) {
                /* TRANSLATORS: left, as in 'Turn left' */
                dir=_("left");
@@ -923,6 +1395,9 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
                } else if (delta < 165) {
                        /* TRANSLATORS: Don't forget the ending space */
                        strength=_("strongly ");
+               } else if (delta < 180) {
+                       /* TRANSLATORS: Don't forget the ending space */
+                       strength=_("really strongly ");
                } else {
                        dbg(1,"delta=%d\n", delta);
                        /* TRANSLATORS: Don't forget the ending space */
@@ -934,9 +1409,44 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
        if (type == attr_navigation_speech) {
                if (nav->turn_around && nav->turn_around == nav->turn_around_limit) 
                        return g_strdup(_("When possible, please turn around"));
-               level=navigation_get_announce_level(nav, itm->item.type, distance);
+               if (!connect) {
+                       level=navigation_get_announce_level(nav, itm->item.type, distance-cmd->length);
+               }
                dbg(1,"distance=%d level=%d type=0x%x\n", distance, level, itm->item.type);
        }
+
+       if (cmd->itm->prev->flags & AF_ROUNDABOUT) {
+               switch (level) {
+               case 2:
+                       return g_strdup(_("Enter the roundabout soon"));
+               case 1:
+                       d = get_distance(distance, type, 1);
+                       /* TRANSLATORS: %s is the distance to the roundabout */
+                       ret = g_strdup_printf(_("In %s, enter the roundabout"), d);
+                       g_free(d);
+                       return ret;
+               case -2:
+               case 0:
+                       cur = cmd->itm->prev;
+                       count_roundabout = 0;
+                       while (cur && (cur->flags & AF_ROUNDABOUT)) {
+                               if (cur->next->ways && is_way_allowed(cur->next->ways)) { // If the next segment has no exit or the exit isn't allowed, don't count it
+                                       count_roundabout++;
+                               }
+                               cur = cur->prev;
+                       }
+                       switch (level) {
+                       case 0:
+                               ret = g_strdup_printf(_("Leave the roundabout at the %s"), get_exit_count_str(count_roundabout));
+                               break;
+                       case -2:
+                               ret = g_strdup_printf(_("then leave the roundabout at the %s"), get_exit_count_str(count_roundabout));
+                               break;
+                       }
+                       return ret;
+               }
+       }
+
        switch(level) {
        case 3:
                d=get_distance(distance, type, 1);
@@ -950,50 +1460,171 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
                d=get_distance(distance, type, 0);
                break;
        case 0:
-               d=g_strdup(_("now"));
+               skip_roads = count_possible_turns(nav->first,cmd->itm,cmd->delta);
+               if (skip_roads > 0) {
+                       if (get_count_str(skip_roads+1)) {
+                               /* TRANSLATORS: First argument is the how manieth street to take, second the direction */ 
+                               ret = g_strdup_printf(_("Take the %1$s road to the %2$s"), get_count_str(skip_roads+1), dir);
+                               return ret;
+                       } else {
+                               d = g_strdup_printf(_("after %i roads"), skip_roads);
+                       }
+               } else {
+                       d=g_strdup(_("now"));
+               }
+               break;
+       case -2:
+               skip_roads = count_possible_turns(cmd->prev->itm,cmd->itm,cmd->delta);
+               if (skip_roads > 0) {
+                       /* TRANSLATORS: First argument is the how manieth street to take, second the direction */ 
+                       if (get_count_str(skip_roads+1)) {
+                               ret = g_strdup_printf(_("then take the %1$s road to the %2$s"), get_count_str(skip_roads+1), dir);
+                               return ret;
+                       } else {
+                               d = g_strdup_printf(_("after %i roads"), skip_roads);
+                       }
+
+               } else {
+                       d = g_strdup("");
+               }
                break;
        default:
                d=g_strdup(_("error"));
        }
        if (cmd->itm->next) {
                int tellstreetname = 0;
-               char *destination = NULL; 
+               char *destination = NULL;
  
                if(type == attr_navigation_speech) { // In voice mode
                        // In Voice Mode only tell the street name in level 1 or in level 0 if level 1
                        // was skipped
 
                        if (level == 1) { // we are close to the intersection
-                               cmd->itm->told = 1; // remeber to be checked when we turn
+                               cmd->itm->streetname_told = 1; // remeber to be checked when we turn
                                tellstreetname = 1; // Ok so we tell the name of the street 
                        }
 
                        if (level == 0) {
-                               if(cmd->itm->told == 0) // we are right at the intersection
+                               if(cmd->itm->streetname_told == 0) // we are right at the intersection
                                        tellstreetname = 1; 
                                else
-                                       cmd->itm->told = 0;  // reset just in case we come to the same street again
+                                       cmd->itm->streetname_told = 0;  // reset just in case we come to the same street again
                        }
 
                }
                else
                     tellstreetname = 1;
 
-               if(tellstreetname) 
+               if(nav->tell_street_name && tellstreetname)
                        destination=navigation_item_destination(cmd->itm, itm, " ");
-               /* 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' */
-               ret=g_strdup_printf(_("Turn %1$s%2$s %3$s%4$s"), strength, dir, d, destination ? destination:"");
+
+               if (level != -2) {
+                       /* 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' */
+                       ret=g_strdup_printf(_("Turn %1$s%2$s %3$s%4$s"), strength, dir, d, destination ? destination:"");
+               } else {
+                       /* TRANSLATORS: First argument is strength, second direction, third how many roads to skip, fourth destination */
+                       ret=g_strdup_printf(_("then turn %1$s%2$s %3$s%4$s"), strength, dir, d, destination ? destination:"");
+               }
                g_free(destination);
-       } else
-               ret=g_strdup_printf(_("You have reached your destination %s"), d);
+       } else {
+               if (!connect) {
+                       ret=g_strdup_printf(_("You have reached your destination %s"), d);
+               } else {
+                       ret=g_strdup_printf(_("then you have reached your destination."));
+               }
+       }
        g_free(d);
        return ret;
 }
 
+/**
+ * @brief Creates announcements for maneuvers, plus maneuvers immediately following the next maneuver
+ *
+ * This function does create an announcement for the current maneuver and for maneuvers
+ * immediately following that maneuver, if these are too close and we're in speech navigation.
+ *
+ * @return An announcement that should be made
+ */
+static char *
+show_next_maneuvers(struct navigation *nav, struct navigation_itm *itm, struct navigation_command *cmd, enum attr_type type)
+{
+       struct navigation_command *cur,*prev;
+       int distance=itm->dest_length-cmd->itm->dest_length;
+       int level, dist, i, time;
+       int speech_time,time2nav;
+       char *ret,*old,*buf,*next;
+
+       if (type != attr_navigation_speech) {
+               return show_maneuver(nav, itm, cmd, type, 0); // We accumulate maneuvers only in speech navigation
+       }
+
+       level=navigation_get_announce_level(nav, itm->item.type, distance-cmd->length);
+
+       if (level > 1) {
+               return show_maneuver(nav, itm, cmd, type, 0); // We accumulate maneuvers only if they are close
+       }
+
+       if (cmd->itm->told) {
+               return g_strdup("");
+       }
+
+       ret = show_maneuver(nav, itm, cmd, type, 0);
+       time2nav = navigation_time(itm,cmd->itm->prev);
+       old = NULL;
+
+       cur = cmd->next;
+       prev = cmd;
+       i = 0;
+       while (cur && cur->itm) {
+               // We don't merge more than 3 announcements...
+               if (i > 1) { // if you change this, please also change the value below, that is used to terminate the loop
+                       break;
+               }
+               
+               next = show_maneuver(nav,prev->itm, cur, type, 0);
+               speech_time = navit_speech_estimate(nav->navit,next);
+               g_free(next);
+
+               if (speech_time == -1) { // user didn't set cps
+                       speech_time = 30; // assume 3 seconds
+               }
+
+               dist = prev->itm->dest_length - cur->itm->dest_length;
+               time = navigation_time(prev->itm,cur->itm->prev);
+
+               if (time >= (speech_time + 30)) { // 3 seconds for understanding what has been said
+                       break;
+               }
+
+               old = ret;
+               buf = show_maneuver(nav, prev->itm, cur, type, 1);
+               ret = g_strdup_printf("%s, %s", old, buf);
+               g_free(buf);
+               if (navit_speech_estimate(nav->navit,ret) > time2nav) {
+                       g_free(ret);
+                       ret = old;
+                       i = 2; // This will terminate the loop
+               } else {
+                       g_free(old);
+               }
+
+               // If the two maneuvers are *really* close, we shouldn't tell the second one again, because TTS won't be fast enough
+               if (time <= speech_time) {
+                       cur->itm->told = 1;
+               }
+
+               prev = cur;
+               cur = cur->next;
+               i++;
+       }
+
+       return ret;
+}
+
 static void
 navigation_call_callbacks(struct navigation *this_, int force_speech)
 {
-       int distance, level = 0;
+       int distance, level = 0, level2;
        void *p=this_;
        if (!this_->cmd_first)
                return;
@@ -1013,7 +1644,13 @@ navigation_call_callbacks(struct navigation *this_, int force_speech)
                }
        } else if (!this_->turn_around_limit || this_->turn_around == -this_->turn_around_limit+1) {
                this_->distance_turn=50;
+               distance-=this_->cmd_first->length;
                level=navigation_get_announce_level(this_, this_->first->item.type, distance);
+               if (this_->cmd_first->itm->prev) {
+                       level2=navigation_get_announce_level(this_, this_->cmd_first->itm->prev->item.type, distance);
+                       if (level2 > level)
+                               level=level2;
+               }
                if (level < this_->level_last) {
                        dbg(1,"level %d < %d\n", level, this_->level_last);
                        this_->level_last=level;
@@ -1032,8 +1669,8 @@ navigation_call_callbacks(struct navigation *this_, int force_speech)
        }
 }
 
-void
-navigation_update(struct navigation *this_, struct route *route)
+static void
+navigation_update(struct navigation *this_, struct route *route, struct attr *attr)
 {
        struct map *map;
        struct map_rect *mr;
@@ -1041,11 +1678,19 @@ navigation_update(struct navigation *this_, struct route *route)
        struct item *sitem;                     /* Holds the corresponding item from the actual map */
        struct attr street_item,street_direction;
        struct navigation_itm *itm;
-       int incr=0,first=1;
+       int mode=0, incr=0, first=1;
+       if (attr->type != attr_route_status)
+               return;
 
-       if (! route)
+       dbg(1,"enter %d\n", mode);
+       if (attr->u.num == route_status_no_destination || attr->u.num == route_status_not_found || attr->u.num == route_status_path_done_new) 
+               navigation_flush(this_);
+       if (attr->u.num != route_status_path_done_new && attr->u.num != route_status_path_done_incremental)
+               return;
+               
+       if (! this_->route)
                return;
-       map=route_get_map(route);
+       map=route_get_map(this_->route);
        if (! map)
                return;
        mr=map_rect_new(map, NULL);
@@ -1053,6 +1698,12 @@ navigation_update(struct navigation *this_, struct route *route)
                return;
        dbg(1,"enter\n");
        while ((ritem=map_rect_get_item(mr))) {
+               if (ritem->type == type_route_start && this_->turn_around > -this_->turn_around_limit+1)
+                       this_->turn_around--;
+               if (ritem->type == type_route_start_reverse && this_->turn_around < this_->turn_around_limit)
+                       this_->turn_around++;
+               if (ritem->type != type_street_route)
+                       continue;
                if (first && item_attr_get(ritem, attr_street_item, &street_item)) {
                        first=0;
                        if (!item_attr_get(ritem, attr_direction, &street_direction))
@@ -1074,32 +1725,22 @@ navigation_update(struct navigation *this_, struct route *route)
                }
                navigation_itm_new(this_, ritem);
        }
+       dbg(2,"turn_around=%d\n", this_->turn_around);
        if (first) 
                navigation_destroy_itms_cmds(this_, NULL);
        else {
                if (! ritem) {
                        navigation_itm_new(this_, NULL);
-                       make_maneuvers(this_,route);
+                       make_maneuvers(this_,this_->route);
                }
                calculate_dest_distance(this_, incr);
-               dbg(2,"destination distance old=%d new=%d\n", this_->distance_last, this_->first->dest_length);
-               if (this_->first->dest_length > this_->distance_last && this_->distance_last >= 0) 
-                       this_->turn_around++;
-               else
-                       this_->turn_around--;
-               if (this_->turn_around > this_->turn_around_limit)
-                       this_->turn_around=this_->turn_around_limit;
-               else if (this_->turn_around < -this_->turn_around_limit+1)
-                       this_->turn_around=-this_->turn_around_limit+1;
-               dbg(2,"turn_around=%d\n", this_->turn_around);
-               this_->distance_last=this_->first->dest_length;
                profile(0,"end");
                navigation_call_callbacks(this_, FALSE);
        }
        map_rect_destroy(mr);
 }
 
-void
+static void
 navigation_flush(struct navigation *this_)
 {
        navigation_destroy_itms_cmds(this_, NULL);
@@ -1202,28 +1843,28 @@ navigation_map_item_attr_get(void *priv_data, enum attr_type attr_type, struct a
        case attr_navigation_short:
                this_->attr_next=attr_navigation_long;
                if (cmd) {
-                       this_->str=attr->u.str=show_maneuver(this_->nav, this_->cmd_itm, cmd, attr_type);
+                       this_->str=attr->u.str=show_next_maneuvers(this_->nav, this_->cmd_itm, cmd, attr_type);
                        return 1;
                }
                return 0;
        case attr_navigation_long:
                this_->attr_next=attr_navigation_long_exact;
                if (cmd) {
-                       this_->str=attr->u.str=show_maneuver(this_->nav, this_->cmd_itm, cmd, attr_type);
+                       this_->str=attr->u.str=show_next_maneuvers(this_->nav, this_->cmd_itm, cmd, attr_type);
                        return 1;
                }
                return 0;
        case attr_navigation_long_exact:
                this_->attr_next=attr_navigation_speech;
                if (cmd) {
-                       this_->str=attr->u.str=show_maneuver(this_->nav, this_->cmd_itm, cmd, attr_type);
+                       this_->str=attr->u.str=show_next_maneuvers(this_->nav, this_->cmd_itm, cmd, attr_type);
                        return 1;
                }
                return 0;
        case attr_navigation_speech:
                this_->attr_next=attr_length;
                if (cmd) {
-                       this_->str=attr->u.str=show_maneuver(this_->nav, this_->cmd_itm, this_->cmd, attr_type);
+                       this_->str=attr->u.str=show_next_maneuvers(this_->nav, this_->cmd_itm, this_->cmd, attr_type);
                        return 1;
                }
                return 0;
@@ -1254,11 +1895,13 @@ navigation_map_item_attr_get(void *priv_data, enum attr_type attr_type, struct a
                this_->attr_next=attr_street_name_systematic;
                if (attr->u.str)
                        return 1;
+               return 0;
        case attr_street_name_systematic:
                attr->u.str=itm->name2;
                this_->attr_next=attr_debug;
                if (attr->u.str)
                        return 1;
+               return 0;
        case attr_debug:
                switch(this_->debug_idx) {
                case 0:
@@ -1301,12 +1944,22 @@ navigation_map_item_attr_get(void *priv_data, enum attr_type attr_type, struct a
                                return 1;
                        }
                case 7:
-                       if (this_->ways) {
-                               this_->str=attr->u.str=g_strdup_printf("other item angle %d type %s id (0x%x,0x%x)", this_->ways->angle2, item_to_name(this_->ways->item.type), this_->ways->item.id_hi, this_->ways->item.id_lo);
+                       if (this_->ways && prev) {
+                               this_->str=attr->u.str=g_strdup_printf("other item angle:%d delta:%d flags:%d dir:%d type:%s id:(0x%x,0x%x)", this_->ways->angle2, angle_delta(prev->angle_end, this_->ways->angle2), this_->ways->flags, this_->ways->dir, item_to_name(this_->ways->item.type), this_->ways->item.id_hi, this_->ways->item.id_lo);
                                this_->ways=this_->ways->next;
                                return 1;
                        }
                        this_->debug_idx++;
+               case 8:
+                       this_->debug_idx++;
+                       if (prev) {
+                               int delta=0;
+                               char *reason=NULL;
+                               maneuver_required2(prev, itm, &delta, &reason);
+                               this_->str=attr->u.str=g_strdup_printf("reason:%s",reason);
+                               return 1;
+                       }
+                       
                default:
                        this_->attr_next=attr_none;
                        return 0;
@@ -1353,6 +2006,9 @@ navigation_map_rect_new(struct map_priv *priv, struct map_selection *sel)
        navigation_map_rect_init(ret);
        ret->item.meth=&navigation_map_item_methods;
        ret->item.priv_data=ret;
+#ifdef DEBUG
+       ret->show_all=1;
+#endif
        return ret;
 }
 
@@ -1387,26 +2043,57 @@ navigation_map_get_item(struct map_rect_priv *priv)
                if (priv->cmd_itm_next && !priv->cmd_itm_next->next)
                        ret->type=type_nav_destination;
                else {
-                       delta=priv->cmd->delta; 
-                       if (delta < 0) {
-                               delta=-delta;
-                               if (delta < 45)
-                                       ret->type=type_nav_left_1;
-                               else if (delta < 105)
-                                       ret->type=type_nav_left_2;
-                               else if (delta < 165) 
-                                       ret->type=type_nav_left_3;
-                               else
-                                       ret->type=type_none;
+                       if (priv->itm && priv->itm->prev && !(priv->itm->flags & AF_ROUNDABOUT) && (priv->itm->prev->flags & AF_ROUNDABOUT)) {
+                       
+                               switch (((180+22)-priv->cmd->roundabout_delta)/45) {
+                               case 0:
+                               case 1:
+                                       ret->type=type_nav_roundabout_r1;
+                                       break;
+                               case 2:
+                                       ret->type=type_nav_roundabout_r2;
+                                       break;
+                               case 3:
+                                       ret->type=type_nav_roundabout_r3;
+                                       break;
+                               case 4:
+                                       ret->type=type_nav_roundabout_r4;
+                                       break;
+                               case 5:
+                                       ret->type=type_nav_roundabout_r5;
+                                       break;
+                               case 6:
+                                       ret->type=type_nav_roundabout_r6;
+                                       break;
+                               case 7:
+                                       ret->type=type_nav_roundabout_r7;
+                                       break;
+                               case 8:
+                                       ret->type=type_nav_roundabout_r8;
+                                       break;
+                               }
                        } else {
-                               if (delta < 45)
-                                       ret->type=type_nav_right_1;
-                               else if (delta < 105)
-                                       ret->type=type_nav_right_2;
-                               else if (delta < 165) 
-                                       ret->type=type_nav_right_3;
-                               else
-                                       ret->type=type_none;
+                               delta=priv->cmd->delta; 
+                               if (delta < 0) {
+                                       delta=-delta;
+                                       if (delta < 45)
+                                               ret->type=type_nav_left_1;
+                                       else if (delta < 105)
+                                               ret->type=type_nav_left_2;
+                                       else if (delta < 165) 
+                                               ret->type=type_nav_left_3;
+                                       else
+                                               ret->type=type_none;
+                               } else {
+                                       if (delta < 45)
+                                               ret->type=type_nav_right_1;
+                                       else if (delta < 105)
+                                               ret->type=type_nav_right_2;
+                                       else if (delta < 165) 
+                                               ret->type=type_nav_right_3;
+                                       else
+                                               ret->type=type_none;
+                               }
                        }
                }
        }
@@ -1460,6 +2147,16 @@ navigation_map_new(struct map_methods *meth, struct attr **attrs)
        return ret;
 }
 
+void
+navigation_set_route(struct navigation *this_, struct route *route)
+{
+       struct attr callback;
+       this_->route=route;
+       this_->route_cb=callback_new_attr_1(callback_cast(navigation_update), attr_route_status, this_);
+       callback.type=attr_callback;
+       callback.u.callback=this_->route_cb;
+       route_add_attr(route, &callback);
+}
 
 void
 navigation_init(void)