Fix:map_csv:Disable default notification of each deleted item.
[profile/ivi/navit.git] / navit / navit / map / csv / csv.c
1 /**
2  * Navit, a modular navigation system.
3  * Copyright (C) 2005-2011 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
21 #include "config.h"
22
23 #include <stdlib.h>
24 #include <glib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <math.h>
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 #include "debug.h"
32 #include "plugin.h"
33 #include "projection.h"
34 #include "item.h"
35 #include "map.h"
36 #include "maptype.h"
37 #include "attr.h"
38 #include "transform.h"
39 #include "file.h"
40 #include "quadtree.h"
41
42 #include "csv.h"
43
44 static int map_id;
45
46 /*prototypes*/
47 static int
48 csv_coord_set(void *priv_data, struct coord *c, int count, enum change_mode mode);
49 static struct item * csv_create_item(struct map_rect_priv *mr, enum item_type it_type);
50 static void quadtree_item_free(void *mr, struct quadtree_item *qitem);
51 static void quadtree_item_free_do(void *qitem);
52
53
54 struct quadtree_data 
55 {
56         enum item_type type;
57         int id_lo;
58         GList* attr_list;
59         struct item *item;
60 };
61
62
63 struct quadtree_data *quadtree_data_dup(struct quadtree_data *qdata)
64 {
65         struct quadtree_data *ret=g_new0(struct quadtree_data,1);
66         GList *l;
67         ret->type=qdata->type;
68         ret->id_lo=qdata->id_lo;
69         ret->item=g_new(struct item,1);
70         *(ret->item)=*(qdata->item);
71         for(l=qdata->attr_list;l;l=g_list_next(l)) {
72                 ret->attr_list=g_list_prepend(ret->attr_list,attr_dup(l->data));
73         }
74         return ret;
75 }
76
77 static void 
78 save_map_csv(struct map_priv *m)
79 {
80         if(m->filename && m->dirty) {
81                 char* filename = g_strdup_printf("%s.tmp",m->filename); 
82                 FILE* fp;
83                 int ferr = 0;
84                 char *csv_line = 0;
85                 char *tmpstr = 0;
86                 char *oldstr = 0;
87                 struct quadtree_iter *iter;
88                 struct quadtree_item *qitem;
89
90                 if( ! (fp=fopen(filename,"w+"))) {
91                         dbg(0, "Error opening csv file to write new entries");
92                         return;
93                 }
94                 /*query the world*/
95                 iter=quadtree_query(m->tree_root, -180, 180, -180, 180, quadtree_item_free, m);
96
97                 while((qitem = quadtree_item_next(iter))!=NULL) {
98                         int i;
99                         enum attr_type *at = m->attr_types;
100                         if(qitem->deleted) 
101                                 continue;
102                         csv_line = NULL;
103                         tmpstr = NULL;
104                         for(i=0;i<m->attr_cnt;++i) {
105                                 if(*at == attr_position_latitude) {
106                                         tmpstr = g_strdup_printf("%lf",qitem->latitude);
107                                 } else if(*at == attr_position_longitude) {
108                                         tmpstr = g_strdup_printf("%lf",qitem->longitude);
109                                 } else {
110                                         GList* attr_list = ((struct quadtree_data*)(qitem->data))->attr_list;
111                                         GList* attr_it = attr_list;
112                                         struct attr* found_attr = NULL;
113                                         /*search attributes*/
114                                         while(attr_it) {
115                                                 if(((struct attr*)(attr_it->data))->type == *at) {
116                                                         found_attr = attr_it->data;
117                                                         break;
118                                                 }
119                                                 attr_it = g_list_next(attr_it);
120                                         }
121                                         if(found_attr) {
122                                                 if(ATTR_IS_INT(*at)) {
123                                                         tmpstr = g_strdup_printf("%d", (int)found_attr->u.num);
124                                                 } else if(ATTR_IS_DOUBLE(*at)) {
125                                                         tmpstr = g_strdup_printf("%lf", *found_attr->u.numd);
126                                                 } else if(ATTR_IS_STRING(*at)) {
127                                                         tmpstr = g_strdup(found_attr->u.str);
128                                                 } else {
129                                                         dbg(0,"Cant represent attribute %s\n",attr_to_name(*at));
130                                                         tmpstr=g_strdup("");
131                                                 }
132                                         } else {
133                                                 dbg(0,"No value defined for the atribute %s, assuming empty string\n",attr_to_name(*at));
134                                                 tmpstr=g_strdup("");
135                                         }
136                                 }
137                                 if(i>0) {
138                                         oldstr = csv_line;
139                                         csv_line = g_strdup_printf("%s,%s",csv_line,tmpstr);
140                                         g_free(tmpstr);
141                                         g_free(oldstr);
142                                         tmpstr = NULL;
143                                 } else {
144                                         csv_line=tmpstr;
145                                 }
146                                 ++at;
147                         }
148                         if(fprintf(fp,"%s\n", csv_line)<0) {
149                                 ferr = 1;
150                         }
151                 }
152
153                 if(fclose(fp)) {
154                         ferr = 1;
155                 }
156
157                 if(! ferr) {
158                         unlink(m->filename);
159                         rename(filename,m->filename);
160                         m->dirty = 0;
161                 }
162                 g_free(filename);
163                 quadtree_query_free(iter);
164
165         }
166 }
167
168 static const int zoom_max = 18;
169
170 static void
171 map_destroy_csv(struct map_priv *m)
172 {
173         dbg(1,"map_destroy_csv\n");
174         /*save if changed */
175         save_map_csv(m);        
176         g_hash_table_destroy(m->qitem_hash);
177         quadtree_destroy(m->tree_root);
178         g_free(m->filename);
179         g_free(m->attr_types);
180         g_free(m);
181 }
182
183 static void
184 csv_coord_rewind(void *priv_data)
185 {
186 }
187
188 static int
189 csv_coord_get(void *priv_data, struct coord *c, int count)
190 {
191         struct map_rect_priv *mr=priv_data;
192         if(mr) {
193                 *c = mr->c;
194                 return 1;
195         }
196         else {
197                 return 0;
198         }
199 }
200
201 static void
202 csv_attr_rewind(void *priv_data)
203 {
204         /*TODO implement if needed*/
205 }
206
207 static int
208 csv_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
209 {
210         int i, bAttrFound = 0;
211         GList* attr_list;
212         struct map_rect_priv *mr=priv_data;
213         enum attr_type *at;
214         if( !mr || !mr->m || !mr->m->attr_types ) {
215                 return 0;
216         }
217
218         attr_list = ((struct quadtree_data*)(mr->qitem->data))->attr_list;
219
220         if (attr_type == attr_any) {
221                 if (mr->at_iter==NULL) {        /*start iteration*/
222                         mr->at_iter = attr_list;
223                         if (mr->at_iter) {
224                                 *attr = *(struct attr*)(mr->at_iter->data);
225                                 return 1;
226                         } else {                /*empty attr list*/
227                                 mr->at_iter = NULL;     
228                                 return 0;
229                         }
230                 } else {                        /*continue iteration*/
231                         mr->at_iter = g_list_next(mr->at_iter); 
232                         if(mr->at_iter) {
233                                 *attr = *(struct attr*)mr->at_iter->data;
234                                 return 1;
235                         } else {
236                                 return 0;
237                         }
238                 }
239                 return 0;
240         }
241
242         at = mr->m->attr_types;
243
244         for(i=0;i<mr->m->attr_cnt;++i) {
245                 if(*at == attr_type) {
246                         bAttrFound = 1;
247                         break;
248                 }
249                 ++at;
250         }
251
252         if(!bAttrFound) {
253                 return 0;
254         }
255
256         while(attr_list) {
257                 if(((struct attr*)attr_list->data)->type == attr_type) {
258                         *attr = *(struct attr*)attr_list->data;
259                         return 1;
260                 }
261                 attr_list = g_list_next(attr_list);     
262         }
263         return 0;
264 }
265
266 static int
267 csv_attr_set(void *priv_data, struct attr *attr, enum change_mode mode)
268 {
269         struct map_rect_priv* mr = (struct map_rect_priv*)priv_data;
270         struct map_priv* m = mr->m;
271         int i, bFound = 0;
272         struct attr *attr_new;
273         GList *attr_list, *curr_attr_list;
274         enum attr_type *at = m->attr_types;
275
276         if(!mr || !mr->qitem) {
277                 return 0;
278         }
279
280         /*if attribute is not supported by this csv map return 0*/
281         for(i=0;i<m->attr_cnt;++i) {
282                 if(*at==attr->type) {
283                         bFound = 1;
284                         break;
285                 }
286                 ++at;
287         }
288         if( ! bFound) {
289                 return 0;
290         }
291         m->dirty = 1;
292         attr_new = attr_dup(attr);
293         attr_list = ((struct quadtree_data*)(mr->qitem->data))->attr_list;
294         curr_attr_list = attr_list;
295
296         while(attr_list) {
297                 if(((struct attr*)attr_list->data)->type == attr->type) {
298                         switch(mode) {
299                                 case change_mode_delete:
300                                         attr_free((struct attr*)attr_list->data);
301                                         curr_attr_list = g_list_delete_link(curr_attr_list,attr_list);
302                                         m->dirty = 1;
303                                         /* FIXME: To preserve consistency, may be the save_map_csv should be called here... */
304                                         attr_free(attr_new);
305                                         return 1;
306                                 case change_mode_modify:
307                                 case change_mode_prepend:
308                                 case change_mode_append:
309                                         /* replace existing attribute */
310                                         if(attr_list->data) {
311                                                 attr_free((struct attr*)attr_list->data);
312                                         }
313                                         attr_list->data = attr_new;
314                                         m->dirty = 1;
315                                         save_map_csv(m);
316                                         return 1;
317                                 default:
318                                         attr_free(attr_new);
319                                         return 0;
320                         }
321                 }
322                 attr_list = g_list_next(attr_list);     
323         }
324
325         if( mode==change_mode_modify || mode==change_mode_prepend || mode==change_mode_append) {
326                 /* add new attribute */
327                 curr_attr_list = g_list_prepend(curr_attr_list, attr_new);      
328                 ((struct quadtree_data*)(mr->qitem->data))->attr_list = curr_attr_list;
329                         m->dirty = 1;
330                         save_map_csv(m);
331                 return 1;
332         }
333         attr_free(attr_new);
334         return 0;
335 }
336
337 static int
338 csv_type_set(void *priv_data, enum item_type type)
339 {
340         struct map_rect_priv* mr = (struct map_rect_priv*)priv_data;
341         dbg(1,"Enter %d\n", type);
342
343         if(!mr || !mr->qitem) {
344                 dbg(1,"Nothing to do\n");
345                 return 0;
346         }
347         
348         if(type!=type_none)
349                 return 0;
350         
351         mr->qitem->deleted=1;
352         dbg(1,"Item %p is deleted\n",mr->qitem);
353
354         return 1;
355 }
356
357 static struct item_methods methods_csv = {
358         csv_coord_rewind,
359         csv_coord_get,
360         csv_attr_rewind,
361         csv_attr_get,
362         NULL,
363         csv_attr_set,
364         csv_coord_set,
365         csv_type_set
366 };
367
368
369 /*
370  * Sets coordinate of an existing item (either on the new list or an item with coord )
371  */
372 static int
373 csv_coord_set(void *priv_data, struct coord *c, int count, enum change_mode mode)
374 {
375         struct quadtree_item query_item, *insert_item, *query_res;
376         struct coord_geo cg;
377         struct map_rect_priv* mr;
378         struct map_priv* m;
379         struct quadtree_item* qi;
380         GList* new_it;
381         dbg(1,"Set coordinates %d %d\n", c->x, c->y);
382
383         /* for now we only support coord modification only */
384         if( ! change_mode_modify) {
385                 return 0;
386         }
387         /* csv driver supports one coord per record only */
388         if( count != 1) {
389                 return 0;
390         }
391
392         /* get curr_item of given map_rect */
393         mr = (struct map_rect_priv*)priv_data;
394         m = mr->m;
395
396         if(!mr->qitem) {
397                 return 0;
398         }
399
400         qi = mr->qitem;
401
402         transform_to_geo(projection_mg, &c[0], &cg);
403
404         /* if it is on the new list remove from new list and add it to the tree with the coord */
405         new_it = m->new_items;  
406         while(new_it) {
407                 if(new_it->data==qi) {
408                         break;
409                 }
410                 new_it = g_list_next(new_it);
411         }
412         if(new_it) {
413                 qi->longitude = cg.lng;
414                 qi->latitude = cg.lat;
415                 quadtree_add( m->tree_root, qi, mr->qiter);
416                 dbg(1,"Set coordinates %f %f\n", cg.lng, cg.lat);
417                 m->new_items = g_list_remove_link(m->new_items,new_it);
418                 m->dirty=1;
419                 save_map_csv(m);
420                 return 1;
421         }
422         
423         /* else update quadtree item with the new coord 
424               remove item from the quadtree */
425         query_item.longitude = cg.lng;
426         query_item.latitude = cg.lat;
427         query_res = quadtree_find_item(m->tree_root, &query_item);
428         if(!query_res) {
429                 return 0;
430         }
431         quadtree_delete_item(m->tree_root, query_res);
432         /*    add item to the tree with the new coord */
433         insert_item=g_new0(struct quadtree_item,1);
434         insert_item->data=quadtree_data_dup(query_res->data);
435         insert_item->longitude = cg.lng;
436         insert_item->latitude  = cg.lat;
437         quadtree_add(m->tree_root, query_res, mr->qiter);
438
439         mr->qitem->ref_count--;
440         mr->qitem=insert_item;
441         mr->qitem->ref_count++;
442
443         m->dirty = 1;
444         save_map_csv(m);
445         return 1;
446 }
447
448 static void quadtree_item_free(void *this, struct quadtree_item *qitem)
449 {
450         struct map_priv* m=this;
451         struct quadtree_data * qdata=qitem->data;
452         if(m) {
453                 g_hash_table_remove(m->qitem_hash,&(qdata->item->id_lo));
454         }
455 }
456
457 static void quadtree_item_free_do(void *data)
458 {
459         struct quadtree_item *qitem=data;
460         GList* attr_it;
461         struct attr* attr;
462         struct quadtree_data * qdata=qitem->data;
463         if(qdata) {
464                 for(attr_it = qdata->attr_list;attr_it;attr_it = g_list_next(attr_it)) {
465                         attr = attr_it->data;
466                         attr_free(attr);
467                 }
468                 g_free(qitem->data);
469         }
470         g_free(data);
471 }
472
473 static void map_csv_debug_dump(struct map_priv *map)
474 {
475         GList *l=g_hash_table_get_values(map->qitem_hash);
476         GList *ll=l;
477         while(ll) {
478                 struct quadtree_item *qi;
479                 GList *attrs;
480                 qi=ll->data;
481                 dbg(0,"%p del=%d ref=%d\n", qi,qi->deleted, qi->ref_count);
482                 attrs=((struct quadtree_data *)qi->data)->attr_list;
483                 while(attrs) {
484                         if(((struct attr*)attrs->data)->type==attr_label)
485                                 dbg(0,"... %s\n",((struct attr*)attrs->data)->u.str);
486                         attrs=g_list_next(attrs);
487                 }
488                 ll=g_list_next(ll);
489         }
490         g_list_free(l);
491 }
492
493 static struct map_rect_priv *
494 map_rect_new_csv(struct map_priv *map, struct map_selection *sel)
495 {
496         struct map_rect_priv *mr;
497         struct coord_geo lu;
498         struct coord_geo rl;
499         struct quadtree_iter *res = NULL;
500         dbg(1,"map_rect_new_csv\n");
501
502 #if 0
503         /* Set above value to 1 to have all map data dumped (including deleted items) to the log at each maprect creation */
504         map_csv_debug_dump(map);
505 #endif  
506         
507         mr=g_new0(struct map_rect_priv, 1);
508         mr->m=map;
509         mr->bStarted = 0;
510         mr->sel=sel;
511         if (map->flags & 1)
512                 mr->item.id_hi=1;
513         else
514                 mr->item.id_hi=0;
515         mr->item.id_lo=0;
516         mr->item.meth=&methods_csv;
517         mr->item.priv_data=mr;
518
519         if(!sel) {
520                 lu.lng=-180;
521                 lu.lat=180;
522                 rl.lng=180;
523                 rl.lat=-180;
524         } else {
525                 transform_to_geo(projection_mg, &sel->u.c_rect.lu, &lu);
526                 transform_to_geo(projection_mg, &sel->u.c_rect.rl, &rl);
527         }
528         res=quadtree_query(map->tree_root, lu.lng, rl.lng, rl.lat, lu.lat, quadtree_item_free, mr->m);
529         mr->qiter = res;
530         mr->qitem = NULL;
531         return mr;
532 }
533
534 static void
535 map_rect_destroy_csv(struct map_rect_priv *mr)
536 {
537         if(mr->qitem)
538                 mr->qitem->ref_count--;
539
540         if(mr->qiter)
541                 quadtree_query_free(mr->qiter);
542
543         g_free(mr);
544 }
545
546 static struct item *
547 map_rect_get_item_csv(struct map_rect_priv *mr)
548 {
549
550         if(mr->qitem)
551                 mr->qitem->ref_count--;
552
553         mr->qitem=quadtree_item_next(mr->qiter);
554
555         if(mr->qitem) {
556                 struct item* ret=&(mr->item);
557                 struct coord_geo cg;
558                 mr->qitem->ref_count++;
559                 mr->item = *(((struct quadtree_data*)(mr->qitem->data))->item);
560                 ret->priv_data=mr;
561                 cg.lng = mr->qitem->longitude;
562                 cg.lat = mr->qitem->latitude;
563                 transform_from_geo(projection_mg, &cg, &mr->c);
564                 return ret;
565         }
566         return NULL;
567 }
568
569 static struct item *
570 map_rect_get_item_byid_csv(struct map_rect_priv *mr, int id_hi, int id_lo)
571 {
572         /*currently id_hi is ignored*/
573         
574         struct quadtree_item *qit = g_hash_table_lookup(mr->m->qitem_hash,&id_lo);
575         
576         if(mr->qitem )
577                 mr->qitem->ref_count--;
578         
579         if(qit) {
580                 mr->qitem = qit;
581                 mr->qitem->ref_count++;
582                 mr->item=*(((struct quadtree_data*)(qit->data))->item);
583                 mr->item.priv_data=mr;
584                 return &(mr->item);
585         } else {
586                 mr->qitem = NULL;
587                 return NULL;
588         }
589 }
590
591 static int
592 csv_get_attr(struct map_priv *m, enum attr_type type, struct attr *attr)
593 {
594         return 0;
595 }
596
597 static struct item *
598 csv_create_item(struct map_rect_priv *mr, enum item_type it_type)
599 {
600         struct map_priv* m;
601         struct quadtree_data* qd;
602         struct quadtree_item* qi;
603         struct item* curr_item;
604         int* pID;
605         if(mr && mr->m) {
606                 m = mr->m;
607         }
608         else {
609                 return NULL;
610         }
611
612         if( m->item_type != it_type) {
613                 return NULL;
614         }
615
616         m->dirty = 1;
617         /*add item to the map*/
618         curr_item = item_new("",zoom_max);
619         curr_item->type = m->item_type;
620         curr_item->meth=&methods_csv;
621
622         curr_item->id_lo = m->next_item_idx;
623         if (m->flags & 1)
624                 curr_item->id_hi=1;
625         else
626                 curr_item->id_hi=0;
627
628         qd = g_new0(struct quadtree_data,1);
629         qi = g_new0(struct quadtree_item,1);
630         qd->item = curr_item;
631         qd->attr_list = NULL;
632         qi->data = qd;
633         /*we don`t have valid coord yet*/
634         qi->longitude = 0;
635         qi->latitude  = 0;
636         /*add the coord less item to the new list*/
637         m->new_items = g_list_prepend(m->new_items, qi);
638         if(mr->qitem)
639                 mr->qitem->ref_count--;
640         mr->qitem=qi;
641         mr->item=*curr_item;
642         mr->item.priv_data=mr;
643         mr->qitem->ref_count++;
644         /*don't add to the quadtree yet, wait until we have a valid coord*/
645         pID = g_new(int,1);
646         *pID = m->next_item_idx;
647         g_hash_table_insert(m->qitem_hash, pID,qi);
648         ++m->next_item_idx;
649         return &mr->item;
650 }
651
652 static struct map_methods map_methods_csv = {
653         projection_mg,
654         "iso8859-1",
655         map_destroy_csv,
656         map_rect_new_csv,
657         map_rect_destroy_csv,
658         map_rect_get_item_csv,
659         map_rect_get_item_byid_csv,
660         NULL,
661         NULL,
662         NULL,
663         csv_create_item,
664         csv_get_attr,
665 };
666
667 static struct map_priv *
668 map_new_csv(struct map_methods *meth, struct attr **attrs, struct callback_list *cbl)
669 {
670         struct map_priv *m = NULL;
671         struct attr *item_type;
672         struct attr *attr_types;
673         struct attr *item_type_attr;
674         struct attr *data;
675         struct attr *flags;
676         struct attr *charset;
677         int bLonFound = 0;
678         int bLatFound = 0;
679         int attr_cnt = 0;
680         enum attr_type* attr_type_list = NULL;  
681         struct quadtree_node* tree_root = quadtree_node_new(NULL,-180,180,-180,180);
682         m = g_new0(struct map_priv, 1);
683         m->id = ++map_id;
684         m->qitem_hash = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, quadtree_item_free_do);
685
686         item_type  = attr_search(attrs, NULL, attr_item_type);
687         attr_types = attr_search(attrs, NULL, attr_attr_types);
688         if(attr_types) {
689                 enum attr_type* at = attr_types->u.attr_types; 
690                 while(*at != attr_none) {
691                         attr_type_list = g_realloc(attr_type_list,sizeof(enum attr_type)*(attr_cnt+1));
692                         attr_type_list[attr_cnt] = *at;
693                         if(*at==attr_position_latitude) {
694                                 bLatFound = 1;
695                         }
696                         else if(*at==attr_position_longitude) {
697                                 bLonFound = 1;
698                         }
699                         ++attr_cnt;
700                         ++at;
701                 }
702                 m->attr_cnt = attr_cnt;
703                 m->attr_types = attr_type_list; 
704         } else {
705                 m->attr_types = NULL;   
706                 return NULL;
707         }
708         
709         charset  = attr_search(attrs, NULL, attr_charset);
710         if(charset) {
711                 dbg(1,"charset:%s\n",charset->u.str);
712                 m->charset=g_strdup(charset->u.str);
713         } else {
714                 m->charset=g_strdup(map_methods_csv.charset);
715         }
716                 
717         if(bLonFound==0 || bLatFound==0) {
718                 return NULL;
719         }
720         
721         item_type_attr=attr_search(attrs, NULL, attr_item_type);
722
723         if( !item_type_attr || item_type_attr->u.item_type==type_none) {
724                 return NULL;
725         }
726
727         m->item_type = item_type_attr->u.item_type;
728
729         data=attr_search(attrs, NULL, attr_data);
730
731         if(data) {
732           struct file_wordexp *wexp;
733           char **wexp_data;
734           FILE *fp;
735           wexp=file_wordexp_new(data->u.str);
736           wexp_data=file_wordexp_get_array(wexp);
737           dbg(1,"map_new_csv %s\n", data->u.str);       
738           m->filename=g_strdup(wexp_data[0]);
739           file_wordexp_destroy(wexp);
740
741           /*load csv file into quadtree structure*/
742           /*if column number is wrong skip*/
743           if((fp=fopen(m->filename,"rt"))) {
744                 const int max_line_len = 256;
745                 char *line=g_alloca(sizeof(char)*max_line_len);
746                 while(!feof(fp)) {
747                         if(fgets(line,max_line_len,fp)) {
748                                 char*line2;
749                                 char* delim = ",";
750                                 int col_cnt=0;
751                                 char*tok;
752         
753                                 if(line[strlen(line)-1]=='\n' || line[strlen(line)-1]=='\r') {
754                                         line[strlen(line)-1] = '\0';
755                                 }
756                                 line2 = g_strdup(line);
757                                 while((tok=strtok( (col_cnt==0)?line:NULL , delim))) {
758                                         ++col_cnt;
759                                 }
760
761                                 if(col_cnt==attr_cnt) {
762                                         int cnt = 0;    /*index of current attr*/
763                                         char*tok;
764                                         GList* attr_list = NULL;
765                                         int bAddSum = 1;        
766                                         double longitude = 0.0, latitude=0.0;
767                                         struct item *curr_item = item_new("",zoom_max);/*does not use parameters*/
768                                         curr_item->type = item_type_attr->u.item_type;
769                                         curr_item->id_lo = m->next_item_idx;
770                                         if (m->flags & 1)
771                                                 curr_item->id_hi=1;
772                                         else
773                                                 curr_item->id_hi=0;
774                                         curr_item->meth=&methods_csv;
775
776                                         
777                                         while((tok=strtok( (cnt==0)?line2:NULL , delim))) {
778                                                 struct attr*curr_attr = g_new0(struct attr,1);
779                                                 int bAdd = 1;   
780                                                 curr_attr->type = attr_types->u.attr_types[cnt];
781                                                 if(ATTR_IS_STRING(attr_types->u.attr_types[cnt])) {
782                                                         curr_attr->u.str = g_strdup(tok);
783                                                 }
784                                                 else if(ATTR_IS_INT(attr_types->u.attr_types[cnt])) {
785                                                         curr_attr->u.num = atoi(tok);
786                                                 }
787                                                 else if(ATTR_IS_DOUBLE(attr_types->u.attr_types[cnt])) {
788                                                         double *d = g_new(double,1);
789                                                         *d = atof(tok);
790                                                         curr_attr->u.numd = d;
791                                                         if(attr_types->u.attr_types[cnt] == attr_position_longitude) {
792                                                                 longitude = *d;
793                                                         }
794                                                         if(attr_types->u.attr_types[cnt] == attr_position_latitude) {
795                                                                 latitude = *d;
796                                                         }
797                                                 }
798                                                 else {
799                                                         /*unknown attribute*/
800                                                         bAddSum = bAdd = 0;
801                                                         g_free(curr_attr);
802                                                 }
803
804                                                 if(bAdd) {
805                                                         attr_list = g_list_prepend(attr_list, curr_attr);
806                                                 }
807                                                 ++cnt;
808                                         }
809                                         if(bAddSum && (longitude!=0.0 || latitude!=0.0)) {
810                                                 struct quadtree_data* qd = g_new0(struct quadtree_data,1);
811                                                 struct quadtree_item* qi =g_new(struct quadtree_item,1);
812                                                 int* pID = g_new(int,1);
813                                                 qd->item = curr_item;
814                                                 qd->attr_list = attr_list;
815                                                 qi->data = qd;
816                                                 qi->longitude = longitude;
817                                                 qi->latitude = latitude;
818                                                 quadtree_add(tree_root, qi, NULL);
819                                                 *pID = m->next_item_idx;
820                                                 g_hash_table_insert(m->qitem_hash, pID,qi);
821                                                 ++m->next_item_idx;
822                                                 dbg(1,"%s\n",line);
823                                         }
824                                         else {
825                                                 g_free(curr_item);
826                                         }
827                                         
828                                 }
829                                 else {
830                                         dbg(0,"ERROR: Non-matching attr count and column count: %d %d  SKIPPING line: %s\n",col_cnt, attr_cnt,line);
831                                 }
832                                 g_free(line2);
833                         }
834                 }
835                 fclose(fp);
836           }
837           else {
838                 dbg(0,"Error opening csv map file %d, starting with empty map\n", m->filename);
839           }
840         } else {
841                 dbg(1,"No data attribute, starting with in-memory map\n");
842         }
843
844         *meth = map_methods_csv;
845
846         meth->charset=m->charset;
847         
848         m->tree_root = tree_root;
849         dbg(2,"%p\n",tree_root);
850         flags=attr_search(attrs, NULL, attr_flags);
851         if (flags) 
852                 m->flags=flags->u.num;
853         return m;
854 }
855
856 void
857 plugin_init(void)
858 {
859         dbg(1,"csv: plugin_init\n");
860         plugin_register_map_type("csv", map_new_csv);
861 }
862