Fix:Core:Renamed src to navit for cleanup of includes
[navit-package] / navit / search.c
1 #include <glib.h>
2 #include <string.h>
3 #include "debug.h"
4 #include "projection.h"
5 #include "map.h"
6 #include "mapset.h"
7 #include "coord.h"
8 #include "item.h"
9 #include "search.h"
10
11 struct search_list_level {
12         struct mapset *ms;
13         struct item *parent;
14         struct attr attr;
15         int partial;
16         struct mapset_search *search;
17         GHashTable *hash;
18         GList *list,*curr,*last;
19 };
20
21 struct search_list {
22         struct mapset *ms;
23         int level;
24         struct search_list_level levels[4];
25         struct search_list_result result;
26 };
27
28 static guint
29 search_item_hash_hash(gconstpointer key)
30 {
31         const struct item *itm=key;
32         gconstpointer hashkey=(gconstpointer)(itm->id_hi^itm->id_lo);
33         return g_direct_hash(hashkey);
34 }
35
36 static gboolean
37 search_item_hash_equal(gconstpointer a, gconstpointer b)
38 {
39         const struct item *itm_a=a;
40         const struct item *itm_b=b;
41         if (item_is_equal_id(*itm_a, *itm_b))
42                 return TRUE;
43         return FALSE;
44 }
45
46 struct search_list *
47 search_list_new(struct mapset *ms)
48 {
49         struct search_list *ret;
50
51         ret=g_new0(struct search_list, 1);
52         ret->ms=ms;
53         
54         return ret;
55 }
56
57 static void search_list_search_free(struct search_list *sl, int level);
58 void
59 search_list_search(struct search_list *this_, struct attr *search_attr, int partial)
60 {
61         int level=-1;
62         struct search_list_level *le;
63         switch(search_attr->type) {
64         case attr_country_all:
65         case attr_country_id:
66         case attr_country_iso2:
67         case attr_country_iso3:
68         case attr_country_car:
69         case attr_country_name:
70                 level=0;
71                 break;
72         case attr_town_postal:
73                 level=1;
74                 break;
75         case attr_town_name:
76                 level=1;
77                 break;
78         case attr_street_name:
79                 level=2;
80                 break;
81         default:
82                 break;
83         }
84         dbg(0,"level=%d\n", level);
85         if (level != -1) {
86                 this_->level=level;
87                 le=&this_->levels[level];
88                 le->attr=*search_attr;
89                 if (search_attr->type != attr_country_id)
90                         le->attr.u.str=g_strdup(search_attr->u.str);
91                 search_list_search_free(this_, level);
92                 le->partial=partial;
93                 if (level > 0) {
94                         le=&this_->levels[level-1];
95                         le->curr=le->list;
96                 }
97                 dbg(1,"le=%p partial=%d\n", le, partial);
98         }
99 }
100
101 static struct search_list_country *
102 search_list_country_new(struct item *item)
103 {
104         struct search_list_country *ret=g_new0(struct search_list_country, 1);
105         struct attr attr;
106
107         ret->item=*item;
108         if (item_attr_get(item, attr_country_car, &attr))
109                 ret->car=g_strdup(attr.u.str);
110         if (item_attr_get(item, attr_country_iso2, &attr))
111                 ret->iso2=g_strdup(attr.u.str);
112         if (item_attr_get(item, attr_country_iso3, &attr))
113                 ret->iso3=g_strdup(attr.u.str);
114         if (item_attr_get(item, attr_country_name, &attr))
115                 ret->name=g_strdup(attr.u.str);
116         return ret;
117 }
118
119 static void
120 search_list_country_destroy(struct search_list_country *this_)
121 {
122         g_free(this_->car);
123         g_free(this_->iso2);
124         g_free(this_->iso3);
125         g_free(this_->name);
126         g_free(this_);
127 }
128
129 static struct search_list_town *
130 search_list_town_new(struct item *item)
131 {
132         struct search_list_town *ret=g_new0(struct search_list_town, 1);
133         struct attr attr;
134         struct coord c;
135         
136         ret->itemt=*item;
137         if (item_attr_get(item, attr_town_streets_item, &attr)) {
138                 dbg(1,"town_assoc 0x%x 0x%x\n", attr.u.item->id_hi, attr.u.item->id_lo);
139                 ret->item=*attr.u.item;
140         }
141         else
142                 ret->item=*item;
143         if (item_attr_get(item, attr_town_name, &attr))
144                 ret->name=map_convert_string(item->map,attr.u.str);
145         if (item_attr_get(item, attr_town_postal, &attr))
146                 ret->postal=map_convert_string(item->map,attr.u.str);
147         if (item_attr_get(item, attr_district_name, &attr))
148                 ret->district=map_convert_string(item->map,attr.u.str);
149         if (item_coord_get(item, &c, 1)) {
150                 ret->c=g_new(struct pcoord, 1);
151                 ret->c->x=c.x;
152                 ret->c->y=c.y;
153                 ret->c->pro = map_projection(item->map);
154         }
155         return ret;
156 }
157
158 static void
159 search_list_town_destroy(struct search_list_town *this_)
160 {
161         map_convert_free(this_->name);
162         map_convert_free(this_->postal);
163         if (this_->c)
164                 g_free(this_->c);
165         g_free(this_);
166 }
167
168 static struct search_list_street *
169 search_list_street_new(struct item *item)
170 {
171         struct search_list_street *ret=g_new0(struct search_list_street, 1);
172         struct attr attr;
173         struct coord c;
174         
175         ret->item=*item;
176         if (item_attr_get(item, attr_street_name, &attr))
177                 ret->name=map_convert_string(item->map, attr.u.str);
178         if (item_coord_get(item, &c, 1)) {
179                 ret->c=g_new(struct pcoord, 1);
180                 ret->c->x=c.x;
181                 ret->c->y=c.y;
182                 ret->c->pro = map_projection(item->map);
183         }
184         return ret;
185 }
186
187 static void
188 search_list_street_destroy(struct search_list_street *this_)
189 {
190         map_convert_free(this_->name);
191         if (this_->c)
192                 g_free(this_->c);
193         g_free(this_);
194 }
195
196
197 static void
198 search_list_result_destroy(int level, void *p)
199 {
200         switch (level) {
201         case 0:
202                 search_list_country_destroy(p);
203                 break;
204         case 1:
205                 search_list_town_destroy(p);
206                 break;
207         case 2:
208                 search_list_street_destroy(p);
209                 break;
210         }
211 }
212
213 static void
214 search_list_search_free(struct search_list *sl, int level)
215 {
216         struct search_list_level *le=&sl->levels[level];
217         GList *next,*curr;
218         if (le->search) {
219                 mapset_search_destroy(le->search);
220                 le->search=NULL;
221         }
222 #if 0 /* FIXME */
223         if (le->hash) {
224                 g_hash_table_destroy(le->hash);
225                 le->hash=NULL;
226         }
227 #endif
228         curr=le->list;
229         while (curr) {
230                 search_list_result_destroy(level, curr->data);
231                 next=g_list_next(curr);
232                 curr=next;
233         }
234         g_list_free(le->list);
235         le->list=NULL;
236         le->curr=NULL;
237         le->last=NULL;
238
239 }
240
241 static int
242 search_add_result(struct search_list_level *le, void *p)
243 {
244         if (! g_hash_table_lookup(le->hash, p)) {
245                 g_hash_table_insert(le->hash, p, (void *)1);    
246                 le->list=g_list_append(le->list, p);
247                 return 1;
248         }
249         return 0;
250 }
251
252 struct search_list_result *
253 search_list_get_result(struct search_list *this_)
254 {
255         struct search_list_level *le,*leu;
256         struct item *item;
257         int level=this_->level;
258
259         dbg(1,"enter\n");
260         le=&this_->levels[level];
261         dbg(1,"le=%p\n", le);
262         for (;;) {
263                 dbg(1,"le->search=%p\n", le->search);
264                 if (! le->search) {
265                         dbg(1,"partial=%d\n", le->partial);
266                         if (! level) 
267                                 le->parent=NULL;
268                         else {
269                                 leu=&this_->levels[level-1];
270                                 if (! leu->curr)
271                                         break;
272                                 le->parent=leu->curr->data;
273                                 leu->last=leu->curr;
274                                 leu->curr=g_list_next(leu->curr);
275                         }
276                         if (le->parent)
277                                 dbg(1,"mapset_search_new with item(%d,%d)\n", le->parent->id_hi, le->parent->id_lo);
278                         dbg(1,"attr=%s\n", attr_to_name(le->attr.type));        
279                         le->search=mapset_search_new(this_->ms, le->parent, &le->attr, le->partial);
280                         le->hash=g_hash_table_new(search_item_hash_hash, search_item_hash_equal);
281                 }
282                 dbg(1,"le->search=%p\n", le->search);
283                 item=mapset_search_get_item(le->search);
284                 dbg(1,"item=%p\n", item);
285                 if (item) {
286                         void *p=NULL;
287                         dbg(1,"id_hi=%d id_lo=%d\n", item->id_hi, item->id_lo);
288                         this_->result.country=NULL;
289                         this_->result.town=NULL;
290                         this_->result.street=NULL;
291                         this_->result.c=NULL;
292                         switch (level) {
293                         case 0:
294                                 p=search_list_country_new(item);
295                                 this_->result.country=p;
296                                 break;
297                         case 1:
298                                 p=search_list_town_new(item);
299                                 this_->result.country=this_->levels[0].last->data;
300                                 this_->result.town=p;
301                                 this_->result.c=this_->result.town->c;
302                                 break;
303                         case 2:
304                                 p=search_list_street_new(item);
305                                 this_->result.country=this_->levels[0].last->data;
306                                 this_->result.town=this_->levels[1].last->data;
307                                 this_->result.street=p;
308                                 this_->result.c=this_->result.street->c;
309                                 break;
310                         }
311                         if (p) {
312                                 if (search_add_result(le, p)) 
313                                         return &this_->result;
314                                 else 
315                                         search_list_result_destroy(level, p);
316                         }
317                 } else {
318                         mapset_search_destroy(le->search);
319                         le->search=NULL;
320                         g_hash_table_destroy(le->hash);
321                         if (! level)
322                                 break;
323                 }
324         }
325         return NULL;
326 }
327
328 void
329 search_list_destroy(struct search_list *this_)
330 {
331         g_free(this_);
332 }