/***************************************************************************
 *            map_osmload.c
 *
 *  2009-08-16
 *  Copyright  2009  Steffen Pohle
 *  steffen@gulpe.de
 ****************************************************************************/

/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/***************************************************
 *
 * read the xml file provided by OpenStreetMap
 *
 */

#define _FILE_OFFSET_BITS 64

#include "osmroute.h"
#include "map.h"
#include "system.h"
#include "memoryleak.h"
#include "vector.h"

#include <locale.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <dirent.h>
#include <ctype.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <libxml/xmlreader.h>
#include <bzlib.h>

struct osm_nodehash {
	unsigned long long int id;  /* node id							*/
	long long int pos;			/* position inside the node file	*/
};


struct osm_waynode {
	unsigned long long int wid;		/* way id								*/
	unsigned short int wsubid;		/* way sub id							*/
	unsigned short int wpnr;		/* point number inside the way node		*/
	long long int next;				/* position of the next way node		*/
};


struct osm_node {
	unsigned long long int id;  		/* node id								*/
	float lon;							/* geo data of the node					*/
	float lat;
	unsigned short int waynodecnt;		/* number of waynodes 					*/
	long long int waynode;				/* position of the first waynode		*/
};


#define OSM_NODEDETAIL_NONE 0
#define OSM_NODEDETAIL_PLACE 1
#define OSM_NODEDETAIL_POI 2
struct osm_nodedetail {
	unsigned long long int id;
	int type;					/* OSM_NODEDETAIL_PLACE, OSM_NODEDETAIL_POI */
	int elements;
	int size;
	int allocsize;
	char *data;
};


struct osm_way {
	unsigned long long int wid;
	int type;
	char name[MAP_W_NAMELEN];
	char ref[MAP_W_NAMELEN];

	int flags;
	int ncnt;
	int nmax;
	unsigned long long int *nid;

	char data[];
};

struct s_osm_hashnodes {
	short int hid;	// number of the hid, -1 == unused

	int hash_cnt;	// current numbers inside
	int hash_fd;	// file descriptor
	int hash_alloc;
	struct osm_nodehash *hash;	// memory to hash
	char fnhash[LEN_FILENAME];

	long long int nodes_end;	// current end position inside the file
	int nodes_fd;				// file descriptor
	char fnnodes[LEN_FILENAME];
};

struct s_osm_xmlcallback {
	FILE *f;
	BZFILE *bzf;
	long long int filesize;
	long long int filepos;
};

#define OSM_HASHNODES 16

static struct s_osm_hashnodes _hashnodes[OSM_HASHNODES];
static struct s_osm_hashnodes *hashnodes[OSM_HASHNODES];

struct s_osmmway {
	int pmax;
	int size;
	struct map_way *mway;
};

struct s_osmmarea {
	int pmax;
	struct map_area *marea;
};

struct s_osmdata {
	struct s_osmmarea area;
	struct s_osmmway way;
	struct osm_way *oway;
} osm;

static struct osm_waynode *osm_wnode = NULL;
static int osm_wnodecnt = 0;
static struct map_waynode *osm_mwnode = NULL;
static int osm_mwnodecnt = 0;


/* for statistic only */
static short int osm_hidmax = -1;		// highest hid number
unsigned long long int osm_cur_wayid;
struct map_pos osm_load_from_web_cur;
struct map_pos osm_load_from_web_start;
struct map_pos osm_load_from_web_end;
unsigned long long int osm_nodes_cnt;
unsigned long long int osm_area_cnt;
unsigned long long int osm_ways_cnt;
float osm_file_pos;

void osm_delete_tmpdir ();
void osm_init ();
void osm_free ();

char *osm_getfname_hid (char *fn, int size, short int hid, char *ext);
char *osm_getfname_id (char *fn, int size, unsigned long long int id, char *ext);

#define osm_hash_getid(__id) ((short int)(__id>>21))
struct s_osm_hashnodes *osm_hashnodes_load (short int hid, int loadhash);
void osm_hashnodes_free (struct s_osm_hashnodes *hnode);

#define osm_node_save(_node) _osm_node_save (_node, 0)
#define osm_node_append(_node) _osm_node_save (_node, 1)
int _osm_node_save (struct osm_node node, int append);
int osm_node_load (struct osm_node *node, unsigned long long int id);
int osm_hash_read (struct s_osm_hashnodes *hnodes, struct osm_nodehash *hash, int pos);
struct s_osm_hashnodes *osm_hash_get (unsigned long long int id, struct osm_nodehash *ret);

int osm_linehashsplit (struct map_pos p1, struct map_pos p2, struct map_pos *np);

struct osm_way *osm_way_alloc (int wmax);
void osm_way_copy (struct osm_way *d, struct osm_way *s);
void osm_way_save (struct osm_way *oway, struct s_osmmway *mway);
void osm_mway_new (int max);				/* realloc temp osm_way struct */

void osm_waynode_add (struct osm_node *node, long long int nodepos, 
                      unsigned long long int id, unsigned short int subid, unsigned short int pnr);
void osm_waynodes_check ();
void osm_waynodes_checknode (struct s_osm_hashnodes *nhash, struct osm_node *node);

void osm_marea_new (struct s_osmmarea *a, int max);
void osm_area_save (struct osm_way *oway, struct s_osmmarea *marea);
int osm_area_split_add (struct s_osmmarea *marea);

void osm_nodedetail_save (struct osm_nodedetail *onoded, struct osm_node *node);

/**************************************************************************
 * create a filename out of the node id..
 */
char *osm_getfname_id (char *fn, int size, unsigned long long int id, char *ext) {
	if (fn == NULL) return NULL;
	if (id == 0) return NULL;
	
	snprintf (fn, size, "%s/nodes-%d%s", cfg.temppath, osm_hash_getid(id), ext);
	return fn;
};


char *osm_getfname_hid (char *fn, int size, short int hid, char *ext) {
	if (fn == NULL) return NULL;
	if (hid == -1) return NULL;
	
	snprintf (fn, size, "%s/nodes-%d%s", cfg.temppath, hid, ext);
	return fn;
};



/**************************************************************************
 * do all preparations for loading a osm file
 */
void osm_delete_tmpdir (char *path) {
	DIR *dir;
	struct dirent *de;
	struct stat fstat;
	char fn[LEN_FILENAME];
	char fndir[LEN_FILENAME];
	static int _osm_recursive = 0;

	if (_osm_recursive > 16) {  // max number of calls..
		d_printf ("%s:%d too many subdirs abort deleting (%s).\n", __FILE__, __LINE__, path);
		return;
	}
	_osm_recursive++;

	/* read the directory */
	dir = opendir(path);
	while (dir != NULL && (de = readdir(dir)) != NULL) {
		snprintf (fndir, LEN_FILENAME, "%s/%s", path, de->d_name);

		/* directory? delete this dir */
		sprintf (fn, "%s/%s", path, de->d_name);
		stat (fn, &fstat);
		if (S_ISDIR (fstat.st_mode) && strcmp (de->d_name, ".") && strcmp (de->d_name, "..")) {
			osm_delete_tmpdir (fndir);
			rmdir (fndir);
		}
		
		/* file? delete file */
		else if (S_ISREG (fstat.st_mode)) {
			unlink (fndir);
		}
	}
	closedir (dir);
	_osm_recursive--;
};


void osm_init () {
	int i;
	
	osm_delete_tmpdir (cfg.temppath);
	
	/* take care of the hash */
	for (i = 0; i < OSM_HASHNODES; i++) {
		_hashnodes[i].hid = -1;
		_hashnodes[i].hash = NULL;		
		_hashnodes[i].hash_alloc = 0;		
		_hashnodes[i].hash_cnt = 0;
		_hashnodes[i].hash_fd = 0;
		_hashnodes[i].nodes_end = 0;
		_hashnodes[i].nodes_fd = 0;
		hashnodes[i] = &_hashnodes[i];
	}

	/* prepare osm_td data */
	if (osm.way.mway) ml_free (osm.way.mway);
	osm.way.mway = NULL;
	osm.way.pmax = 0;
	osm.way.size = 0;

	if (osm.area.marea) ml_free (osm.area.marea);
	osm.area.marea = NULL;
	osm.area.pmax = 0;
	if (osm.oway) ml_free (osm.oway);
	osm.oway = osm_way_alloc (32);

	osm_nodes_cnt = 0;
	osm_area_cnt = 0;
	osm_ways_cnt = 0;
	osm_hidmax = -1;

#ifdef _LINUX_
	mkdir (cfg.temppath, 0755);
#else
	mkdir (cfg.temppath);
#endif
};


void osm_free () {
	int i;

	/* take care of the hash files */
	do {
		for (i = 0; i < OSM_HASHNODES; i++) if (hashnodes[i]->hid != -1) {
			osm_hashnodes_free (hashnodes[i]);
			break;
		}
	}
	while (i < OSM_HASHNODES);

	if (osm.way.mway) ml_free (osm.way.mway);
	osm.way.mway = NULL;
	osm.way.pmax = 0;
	osm.way.size = 0;

	if (osm.area.marea) ml_free (osm.area.marea);
	osm.area.marea = NULL;
	osm.area.pmax = 0;
	
	if (osm.oway) ml_free (osm.oway);
	osm.oway = NULL;

	if (osm_wnode != NULL) ml_free (osm_wnode);
	osm_wnode = NULL;
	osm_wnodecnt = 0;

	if (osm_mwnode != NULL) ml_free (osm_mwnode);
	osm_mwnode = NULL;
	osm_mwnodecnt = 0;

	// osm_delete_tmpdir (TMPDIR);
};



/***********************************************************************
 * nodehash filemanagment
 */

/*
 * load the needed nodes and nodehash file into the memory
 * free unused memory if needed 
 */
struct s_osm_hashnodes *osm_hashnodes_load (short int hid, int loadhash) {
	struct stat fstathash, fstatnodes;
	struct s_osm_hashnodes *hnodes = NULL;
	int i, j, t;

	/* searching for the current hash inside the memory,
	 * when finished: j - first free entry, t - last unused */
	for (j = -1, t = -1, i = 0 ; i < OSM_HASHNODES; i++) {
		if (hashnodes[i]->hid == hid) { 
			/* found hashnodes, select it and put it to the first entry */
			hnodes = hashnodes[i];
			if (i > 0) for(j = i; j > 0; j--) hashnodes[j] = hashnodes[j-1];
			hashnodes[0] = hnodes;
			break;
		}

		else if (j == -1 && hashnodes[i]->hid == -1) j = i;
		else if (hashnodes[i]->hid != -1)
			t = i;
	}

	if (hnodes == NULL) {
		/* give us the first entry */
		if (t+1 == OSM_HASHNODES) osm_hashnodes_free (hashnodes[t]); // delete last one

		hnodes = hashnodes[OSM_HASHNODES-1];
		for(i = OSM_HASHNODES-1; i > 0; i--) hashnodes[i] = hashnodes[i-1];
		hashnodes[0] = hnodes;

		/* create the filenames for the files */
		osm_getfname_hid (hnodes->fnhash, LEN_FILENAME, hid, ".hashnode");
		osm_getfname_hid (hnodes->fnnodes, LEN_FILENAME, hid, ".nodes");
	
		/* check how much memory we will need to laod the data */
		if (stat (hnodes->fnhash, &fstathash) != 0)
			fstathash.st_size = 0;
		if (stat (hnodes->fnnodes, &fstatnodes) != 0)
			fstatnodes.st_size = 0;

		/* load the needed data */
		hnodes->hid = hid;
		hnodes->hash = NULL;
		if ((hnodes->hash_fd = open (hnodes->fnhash, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR)) < 0)
			d_printf ("%s:%d open file '%s' failed. error:%s", __FILE__, __LINE__, hnodes->fnhash, strerror (errno));
		
		hnodes->hash_cnt = fstathash.st_size / sizeof (struct osm_nodehash);
		if ((hnodes->nodes_fd = open (hnodes->fnnodes, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR)) < 0)
			d_printf ("%s:%d open file '%s' failed. error:%s", __FILE__, __LINE__, hnodes->fnnodes, strerror (errno));
		hnodes->nodes_end = fstatnodes.st_size;
	}

	/*
	 * do we need to load the full hash data?
	 */
	if (loadhash && hnodes->hash == NULL) {
		hnodes->hash_alloc = 5000 + hnodes->hash_cnt;
		hnodes->hash = (struct osm_nodehash*) ml_malloc (hnodes->hash_alloc * sizeof (struct osm_nodehash));
		lseek (hnodes->hash_fd, 0, SEEK_SET);
		if (read (hnodes->hash_fd, hnodes->hash, hnodes->hash_cnt * sizeof (struct osm_nodehash)) < sizeof (struct osm_nodehash) * hnodes->hash_cnt) {
			d_printf ("%s:%d could not read data from file:%s", __FILE__, __LINE__, hnodes->fnhash);
			errorexit (-1);
		}
	}

	if (hid > osm_hidmax) osm_hidmax = hid;
	
	return hnodes;
};


/*
 * all data will be saved immediately so we need only to close the file
 */
void osm_hashnodes_free (struct s_osm_hashnodes *hnode) {
	if (hnode->hid == -1) return;

	if ((hnode - _hashnodes) >= OSM_HASHNODES || (hnode - _hashnodes) < 0) {
		d_printf ("%s:%d something went very wrong: %d, max (OSM_HASHNODES): %d\n", __FILE__, __LINE__,
		          (hnode - _hashnodes), OSM_HASHNODES);
		errorexit (-1);
	}

	/* free all data */
	if (hnode->hash && hnode->hash_alloc > 0) {
		lseek (hnode->hash_fd, 0, SEEK_SET);
		if (write (hnode->hash_fd, hnode->hash, 
		           hnode->hash_cnt*sizeof(struct osm_nodehash)) < hnode->hash_cnt*sizeof(struct osm_nodehash)) {
			d_printf ("%s:%d could not save all needed data.", __FILE__, __LINE__);
		}
		ml_free (hnode->hash);
		hnode->hash_alloc = 0;
		hnode->hash = NULL;
	}
	else if (hnode->hash) {
		ml_free (hnode->hash);
		hnode->hash_alloc = 0;
		hnode->hash = NULL;
	}		
	hnode->hash_cnt = 0;
	if (hnode->hash_fd > 0) {
		close (hnode->hash_fd);
		hnode->hash_fd = 0;
	}
	hnode->nodes_end = 0;
	if (hnode->nodes_fd > 0) {
		close (hnode->nodes_fd);
		hnode->nodes_fd = 0;
	}
	hnode->hid = -1;
};


/*
 * read hash node from position
 */
int osm_hash_read (struct s_osm_hashnodes *hnodes, struct osm_nodehash *hash, int pos) {
	if (hnodes->hash_alloc > 0 && hnodes->hash) {
		memcpy (hash, hnodes->hash+pos, sizeof(struct osm_nodehash));
	}
	else {
		lseek (hnodes->hash_fd, pos * sizeof (struct osm_nodehash), SEEK_SET);
		if (read (hnodes->hash_fd, hash, sizeof (struct osm_nodehash)) < sizeof (struct osm_nodehash)) {
			d_printf ("%s:%d could not read data from file:%s pos:%d", __FILE__, __LINE__, hnodes->fnhash, pos);
			return 0;
		}
	}
	return 1;
};


/* 
 * returns the nodehash entry to the givin node
 */
struct s_osm_hashnodes *osm_hash_get (unsigned long long int id, struct osm_nodehash *ret) {
	short int hid = osm_hash_getid (id);
	struct s_osm_hashnodes *hnodes = NULL;
	struct osm_nodehash hash;
	long long int left, pos, lpos1, lpos2;
	int i;
	unsigned long long int lid;

	ret->id = 0;
	ret->pos = 0;

	/* prepare for looking inside the hash */
	hnodes = osm_hashnodes_load (hid, 0);
	left = hnodes->hash_cnt/2;
	pos = left;
	lpos2 = -2;
	lpos1 = -1;

	while (left > 0 && lpos1 != pos && lpos2 != pos && lpos1 != lpos2) {
		lpos1 = lpos2;
		lpos2 = pos;
		if (!osm_hash_read (hnodes, &hash, pos)) {
			d_printf ("%s:%d osm_hash_get id:%lld    hnodes.hid:%d hnodes.cnt:%d hnodes.fnnode:%s", __FILE__, __LINE__, id, hnodes->hid, hnodes->hash_cnt, hnodes->fnnodes);
			return NULL;
		}
		if (hash.id == id) {
			*ret = hash;
			return hnodes;
		}
		else if (hash.id < id) { 
			/* hid is larger than half.hid */
			left = left / 2 + left % 2;
			pos = pos+left;
			if (pos >= hnodes->hash_cnt) pos = hnodes->hash_cnt-1;
		}
		else {
			/* hid is smaler than half.hid */
			left = left / 2 + left % 2;
			pos = pos-left;
			if (pos < 0) pos = 0;
		}
	}

	if (!osm_hash_read (hnodes, &hash, pos)) {
		d_printf ("%s:%d osm_hash_get id:%lld    hnodes.hid:%d hnodes.cnt:%d hnodes.fnnode:%s", __FILE__, __LINE__, id, hnodes->hid, hnodes->hash_cnt, hnodes->fnnodes);
		return NULL;
	}
	if (hash.id == id) {
		*ret = hash;
		return hnodes;
	}
	else for (lpos1 = 0; lpos1 < left+1; lpos1++) {
		if (pos-lpos1 >= 0) {
			if (!osm_hash_read (hnodes, &hash, pos-lpos1)) {
				d_printf ("%s:%d osm_hash_get id:%lld    hnodes.hid:%d hnodes.cnt:%d hnodes.fnnode:%s", __FILE__, __LINE__, id, hnodes->hid, hnodes->hash_cnt, hnodes->fnnodes);
				return NULL;
			}
			if (hash.id == id) {
				*ret = hash;
				return hnodes;
			}
		}
		if (pos+lpos1 < hnodes->hash_cnt) {
			if (!osm_hash_read (hnodes, &hash, pos+lpos1)) {
				d_printf ("%s:%d osm_hash_get id:%lld    hnodes.hid:%d hnodes.cnt:%d hnodes.fnnode:%s", __FILE__, __LINE__, id, hnodes->hid, hnodes->hash_cnt, hnodes->fnnodes);
				return NULL;
			}
			if (hash.id == id) {
				*ret = hash;
				return hnodes;
			}
		}
	}

	d_printf ("node %lld not found over fast way. hid:%d", id, hnodes->hid);
	for (i = 0; i < OSM_HASHNODES; i++) {
		d_printf ("%s hid:%d hash_alloc:%d hash_cnt:%d", __FUNCTION__, hashnodes[i]->hid, hashnodes[i]->hash_alloc, hashnodes[i]->hash_cnt);
	}
	for (lid = 0, left = 0, pos = 1; (left < hnodes->hash_cnt); left++) {
		osm_hash_read (hnodes, &hash, left);
		if (hash.id == id) {
			d_printf ("     node found over slow way: %lld nr:%d", id, left);
			*ret = hash;
			return hnodes;
		}
		if (left>0 && pos) if (hash.id <= lid && hnodes->hash) {
			d_printf ("nodes are not sorted %lld <= %lld. hid:%d", hnodes->hash[left].id, hnodes->hash[left-1].id, hnodes->hid);
			pos = 0;
		}
		lid = hash.id;
	}
	
	return NULL;
};


/*
 * add the new hash entry to the hash table, we will not check for double
 * entrys, this have to be done by the caller.
 */ 
int osm_hash_add (struct s_osm_hashnodes *hnodes, struct osm_nodehash hash) {
	int i;
	struct osm_nodehash thash;

	if (hnodes->hash == NULL || hnodes->hash_alloc == 0)
		hnodes = osm_hashnodes_load (hnodes->hid, 1);
	if (hnodes->hash_alloc <= hnodes->hash_cnt) {
		hnodes->hash_alloc += 5000;
		hnodes->hash = ml_realloc (hnodes->hash, hnodes->hash_alloc * sizeof (struct osm_nodehash));
	}	

	/* check for the right place */
	i = hnodes->hash_cnt;
	if (i > 0) thash = hnodes->hash[i-1];
	while (i > 0 && thash.id > hash.id) {
		hnodes->hash[i] = thash;
		i--;
		if (i > 0) thash = hnodes->hash[i-1];
	}
	hnodes->hash[i] = hash;
	hnodes->hash_cnt++;
	
	return 1;
};


/***********************************************************************
 * loading / saving of a node also adding the new pos to the hash file
 */
int _osm_node_save (struct osm_node node, int append) {
	struct s_osm_hashnodes *hnodes = NULL;
	struct osm_nodehash hash;
	
	/* search if we have to update the node */
	hash.id = -1;
	hash.pos = -1;

	if (!append) /* update --> hash and hnodes == set */
		hnodes = osm_hash_get (node.id, &hash);

	/* append? check if we have enought memory also setup the hash entry */
	if (hnodes == NULL) { /* append */
		hnodes = osm_hashnodes_load (osm_hash_getid (node.id), 1);
		hash.pos = hnodes->nodes_end;
		hash.id = node.id;
		hnodes->nodes_end += sizeof (struct osm_node);
		osm_hash_add (hnodes, hash);
	}

	lseek (hnodes->nodes_fd, hash.pos, SEEK_SET);
	if (write (hnodes->nodes_fd, &node, sizeof (struct osm_node)) < sizeof (struct osm_node)) {
		d_printf ("%s:%d could not write data to file:%s pos:%d", __FILE__, __LINE__, hnodes->fnnodes, hash.pos);
		errorexit (-1);
	}

	return 1;
};


int osm_node_load (struct osm_node *node, unsigned long long int id) {
	struct s_osm_hashnodes *hnodes = NULL;
	struct osm_nodehash hash;

	hnodes = osm_hash_get (id, &hash);
	if (hnodes == NULL) return -1;

	if (lseek (hnodes->nodes_fd, hash.pos, SEEK_SET) < 0)
		d_printf ("%s:%d lseek failed. fd:%d  error:%s", __FILE__, __LINE__, hnodes->nodes_fd, strerror (errno));
	if (read (hnodes->nodes_fd, node, sizeof (struct osm_node)) < sizeof (struct osm_node)) {
		d_printf ("%s:%d could not read data from file:%s pos:%d", __FILE__, __LINE__, hnodes->fnnodes, hash.pos);
		errorexit (-1);
	}
	return hash.pos;
};


/******************************************************************************
 * waynodes handling
 */

/*
 * save the waynode data inside the hash file to read all needed data later on
 * and check the waynodes inside the map files.
 */
void osm_waynode_add (struct osm_node *node, long long int nodepos, unsigned long long int id, 
					  unsigned short int subid, unsigned short int pnr) {
	struct s_osm_hashnodes *hnodes = NULL;
	struct osm_nodehash hash;
	struct osm_waynode wn;
	long long int pos, wpos;

	if (node == NULL) return;
	
	hnodes = osm_hash_get (node->id, &hash);
	if (hnodes == NULL) return;

	pos = hnodes->nodes_end;
	hnodes->nodes_end += sizeof (struct osm_waynode);

	/* save waynode at the end of the file */
	wn.wid = id;
	wn.wsubid = subid;
	wn.wpnr = pnr;
	wn.next = 0;
	// d_printf ("wn id:%lld subid:%d pnr: %hd",wn.wid, wn.wsubid, wn.wpnr);
	lseek (hnodes->nodes_fd, pos, SEEK_SET);
	if (write (hnodes->nodes_fd, &wn, sizeof (struct osm_waynode)) < sizeof (struct osm_waynode)) {
		d_printf ("%s:%d could not write waynode data to file:%s pos:%d", __FILE__, __LINE__, hnodes->fnnodes, pos);
		errorexit (-1);
	}
						  
	if (node->waynode == 0) {
		/* save node with new waypos */
		node->waynode = pos;
	}
	else {
		/* search for the last waynode entry */
		wpos = node->waynode;
		do {
			lseek (hnodes->nodes_fd, wpos, SEEK_SET);
			if (read (hnodes->nodes_fd, &wn, sizeof (struct osm_waynode)) < sizeof (struct osm_waynode)) {
				d_printf ("%s:%d could not read data from file:%s pos:%d", __FILE__, __LINE__, 
						  hnodes->fnnodes, hash.pos);
				errorexit (-1);
			}
			wpos = wn.next;
		}
		while (wn.next != 0);
		
		wn.next = pos;
		pos = 0 - (long long int)sizeof (struct osm_waynode);
		lseek (hnodes->nodes_fd, pos, SEEK_CUR);
		if (write (hnodes->nodes_fd, &wn, sizeof (struct osm_waynode)) < sizeof (struct osm_waynode)) {
			d_printf ("%s:%d could not write data to file:%s pos:%d", __FILE__, __LINE__, 
					  hnodes->fnnodes, hash.pos);
			errorexit (-1);
		}
	}

	/* write node data */
	node->waynodecnt++;
	lseek (hnodes->nodes_fd, nodepos, SEEK_SET);
	if (write (hnodes->nodes_fd, node, sizeof (struct osm_node)) < sizeof (struct osm_node)) {
		d_printf ("%s:%d could not read data from file:%s pos:%d", __FILE__, __LINE__, hnodes->fnnodes, hash.pos);
		errorexit (-1);
	}
	return;
};


void osm_waynodes_check () {
	int hid, i;
	struct s_osm_hashnodes *ohash;
	struct osm_node node;
	char text[256];

	d_printf ("osm_waynodes_check started");
	
	for (hid = 0; hid < osm_hidmax; hid++) {
		sprintf (text, _("checking for waynodes in hid %d"), hid);
		app_status (-1, text, 0.0);
		ohash = osm_hashnodes_load (hid, 1);
		for (i = 0; i < ohash->hash_cnt; i++) {
			if ((i%1024) == 0) main_wnd_loop (i, ohash->hash_cnt);
			/* read node */
			lseek (ohash->nodes_fd, ohash->hash[i].pos, SEEK_SET);
			if (read (ohash->nodes_fd, &node, sizeof (struct osm_node)) < sizeof (struct osm_node)) {
				d_printf ("%s:%d could not read data from file:%s pos:%d", __FILE__, __LINE__, 
						  ohash->fnnodes, ohash->hash[i].pos);
				errorexit (-1);
			}
			osm_waynodes_checknode (ohash, &node);
		}
	}

	d_printf ("osm_waynodes_check finished");
};


void osm_waynodes_checknode (struct s_osm_hashnodes *ohash, struct osm_node *node) {
	struct map_way *way;
	struct map_hash *mh;
	int wncnt, ncur, nto, i, waysize;
	
	/* check and allocate enought memory */
	if (osm_wnodecnt < node->waynodecnt || osm_wnode == NULL) {
		osm_wnodecnt = node->waynodecnt + 4;
		if (osm_wnode) osm_wnode = ml_realloc (osm_wnode, sizeof (struct osm_waynode) * osm_wnodecnt);
		else osm_wnode = ml_malloc (sizeof (struct osm_waynode) * osm_wnodecnt);
	}

	if (node->waynode == 0 && node->waynodecnt == 0) return;
	else if (node->waynode == 0 || node->waynodecnt == 0) {
		d_printf ("%s:%d osm_waynodes_checknode error something isn't right waynode:%lld waynodecnt:%d", __FILE__, __LINE__, node->waynode, node->waynodecnt);
		return;
	}
	if (node->waynodecnt == 1) return;

	/* read all waynodes */
	lseek (ohash->nodes_fd, node->waynode, SEEK_SET);
	wncnt = 0;
	do {
		/* read waynode */
		if (read (ohash->nodes_fd, &osm_wnode[wncnt], sizeof (struct osm_waynode)) < sizeof (struct osm_waynode)) {
			d_printf ("%s:%d could not read data from file:%s pos:%d",
				      __FILE__, __LINE__, ohash->fnnodes, osm_wnode[wncnt].next);
			errorexit (-1);
		}
		lseek (ohash->nodes_fd, osm_wnode[wncnt].next, SEEK_SET);
		wncnt++;
	} while (osm_wnode[wncnt-1].next != 0 && wncnt < node->waynodecnt);

	/* 
	 * walk trough all waynodes 
	 */
	for (ncur = 0; ncur < wncnt; ncur++) {
		/*
		 * prepare current way
		 */
		if ((mh = map_hash_get (node->lon, node->lat, MHLOAD_RELOAD)) == NULL) continue;
		if ((way = map_way_find (mh, osm_wnode[ncur].wid, osm_wnode[ncur].wsubid)) == NULL) continue;
		waysize = map_way_getsize (way) + POINTERALIGNMENT;

		/* check for enought memory */
		if (osm_mwnodecnt < way->n_cnt+wncnt) {
			osm_mwnodecnt = way->n_cnt+wncnt + 4;
			if (osm_mwnode) osm_mwnode = ml_realloc (osm_mwnode, sizeof (struct map_waynode) * osm_mwnodecnt);
			else osm_mwnode = ml_malloc (sizeof (struct map_waynode) * osm_mwnodecnt);
		}
		if (osm.way.size < waysize) {
			osm.way.size = waysize + 256;
			if (osm.way.mway) osm.way.mway = ml_realloc (osm.way.mway, osm.way.size);
			else osm.way.mway = ml_malloc (osm.way.size);
		}

		/* copy way to osm_mway and reset pointer to the nodes*/
		map_way_copy (osm.way.mway, way);
		osm.way.mway->next = NULL;
		osm.way.mway->n = osm_mwnode;
		osm.way.mway->n_cnt = way->n_cnt;
		
		/* copy nodes */
		for (i = 0; i < way->n_cnt; i++)
			osm.way.mway->n[i] = way->n[i];

		/* 
		 * now update or add the new nodes 
		 */
		for (nto = 0; nto < wncnt; nto++) {
			if (nto == ncur) continue; /* from and to identical. */
			for (i = 0; i < osm.way.mway->n_cnt; i++) {
				/* check if we know this node already */
				if (osm.way.mway->n[i].d_id == osm_wnode[nto].wid &&
				    osm.way.mway->n[i].d_subid == osm_wnode[nto].wsubid && 
				    osm.way.mway->n[i].d_pnr == osm_wnode[nto].wpnr) break;
			}
			
			if (i == osm.way.mway->n_cnt && i < osm_mwnodecnt) { 
				/* unknown waynode add */
				osm.way.mway->n[i].d_pnr = osm_wnode[nto].wpnr;
				osm.way.mway->n[i].d_id = osm_wnode[nto].wid;
				osm.way.mway->n[i].d_subid = osm_wnode[nto].wsubid;
				osm.way.mway->n[i].d.lon = node->lon;
				osm.way.mway->n[i].d.lat = node->lat;
				osm.way.mway->n[i].pnr = osm_wnode[ncur].wpnr;
				osm.way.mway->n[i].flags = 0;
				osm.way.mway->n_cnt++;
			}
			else if (i == osm.way.mway->n_cnt && i >= osm_mwnodecnt) {
				d_printf ("%s:%d osm_waynodes_checknode: something went very wrong. (i == osm_mway->n_cnt && i >= osm_mwnodecnt)", __FILE__, __LINE__);
				errorexit (1);
			}
		}

		/* replace current node */
		if (way->n_cnt != osm.way.mway->n_cnt) {
			map_way_add (osm.way.mway, MHLOAD_RELOAD);
		}
	}
};


/****************************************************************************
 * split the line into peaces, is the line intersects with more then one
 * hash segment the function will return 2 as indicator of another 
 * intersection.
 */
int osm_linehashsplit (struct map_pos p1, struct map_pos p2, struct map_pos *np) {
	return 0; // for now just return 0 and get the other stuff running first.
};


/***************************************************************************
 * osm_way handling .. allocating memory and converting it into map_way
 */
struct osm_way *osm_way_alloc (int wmax) {
	struct osm_way *w = NULL;

	w = (struct osm_way*) ml_malloc (sizeof (struct osm_way) + wmax * sizeof (unsigned long long int));
	w->nmax = wmax;
	w->ncnt = 0;
	w->nid = (unsigned long long int*) &w->data[0];
	w->name[0] = 0;
	w->ref[0] = 0;
	w->type = MWAY_unknown;	
	w->flags = 0;
	
	return w;
};


void osm_way_copy (struct osm_way *d, struct osm_way *s) {
	int i;
	
	if (d == NULL || s == NULL) {
		d_printf ("%s:%d  d or s is NULL \n", __FILE__, __LINE__);
		errorexit (-1);
	}
	
	d->wid = s->wid;
	d->type = s->type;
	strncpy (d->name, s->name, MAP_W_NAMELEN);
	strncpy (d->ref, s->ref, MAP_W_NAMELEN);
	for (i = 0; i < s->ncnt; i++)
		if (i < d->nmax) d->nid[i] = s->nid[i];
	d->ncnt = s->ncnt;
	d->flags = s->flags;
};


void osm_mway_pmax_new (struct s_osmmway *w, int max) {
	int newsize = sizeof (struct map_way) + 2 * sizeof (struct map_waynode) + max * sizeof (struct map_pos);
	if (w->mway == NULL || newsize > w->size) {
		w->mway = ml_realloc (w->mway, newsize);
		w->size = newsize;
	}

	w->pmax = max;
	w->mway->name[0] = 0;
	w->mway->ref[0] = 0;
	w->mway->n_cnt = 0;
	w->mway->p_cnt = 0;
	w->mway->n = (struct map_waynode*) &w->mway->data[0];
	w->mway->p = (struct map_pos*) &w->mway->data[2 * sizeof (struct map_waynode)];
	w->mway->id = 0;
	w->mway->subid = 0;
	w->mway->next = 0;
	w->mway->flags = 0;
};


/********************************************************************
 * convert the osm way into the map_way type and save it into the 
 * hash data block. I case the way goes over more hash segments the
 * way will be slit into peaces */
void osm_way_save (struct osm_way *oway, struct s_osmmway *way) {
	int p;
	long long int nodepos;
	unsigned long long int id;
	struct osm_node node;
	struct map_pos curpos, lastpos;

	osm_mway_pmax_new (way, oway->ncnt);

	way->mway->id = oway->wid;
	way->mway->type = oway->type;
	way->mway->flags = oway->flags;
	strncpy (way->mway->name, oway->name, MAP_W_NAMELEN);
	strncpy (way->mway->ref, oway->ref, MAP_W_NAMELEN);

	for (p = 0; p < oway->ncnt; p++) {
		/* find the node */
		id = oway->nid[p];
		if ((nodepos = osm_node_load (&node, id)) == -1) return;
		
		/* check if we are still in the same AREA.. */
		curpos.lon = node.lon;
		curpos.lat = node.lat;
		
		if (p > 0 && 
			(map_geo2igeo (lastpos.lon) != map_geo2igeo (curpos.lon) || map_geo2igeo (lastpos.lat) != map_geo2igeo (curpos.lat))) {  
				/* 
				 * save the known part of the way.. 
				 * and create a new part of the way
				 */
				way->mway->n[way->mway->n_cnt].d_id = way->mway->id;
				way->mway->n[way->mway->n_cnt].d_subid = way->mway->subid+1;
				way->mway->n[way->mway->n_cnt].d_pnr = 0;
				way->mway->n[way->mway->n_cnt].pnr = way->mway->p_cnt-1;
				way->mway->n[way->mway->n_cnt].d = curpos;
				way->mway->n[way->mway->n_cnt].flags = 0;
				way->mway->n_cnt++;

				map_way_add (way->mway, MHLOAD_RELOAD);

				/* prepare a new way with subid + 1 */
				way->mway->n_cnt = 1;
				way->mway->n[0].d_subid = way->mway->subid;
				way->mway->n[0].d_id = way->mway->id;
				way->mway->n[0].d = lastpos;
				way->mway->n[0].d_pnr = way->mway->p_cnt-1;
				way->mway->n[0].pnr = 0;
				way->mway->n[0].flags = 0;
				way->mway->p_cnt = 0;
				way->mway->subid++;
			 }
		
		/*
		 * add the new node to the way.. also add the way to the nodehash..
		 */
		way->mway->p[way->mway->p_cnt].lon = node.lon;
		way->mway->p[way->mway->p_cnt].lat = node.lat;
		if (way->mway->type < MWAY_MAX)
			osm_waynode_add (&node, nodepos, way->mway->id, way->mway->subid, way->mway->p_cnt);
		else {
			d_printf ("%s:%d osm_way_save: osm_mway->type >= MWAY_MAX which should not happen, since it should call osm_area_save", __FILE__, __LINE__);
			exit (1);
		}
		way->mway->p_cnt++;
	
		/* save last position */
		lastpos = curpos;
		osm_cur_wayid = oway->wid;
		main_wnd_loop(p, -2);
	}

	map_way_add (way->mway, MHLOAD_RELOAD);
	return;
};


/******************************************************************************
 * all code to save an area
 */
void osm_marea_new (struct s_osmmarea *a, int max) {
	if (a->marea == NULL || max > a->pmax) {
		a->marea = ml_realloc (a->marea, sizeof (struct map_area) + max * sizeof (struct map_pos));
		a->pmax = max;
	}

	a->marea->id = 0;
	a->marea->subid = 0;
	a->marea->type = MAREA_unknown;
	a->marea->p = (struct map_pos*) a->marea->data;
	a->marea->p_cnt = 0;
};


/********************************************************************
 * convert the osm "way" into the map_area type and save it into the 
 * hash data block. I case the way goes over more hash segments the
 * way will be slit into peaces 
 *
 * splitting into peaces does not work yet, also taking care of the
 * polygons, no angles over 180°.
 * 
 * CALL with NULL will free all unneeded memory
 */
void osm_area_save (struct osm_way *oway, struct s_osmmarea *area ) {
	int ndfirst, nd;						// first node, current node
	int outfirstnd;							// first outside node, current outside node
	static char *nodestat = NULL;			// array to save all some node data
	static int nodestat_alloc = 0;			// size of the struct
	struct map_pos pos, p1;					// current hash, pos
	struct osm_node curnode, node;			// current node, node
	int sid = 0;

	/* check if we just need to free all data */
	if (oway == NULL) {
		if (nodestat != NULL) free (nodestat);
		nodestat = NULL;
		nodestat_alloc = 0;
		return;
	}

	/* basic check and allocate enought memory (if needed) */
	if (oway->type == MAREA_ignore) return;

	else if (oway->type == MAREA_campsite) {
		struct map_poi poi;

		poi.lon = 0.0;
		poi.lat = 0.0;
		poi.name = oway->name;
		poi.additional = NULL;
		poi.type = MAP_POI_campsite;
		poi.next = NULL;
		poi.id = 1;
		for (nd = 0; nd < oway->ncnt; nd++) {
			if (osm_node_load (&node, oway->nid[nd]) == -1) {
				d_printf ("%s:%d osm_area_save count not find node number: %lld", __FILE__, __LINE__, oway->nid[nd]);
				return;
			}
			poi.lon += node.lon;
			poi.lat += node.lat;
		}
		poi.lon = poi.lon / (float) nd;
		poi.lat = poi.lat / (float) nd;

		map_poi_add (&poi, MHLOAD_RELOAD);

		return;
	}
	if (oway->ncnt < 2) {
		return;	// a polygon needs at last 3 nodes
	}

	osm_marea_new (area, oway->ncnt);

	/* allocate data for nodestat, and reset data */
	if (nodestat_alloc < oway->ncnt) {
		nodestat = ml_malloc (oway->ncnt);
		nodestat_alloc = oway->ncnt;
	}
	memset (nodestat, 0x0, nodestat_alloc);

	/* 
	 * find the first complete hash segment and it's end
	 */
	do {
		/* find first unused node, also the center of the area */
		for (ndfirst = 0; ndfirst < oway->ncnt && nodestat[ndfirst] != 0; ndfirst++);

		/* 
		 * found an unused node so save this segment 
		 */
		if (ndfirst < oway->ncnt) {
			if (osm_node_load (&curnode, oway->nid[ndfirst]) == -1) {
				d_printf ("%s:%d osm_area_save count not find node number: %lld", __FILE__, __LINE__, oway->nid[ndfirst]);
				return;
			}
			nodestat[ndfirst] = 1;

			/* save first node */
			area->marea->id = oway->wid;
			area->marea->subid = sid;
			area->marea->type = oway->type;
			area->marea->p_cnt = 1;
			area->marea->p = (struct map_pos *) area->marea->data;
			area->marea->p[0].lon = curnode.lon;
			area->marea->p[0].lat = curnode.lat;

			/* find all nodes which are inside this segment
			 * do preparations after this save the area */
			nd = ndfirst;
			outfirstnd = -1;
			pos.lon = curnode.lon;
			pos.lat = curnode.lat;
			if (++nd >= oway->ncnt) nd = 0;	/* count +1, check for overrun */
			while (nd != ndfirst) {
				if (osm_node_load (&node, oway->nid[nd]) == -1) {
					d_printf ("%s:%d osm_area_save count not find node number: %lld", 
							  __FILE__, __LINE__, oway->nid[nd]);
					return;
				}
				pos.lon = node.lon;
				pos.lat = node.lat;

				if (outfirstnd >= 0) {
					/* we are still outside, find the next inside pos */
					d_printf ("%s:%d FIX ME", __FILE__, __LINE__);
					exit (-1);
				}

				else {
					/* we are inside the current node
					 * check and split in two if needed */
					if (osm_linehashsplit (area->marea->p[area->marea->p_cnt-1], pos, &p1) > 0) {
						/* node is outside the area, the border is saved at p1 */
						area->marea->p_cnt++;
						outfirstnd = nd;
					}
					else {
						/* node is inside the area */
						area->marea->p[area->marea->p_cnt].lon = node.lon;
						area->marea->p[area->marea->p_cnt].lat = node.lat;
						area->marea->p_cnt++;
						nodestat[nd] = 1;
					}
				}
				if (++nd >= oway->ncnt) nd = 0;	/* count +1, check for overrun */
			}
			osm_area_split_add (area);
		}
	} while (ndfirst < oway->ncnt);
	
	return;
};


/*
 * convert area into a polygon without angles above 180°
 * it saves time late in drawing on slow devices.
 * only needed because of GL_TRIANGLE_STRIP and return
 * last subid saved.
 */
struct s_osmareapnt {
	int pnr;
	fPoint km;
	float angle;
	float sel_dist;
	float sel_angle;
};


#define MAX_SUBID 250
int osm_area_split_add (struct s_osmmarea *marea) {
	/* allocate enought memory */
	struct map_area *a = NULL;
	struct s_osmareapnt *pt = ml_malloc (sizeof (struct s_osmareapnt) * marea->marea->p_cnt);
	int i, st, pt_c, c;
	int _debug = 0, rotated = 0;
	float angle_sum;

//	if (marea->marea->id == 22963835) _debug = 1;
//	else return 1;
//	d_printf ("marea: %lld   cnt:%d", marea->marea->id, marea->marea->p_cnt);
//	map_area_add (marea->marea, MHLOAD_RELOAD);
//	return 1;

	if (_debug) d_printf ("area:%lld:%d", marea->marea->id, marea->marea->subid);
	a = ml_malloc (map_area_getsize (marea->marea));
	map_area_copy (a, marea->marea);

	/* calculate all klon, klat and prepare start struct, also
	 * ignore double entrys */
	for (pt_c = 0, i = 0; i < marea->marea->p_cnt; i++) {
		if (i == 0) st = marea->marea->p_cnt-1;
		else st = i-1;

		if (marea->marea->p[i].lon == marea->marea->p[st].lon
			&& marea->marea->p[i].lat == marea->marea->p[st].lat) continue;

		pt[pt_c].pnr = i;
		pt[pt_c].angle = -1.0;
		pt[pt_c].km.x = map_lon2km (marea->marea->p[i].lon, marea->marea->p[i].lat);
		pt[pt_c].km.y = map_lat2km (marea->marea->p[i].lat);
		if (_debug) d_printf ("pt[%-3d].pnr:%d  km.x:%f   km.y:%f", pt_c, pt[pt_c].pnr, pt[pt_c].km.x, pt[pt_c].km.y);
		pt_c++;
	}

	while (pt[0].pnr >= 0 && pt_c > 2 && a->subid < MAX_SUBID) {
		/* st - will keep first pt to start checking polygon
		 * c  - count how many angles are above 180° */
		if (_debug) d_printf ("**************** subid:%d    pt_c:%d", a->subid, pt_c);
		for (angle_sum = 0.0, st = -1, c = 0, i = 0; i < pt_c; i++) {
			if (i == pt_c-1) 	pt[i].angle = point_angle (pt[i-1].km, pt[i].km, pt[0].km);
			else if (i == 0)	pt[i].angle = point_angle (pt[pt_c-1].km, pt[i].km, pt[i+1].km);
			else				pt[i].angle = point_angle (pt[i-1].km, pt[i].km, pt[i+1].km);
			if (pt[i].angle > M_PI) {	/* only select first pt */
				if (st == -1)	st = i;
				else if (pt[st].angle < pt[i].angle) st = i;
				c++;
			}
			angle_sum += pt[i].angle;
			if (_debug) d_printf ("i:%-2d   pnr:%-2d  angle:%f",i, pt[i].pnr, pt[i].angle);
		}
		angle_sum /= (float)pt_c;
		if (_debug) d_printf ("c:%d  pt_c:%d   st:%d angle_sum:%f",c, pt_c, st, angle_sum);

		/* make sure we going counterclock direction, only first area */
		if (rotated == 0 && angle_sum > M_PI && a->subid == marea->marea->subid) {
			struct s_osmareapnt *pt_ = ml_malloc (sizeof (struct s_osmareapnt) * pt_c);

			if (_debug) d_printf ("change rotation ...");
			for (i = 0; i < pt_c; i++) pt_[pt_c - i - 1] = pt[i];
			ml_free (pt);
			pt = pt_;
			rotated = 1;
			continue;
		}

		/* if c==0 save last areapart */
		else if (c == 0) {
			a->p_cnt = 0;
			for (i = 0; i < pt_c; i++) {
				if (_debug) d_printf ("0: added %d pnr:%d", a->p_cnt, pt[i].pnr);
				a->p[a->p_cnt++] = marea->marea->p[pt[i].pnr];
				pt[i].pnr = -1;
			}
			map_area_add (a, MHLOAD_RELOAD);
			a->subid++;
		}

		/* if c==1 select j as 0 then quit, if GL_TRIANGLE_STRIP gets kicked out of
		 * openGL we need to change this */
		else if (c == 1) {
			for (a->p_cnt = 0, i = st; a->p_cnt < pt_c;) {
				if (_debug) d_printf ("1: added %d pnr:%d", a->p_cnt, pt[i].pnr);
				a->p[a->p_cnt++] = marea->marea->p[pt[i].pnr];
				pt[i].pnr = -1;

				if (i < pt_c-1) i++;
				else i = 0;
			}
			map_area_add (a, MHLOAD_RELOAD);
			a->subid++;
		}

		/* check again for the part to split the area. */
		else {
			int j, sel, s, i_old, c;
			float dist;
			float angle;

			/* check if selected start is working for us */
			sel = st;
			i_old = -1;
			do {
				/* fill up all sel_angles and sel_dists */
				if (sel < pt_c-1) s = sel + 1;
				else s = 0;
				if (_debug) d_printf ("select %d [pnr:%d] second:%d", sel, pt[sel].pnr, s);
				for (i = 0; i < pt_c; i++) {
					if (i != sel) {
						pt[i].sel_angle = point_angle (pt[i].km, pt[sel].km, pt[s].km);
						pt[i].sel_dist = vec_len (vec_sub (pt[i].km, pt[sel].km));
					}
					else {
						pt[i].sel_angle = -2.0;
						pt[i].sel_dist = -2.0;
					}
					if (_debug) d_printf ("       %-2d pnr:%-2d angle:%f dist:%f", i, pt[i].pnr, pt[i].sel_angle, pt[i].sel_dist);
				}

				a->p_cnt = 0;
				a->p[a->p_cnt++] = marea->marea->p[pt[sel].pnr];
				angle = 0.0;
				if (_debug) d_printf ("  check for possible loop: i:%d  s:%d  st:%d  sel:%d  angle:%f  pt[i].sel_angle:%f", i, s, st, sel, angle, pt[i].sel_angle);
				for (i_old = -1, i = s, angle = 0.0; i != sel && angle <= pt[i].sel_angle;) {
					if (_debug) d_printf ("  i:%d  sel:%d  angle:%f  pt[i].sel_angle:%f", i, st, angle, pt[i].sel_angle);
					for (j = i; j != sel;) {
						if (_debug) d_printf ("           j:%d (pnr:%d, angle:%f, dist:%f)    i:%d (pnr:%d, angle:%f, dist:%f) ", j, pt[j].pnr, pt[j].sel_angle, pt[j].sel_dist, i, pt[i].pnr, pt[i].sel_angle, pt[i].sel_dist);
						if (pt[i].sel_angle > pt[j].sel_angle && pt[i].sel_dist > pt[j].sel_dist) {
							if (_debug) d_printf ("       break 1");
							break;
						}
						j++; if (j >= pt_c) j = 0;
					}
					if (j != sel) {
						/* something is in the way */
						if (_debug) d_printf ("       break 2");
						break;
					}
					else {
						/* found something */
						if (i_old >= 0) pt[i_old].pnr = -1; /* already second pass */
						a->p[a->p_cnt++] = marea->marea->p[pt[i].pnr];
						if (_debug) d_printf ("add nr:%d  pnr:%d", a->p_cnt-1, pt[i].pnr);
						angle = pt[i].sel_angle;
					}

					i_old = i;
					i++; if (i >= pt_c) i = 0;
				}

				if (a->p_cnt < 3) {
					/* found nothing try next one */
					sel++; if (sel >= pt_c) sel = 0;
				}

			} while (sel != st && a->p_cnt < 3);

			/* add element */
			if (a->p_cnt >= 3) {
				map_area_add (a, MHLOAD_RELOAD);
				a->subid++;
			}
		}

		/* recreate pall list, delete unneeded elements (pnr == -1) */
		for (c = 0, i = 0; i < pt_c; i++)	if (pt[i].pnr != -1) pt[c++] = pt[i];
		if (pt_c == c) {
			d_printf ("%s:%d pt_c == c : nothing deleted.. something went wrong.", __FILE__, __LINE__);
			d_printf ("  rotated:%d", rotated);
			break;
		}
		pt_c = c;
	}

	if (a->subid >= MAX_SUBID) {
		d_printf ("%s:%d max subid reached. area id:%lld", __FILE__, __LINE__, a->id);
	}

	if (pt[0].pnr >= 0 && pt_c > 2) {
		d_printf ("%s:%d osm_area_split_add: something went very wrong", __FILE__, __LINE__);
		d_printf ("      marea->id: %lld:%d", a->id, a->subid);
		d_printf ("      pt[0].pnr:%d    pt[1].pnr:%d    pall_cnt: %d", pt[0].pnr, pt[1].pnr, pt_c);
	}

	/* free unneeded memory and return to caller */
	ml_free (a);
	ml_free (pt);

	return a->subid;
};



/********************************************************************
 * save detail information of the node. This will also create the 
 * search index.
 */
void osm_nodedetail_save (struct osm_nodedetail *onoded, struct osm_node *node) {
	int i, j;
	char *data;
	char *var;
	char *val;

	data = onoded->data;
	if (onoded->type == OSM_NODEDETAIL_PLACE) {
		struct map_place place;

		place.lon = node->lon;
		place.lat = node->lat;
		place.id = node->id;
		place.name = NULL;
		place.country = NULL;
		place.state = NULL;
		place.district = NULL;
		place.postalcode = NULL;
		place.next = NULL;
		place.population = 0;
		place.type = MAP_PLACE_unknown;

		for (i = 0; i < onoded->elements; i++) {
			var = data;
			val = var + strlen (var) + 1;
			data = val + strlen (val) + 1;

			// d_printf ("variable:%s   value:%s", var, val);
			if (strcmp (var, "name") == 0) {
				place.name = val;
			}
			else if (strcmp (var, "place") == 0) {
				for (j = 0; val[j] != 0; j++)
					val[j] = tolower (val[j]);
				if (strcmp (val, "city") == 0) {
					place.type = MAP_PLACE_city;
				}
				else if (strcmp (val, "suburb") == 0) {
					place.type = MAP_PLACE_suburb;
				}
				else if (strcmp (val, "village") == 0) {
					place.type = MAP_PLACE_village;
				}
				else if (strcmp (val, "hamlet") == 0) {
					place.type = MAP_PLACE_hamlet;
				}
				else if (strcmp (val, "town") == 0) {
					place.type = MAP_PLACE_town;
				}
				else {
//					d_printf ("unknown place:'%s' for '%s'", val, place.name);
					place.type = MAP_PLACE_unknown;
				}
			}
		}

//		d_printf ("NAME: id:%lld name:'%s' type:%d", place.id, place.name, place.type); 

		if (place.type != MAP_PLACE_unknown) {
			map_place_add (&place, MHLOAD_RELOAD);
			map_search_add (place.country, place.name, place.id, place.lon, place.lat);
		}
	}

	else if (onoded->type == OSM_NODEDETAIL_POI) {
		struct map_poi poi;

		poi.lon = node->lon;
		poi.lat = node->lat;
		poi.id = node->id;
		poi.name = NULL;
		poi.additional = NULL;
		poi.type = MAP_POI_unknown;
		
		for (i = 0; i < onoded->elements; i++) {
			var = data;
			val = var + strlen (var) + 1;
			data = val + strlen (val) + 1;

			if (strcmp (var, "name") == 0) {
				poi.name = val;
			}
			else if (strcmp (var, "highway") == 0) {
				for (j = 0; val[j] != 0; j++)
					val[j] = tolower (val[j]);
				if (strcmp (val, "bus_stop") == 0) {
					poi.type = MAP_POI_busstop;
				}
			}
			else if (strcmp (var, "amenity") == 0) {
				for (j = 0; val[j] != 0; j++)
					val[j] = tolower (val[j]);
				if (strcmp (val, "restaurant") == 0) {
					poi.type = MAP_POI_restaurant;
				}
				else if (strcmp (val, "fuel") == 0) {
					poi.type = MAP_POI_gasstation;
				}					
			}
			else if (strcmp (var, "tourism") == 0) {
				for (j = 0; val[j] != 0; j++)
					val[j] = tolower (val[j]);
				if (strcmp (val, "hotel") == 0) {
					poi.type = MAP_POI_hotel;
				}
			}
		}

		if (poi.type != MAP_POI_unknown && poi.name != NULL)
			if (strlen (poi.name) > 0) map_poi_add (&poi, MHLOAD_RELOAD);
	}
};


/*
 * append to the onoded another data, this will also check the size of the allocated data
 */
void osm_nodedetail_append (struct osm_nodedetail *onoded, char *variable, char *value) {
	char *data, *var, *val;
	int i,j;

	/* allocated memory for the data is too small */
	if (onoded->allocsize == 0 || onoded->data == NULL) {
		onoded->allocsize = strlen (variable) + strlen (value) + 2 + 4096;
		onoded->size = 0;
		onoded->data = ml_malloc (onoded->allocsize);
	}
	else if ((strlen (variable) + strlen (value) + 2 + onoded->size) >= onoded->allocsize) {
		char *olddata;
		int oldsize;

		olddata = onoded->data;
		oldsize = onoded->allocsize;
		onoded->allocsize += (strlen (variable) + strlen (value) + 2 + 4096);
		onoded->data = ml_malloc (onoded->allocsize);
		memcpy (onoded->data, olddata, oldsize);
		ml_free (olddata);
	}

	/* go to the last element and save data */
	data = onoded->data + onoded->size;
	var = data;
	for (i = 0; i < strlen (variable); i++)
		data[i] = tolower (variable[i]);
	data[i] = '\0';
	data = data + i + 1;
	val = data;
	for (j = 0; j < strlen (value); j++)
		data[j] = value[j];
	data[j] = '\0';
	onoded->size = onoded->size + j + i + 2;

	if (strncmp (var, "place", 6) == 0) {
		onoded->type = OSM_NODEDETAIL_PLACE;
	}
	if (strncmp (var, "highway", 8) == 0 && strncmp (val, "bus_stop", 9) == 0) {
		onoded->type = OSM_NODEDETAIL_POI;
	}
	if (strncmp (var, "amenity", 8) == 0) {
		onoded->type = OSM_NODEDETAIL_POI;
	}
	if (strncmp (var, "tourism", 8) == 0) {
		onoded->type = OSM_NODEDETAIL_POI;
	}
	
	onoded->elements++;
};


/***************************************************************************
 * read a osmxml file, 
 */
#define XML_TEXTLEN 256
void osm_processdata (xmlTextReaderPtr reader) {
    const xmlChar *name, *attr, *k, *v;
	static int xmlolddepth = -1;
	int xmldepth;

	char *cid;
	unsigned long long int id;
	static struct osm_node onode;
	static struct osm_nodedetail onoded;
	struct osm_way *tmpoway = NULL;
	static void *last = NULL;

	if (xmlolddepth == -1) {
		onode.id = 0;
		onoded.data = NULL;
		onoded.allocsize = 0;
		onoded.size = 0;
		onoded.elements = 0;
		onoded.type = OSM_NODEDETAIL_NONE;
		if (osm.oway != NULL) {
			osm.oway->type = MWAY_unknown;
			osm.oway->wid = 0;
			osm.oway->ncnt = 0;
		}
		else {
			osm.oway = osm_way_alloc (32);
		}
		last = NULL;
	}
	
    name = xmlTextReaderConstName(reader);
    if (name == NULL)
		name = BAD_CAST "--";
	
	/* check if we need to save the data.. */
	cid = (char*) xmlTextReaderGetAttribute (reader, (xmlChar*)"id");
	if (cid) {
		id = atoll (cid);
		free (cid);
	}
	else id = 0;
	xmldepth = xmlTextReaderDepth (reader);

	if (xmldepth == 1 && (strncmp ((char*) name, "#text", 6) == 0)) {
		/*
		 * save data
		 */
		if (last == (void*) osm.oway) {
			if (osm.oway->type >= MWAY_MAX) {
				osm.oway->type -= MWAY_MAX;
				osm_area_cnt++;

				if (osm.oway->type != MAREA_ignore) osm_area_save (osm.oway, &osm.area);
			}
			else {
				osm_ways_cnt++;
				osm_way_save (osm.oway, &osm.way);
			}
		}
		else if (last == (void*) &onode) {
			/* add the current node */
			osm_nodes_cnt++;
			osm_node_append (onode);
			if (onoded.type != OSM_NODEDETAIL_NONE)
				osm_nodedetail_save (&onoded, &onode);
		}
		onode.id = 0;
		onode.waynode = 0;
		onoded.type = OSM_NODEDETAIL_NONE;
		onoded.size = 0;
		onoded.elements = 0;
		osm.oway->wid = 0;
		osm.oway->type = MWAY_MAX + MAREA_ignore;
		osm.oway->ncnt = 0;
		osm.oway->name[0] = 0;
		osm.oway->ref[0] = 0;
		osm.oway->flags = 0;

		last = NULL;
	}

	/*
	 * check and process date for a node
	 */
	if (strncmp ((char*) name, (char*) "node",5) == 0) { // it's a node
		if (id == 0) return;
		onode.id = id;
	
		// d_printf ("xml.. node: %lld\n", onode.id);
		attr = xmlTextReaderGetAttribute (reader, (xmlChar*)"lat");	// lat
		if (attr == NULL) return;
		sscanf ((char*)attr , "%g", &onode.lat);
		free ((void *)attr);
	
		attr = xmlTextReaderGetAttribute (reader, (xmlChar*)"lon");	// lon
		if (attr == NULL) return;
		sscanf ((char*)attr, "%g", &onode.lon);
		free ((void *)attr);
		
		xmlolddepth = xmldepth;
		last = (void*)&onode;
	}

	else if ((strncmp ((char*) name, (char*) "tag", 3) == 0) && last == (void*)&onode) { // tag to a node?
		k = xmlTextReaderGetAttribute (reader, (xmlChar*)"k");
		if (k == NULL) return;
		v = xmlTextReaderGetAttribute (reader, (xmlChar*)"v");
		if (v == NULL) {
			free ((void *)k);
			return;
		}

		onoded.id = onode.id;
		osm_nodedetail_append (&onoded, (char*)k, (char*)v);
		free ((void *)k);
		free ((void *)v);
	}

	/*
	 * check and process data for way or an area
	 */
	else if (strncmp ((char*) name, (char*) "way",4) == 0) { // it's a way
		if (id == 0) return;
		osm.oway->wid = id;
		
		xmlolddepth = xmldepth;
		last = (void*)osm.oway;
	}
	
	else if ((strncmp ((char*) name, (char*) "tag", 3) == 0) && last == (void*)osm.oway) { // tag to a way?
		k = xmlTextReaderGetAttribute (reader, (xmlChar*)"k");
		if (k == NULL) return;
		v = xmlTextReaderGetAttribute (reader, (xmlChar*)"v");
		if (v == NULL) {
			free ((void *)k);
			return;
		}
	
		if (strncmp ((char*) k, (char*) "highway", 8) == 0) {
			if (strcmp ((char*) v, (char*) "primary") == 0) osm.oway->type = MWAY_tertiary;
			else if (strcmp ((char*) v, (char*) "primary_link") == 0) {
				osm.oway->type = MWAY_tertiary;
				osm.oway->flags |= MWAY_F_junction;
			}
			else if (strcmp ((char*) v, (char*) "tertiary") == 0) osm.oway->type = MWAY_tertiary;
			else if (strcmp ((char*) v, (char*) "secondary") == 0) osm.oway->type = MWAY_tertiary;
			else if (strcmp ((char*) v, (char*) "motorway") == 0) osm.oway->type = MWAY_highway;
			else if (strcmp ((char*) v, (char*) "motorway_link") == 0) {
				osm.oway->type = MWAY_highway;
				osm.oway->flags |= MWAY_F_junction;
			}
			else if (strcmp ((char*) v, (char*) "trunk") == 0) osm.oway->type = MWAY_highway;
			else if (strcmp ((char*) v, (char*) "trunk_link") == 0) {
				osm.oway->type = MWAY_highway;
				osm.oway->flags |= MWAY_F_junction;
			}
			else if (strcmp ((char*) v, (char*) "residential") == 0) osm.oway->type = MWAY_residential;
			else if (strcmp ((char*) v, (char*) "living_street") == 0) osm.oway->type = MWAY_residential;
			else if (strcmp ((char*) v, (char*) "road") == 0) osm.oway->type = MWAY_residential;
			else if (strcmp ((char*) v, (char*) "unclassified") == 0) osm.oway->type = MWAY_residential;
			else if (strcmp ((char*) v, (char*) "path") == 0) osm.oway->type = MWAY_residential;
			else if (strcmp ((char*) v, (char*) "construction") == 0) osm.oway->type = MWAY_residential;
			else if (strcmp ((char*) v, (char*) "cycleway") == 0) osm.oway->type = MWAY_cycleway;
			else if (strcmp ((char*) v, (char*) "track") == 0) osm.oway->type = MWAY_railway;
			else if (strcmp ((char*) v, (char*) "service") == 0) osm.oway->type = MWAY_service;
			else if (strcmp ((char*) v, (char*) "platform") == 0) osm.oway->type = MWAY_footway;
			else if (strcmp ((char*) v, (char*) "footway") == 0) osm.oway->type = MWAY_footway;
			else if (strcmp ((char*) v, (char*) "pedestrian") == 0) osm.oway->type = MWAY_footway;
			else if (strcmp ((char*) v, (char*) "steps") == 0) osm.oway->type = MWAY_footway;
			else {
				osm.oway->type = MWAY_unknown_way;
				printf ("unknown highway:'%s'\n", v);
			}
		}

		/*
		 * check if it is a railway
		 */
		else if (strncmp ((char*) k, (char*) "railway", 8) == 0) {
			if (strcmp ((char*) v, (char*) "rail") == 0) {
				osm.oway->flags = osm.oway->flags | MWAY_F_railway;
				if (osm.oway->type == MWAY_unknown || osm.oway->type == MWAY_unknown_railway) 
					osm.oway->type = MWAY_railway; 
			}
			else if  (strcmp ((char*) v, (char*) "abandoned") == 0) {
				osm.oway->flags = osm.oway->flags | MWAY_F_railway;
				if (osm.oway->type == MWAY_unknown || osm.oway->type == MWAY_unknown_railway) osm.oway->type = MWAY_unknown_railway; 
			}
			else {
				osm.oway->flags = osm.oway->flags | MWAY_F_railway;
	//			d_printf ("unknown railway:'%s' name:%s type:%d id:%lld", v, osm.oway->name, osm.oway->type, osm.oway->wid);
				if (osm.oway->type == MWAY_unknown || osm.oway->type == MWAY_unknown_railway) 
					osm.oway->type = MWAY_unknown_railway; 
			}
		}


		/*
		 * name ?
		 */
		else if (strncmp ((char*) k, (char*) "name", 5) == 0) {
			strncpy (osm.oway->name, (char*)v, MAP_W_NAMELEN);
		}

		
		/*
		 * ref ?
		 */
		else if (strncmp ((char*) k, (char*) "ref", 4) == 0) {
			strncpy (osm.oway->ref, (char*)v, MAP_W_NAMELEN);
		}

		
		/*
		 * one way ?
		 */
		else if (strncmp ((char*) k, (char*) "oneway", 7) == 0) {
			if (strcmp ((char*) v, (char*) "yes") == 0)
				osm.oway->flags = osm.oway->flags | MWAY_F_oneway;
		}


		/*
		 * junction ?
		 */
		else if (strncmp ((char*) k, (char*) "junction", 9) == 0) {
			if (strcmp ((char*) v, (char*) "roundabout") == 0)
				osm.oway->flags |= MWAY_F_roundabout;
		}


		/*
		 * construction ?
		 */
		else if (strncmp ((char*) k, (char*) "construction", 13) == 0) {
			osm.oway->flags |= MWAY_F_planed;
		}

		
		
		/*
		 * check if we have an area
		 */
		else if (strncmp ((char*) k, (char*) "natural", 8) == 0 || strncmp ((char*) k, (char*) "landuse", 8) == 0) {
			if (strcmp ((char*) v, (char*) "water") == 0) osm.oway->type = MAREA_water;
			else if (strcmp ((char*) v, (char*) "industrial") == 0) osm.oway->type = MAREA_industrial;
			else if (strcmp ((char*) v, (char*) "heath") == 0) osm.oway->type = MAREA_industrial;
			else if (strcmp ((char*) v, (char*) "construction") == 0) osm.oway->type = MAREA_industrial;
			else if (strcmp ((char*) v, (char*) "commercial") == 0) osm.oway->type = MAREA_commercial;
			else if (strcmp ((char*) v, (char*) "retail") == 0) osm.oway->type = MAREA_commercial;
			else if (strcmp ((char*) v, (char*) "cemetery") == 0) osm.oway->type = MAREA_commercial;
			else if (strcmp ((char*) v, (char*) "farm") == 0) osm.oway->type = MAREA_farm;
			else if (strcmp ((char*) v, (char*) "field") == 0) osm.oway->type = MAREA_farm;
			else if (strcmp ((char*) v, (char*) "farmland") == 0) osm.oway->type = MAREA_farm;
			else if (strcmp ((char*) v, (char*) "farmyard") == 0) osm.oway->type = MAREA_farm;
			else if (strcmp ((char*) v, (char*) "village_green") == 0) osm.oway->type = MAREA_greenfield;
			else if (strcmp ((char*) v, (char*) "greenfield") == 0) osm.oway->type = MAREA_greenfield;
			else if (strcmp ((char*) v, (char*) "grass") == 0) osm.oway->type = MAREA_greenfield;
			else if (strcmp ((char*) v, (char*) "residential") == 0) osm.oway->type = MAREA_residential;
			else if (strcmp ((char*) v, (char*) "allotments") == 0) osm.oway->type = MAREA_residential;
			else if (strcmp ((char*) v, (char*) "forest") == 0) osm.oway->type = MAREA_wood;
			else if (strcmp ((char*) v, (char*) "meadow") == 0) osm.oway->type = MAREA_wood;
			else if (strcmp ((char*) v, (char*) "wood") == 0) osm.oway->type = MAREA_wood;
			else if (strcmp ((char*) v, (char*) "land") == 0) osm.oway->type = MAREA_land;
			else if (strcmp ((char*) v, (char*) "military") == 0) osm.oway->type = MAREA_military;
			else if (strcmp ((char*) v, (char*) "basin") == 0) osm.oway->type = MAREA_water;
			else if (strcmp ((char*) v, (char*) "reservoir") == 0) osm.oway->type = MAREA_water;
			else if (strcmp ((char*) v, (char*) "-----") == 0) osm.oway->type = MAREA_ignore;
			else {
				osm.oway->type = MAREA_ignore;
				// d_printf ("unknown natural+landuse:'%s'", v);
			}
			osm.oway->type += MWAY_MAX;
		}
		else if (strncmp ((char*) k, (char*) "boundary", 8) == 0 && strcmp ((char *) v, (char *) "yes") == 0) {
			osm.oway->type = MAREA_ignore + MWAY_MAX;
		}
		else if (strncmp ((char*) k, (char*) "man made", 8) == 0 && strcmp ((char *) v, (char *) "pipeline") == 0) {
			osm.oway->type = MAREA_ignore + MWAY_MAX;
		}
		else if (strncmp ((char*) k, (char*) "building", 8) == 0 && strcmp ((char *) v, (char *) "yes") == 0) {
			osm.oway->type = MAREA_ignore + MWAY_MAX;
		}
		else if (strncmp ((char*) k, (char*) "tourism", 8) == 0 && strcmp ((char *) v, (char *) "camp_site") == 0) {
			osm.oway->type = MAREA_campsite + MWAY_MAX;
		}
		free ((void *)k);
		free ((void *)v);
	}
	
	else if ((strncmp ((char*) name, (char*) "nd", 3) == 0) && last == (void*)osm.oway) { // node to a way?
		attr = xmlTextReaderGetAttribute (reader, (xmlChar*)"ref");
		if (attr == NULL) return;
		id = atoll ((char*)attr);
		free ((void *)attr);

		if (osm.oway->ncnt+1 > osm.oway->nmax) {
			tmpoway = osm_way_alloc (osm.oway->nmax+16);
			osm_way_copy (tmpoway, osm.oway);
			ml_free (osm.oway);
			osm.oway = tmpoway;
		}
		osm.oway->nid[osm.oway->ncnt] = id;
		osm.oway->ncnt++;
		last = osm.oway;
	}
	else if (xmldepth == 1) {
		xmlolddepth = xmldepth;
		last = NULL;
	}
};


int osm_loadfile_readcallback (void *context, char *buffer, int len) {
	int bzerr, bzlen;
	struct s_osm_xmlcallback *xmlcb = (struct s_osm_xmlcallback*) context;
	static int loopcnt;
	if (++loopcnt > 100) {
		xmlcb->filepos = ftell (xmlcb->f) / 1000;
		osm_file_pos = (100.0 * (float)(xmlcb->filepos) / (float)(xmlcb->filesize));
		loopcnt = 0;
	}
	
	bzlen = BZ2_bzRead (&bzerr, xmlcb->bzf, buffer, len);
	if (bzerr == BZ_STREAM_END && !feof(xmlcb->f)) {
		/* next data stream */
		unsigned char unused[BZ_MAX_UNUSED];
		unsigned char *unusedTmp;
		int nUnused = 0;

		BZ2_bzReadGetUnused (&bzerr, xmlcb->bzf, (void**) &unusedTmp, &nUnused);
		if (nUnused > 0) memcpy (unused, unusedTmp, nUnused);
		BZ2_bzReadClose (&bzerr, xmlcb->bzf);
		xmlcb->bzf = BZ2_bzReadOpen(&bzerr, xmlcb->f, 0, 0, unused, nUnused);
	}
	
	if (bzerr != BZ_OK) d_printf ("%s:%d bzread: should:%d is:%d   filepos:%d   error:%d", __FILE__, __LINE__, bzlen, len, xmlcb->filepos, bzerr);

	if (bzerr == BZ_CONFIG_ERROR) d_printf ("BZ_CONFIG_ERROR");
	else if (bzerr == BZ_PARAM_ERROR) d_printf ("BZ_PARAM_ERROR");
	else if (bzerr == BZ_IO_ERROR) d_printf ("BZ_IO_ERROR");
	else if (bzerr == BZ_MEM_ERROR) d_printf ("BZ_MEM_ERROR");
	else if (bzerr == BZ_SEQUENCE_ERROR) d_printf ("BZ_SEQUENCE_ERROR");
	else if (bzerr == BZ_DATA_ERROR) d_printf ("BZ_DATA_ERROR");
	else if (bzerr == BZ_DATA_ERROR_MAGIC) d_printf ("BZ_DATA_ERROR_MAGIC");
	else if (bzerr == BZ_UNEXPECTED_EOF) d_printf ("BZ_UNEXPECTED_EOF");
	else if (bzerr != BZ_OK) d_printf ("any other bz error is there:%d", bzerr);

	return bzlen;
};


int osm_loadfile_closecallback(void *context) {
    int bzerr;
    
    BZ2_bzReadClose(&bzerr, ((struct s_osm_xmlcallback *)context)->bzf);
    return bzerr == BZ_OK;
};


void osm_loadfile (char *fn) {
	xmlTextReaderPtr reader;
	struct s_osm_xmlcallback xmlcb;
	int ret, compressed, i, timeout_cnt = 0, bzerr;
	time_t timeout;
	char ext[16];
	
	osm_init ();
	if (fn == NULL) return;
	app_status (-1, _("converting file"), 0.0);
	d_printf ("osm_loadfile (%s)", fn);
	
	/* check the extension of the osm file */
	for (i = 0; i < 15 && fn[i+strlen(fn)-4] != 0; i++) 
		ext[i] = tolower (fn[i+strlen(fn)-4]);
	ext[i] = 0;
	if (strncmp (ext, ".bz2", 5) == 0) compressed = 1;
	else compressed = 0;

	/* set the locale to POSIX, needed for decimal numbers. */
	setlocale(LC_ALL, "C");

	if (compressed) {	    
		xmlcb.f = fopen (fn, "r");
		if (!xmlcb.f) {
			d_printf ("%s:%d could not open file '%s' for reading. Error:%s", __FILE__, __LINE__, fn, strerror (errno));
			return;
		}
		fseek (xmlcb.f, 0, SEEK_END);
		xmlcb.filesize = ftell (xmlcb.f) / 1000;
		fseek (xmlcb.f, 0, SEEK_SET);
	
		xmlcb.bzf = BZ2_bzReadOpen(&bzerr, xmlcb.f, 0, 0, NULL, 0);
	    if (xmlcb.bzf == NULL || bzerr != BZ_OK) {
			d_printf ("%s:%d osm_loadfile could not open source file.", __FILE__, __LINE__);
			exit (0);
	    }
		reader = xmlReaderForIO(osm_loadfile_readcallback, osm_loadfile_closecallback, &xmlcb, "", NULL, 0);
	}
	else reader = xmlReaderForFile(fn, NULL, 0);

	/*
	 * read the whole file...
	 */
	if (reader != NULL) {
		ret = xmlTextReaderRead(reader);
		while (ret == 1) {
			osm_processdata(reader);
			ret = xmlTextReaderRead(reader);
			
			if (++timeout_cnt > 1000 || timeout < time(NULL)) {	
				if (compressed)
					main_wnd_loop(xmlcb.filepos, xmlcb.filesize);
				else 
					main_wnd_loop(xmlTextReaderGetParserLineNumber (reader), -1);
				timeout = time(NULL);
				timeout_cnt = 0;
			}	
		}
		xmlFreeTextReader(reader);
	}
	if (compressed) {
		fclose (xmlcb.f);
	}

	/* check data inside the hash for waynodes */
	osm_waynodes_check ();
	
	/* reset the locale setting back to the environment setting */
	setlocale (LC_ALL, NULL);
	osm_free ();
	app_status (-1, _(""), 0.0);
};


#define MLWEBMAX 10
void map_load_web (struct map_pos hs, struct map_pos he) {
	char parm1[128];
	char parm2[128];
	char cmd[255];
	char url[128];
	char *args[13];
	int ret, i;
	float x1, y1;
	struct stat sb;
	struct map_pos h;
	struct {
		struct s_execcall p;
		char fcache[LEN_FILENAME];
	} wl[MLWEBMAX];

	d_printf ("map_load_web: (%f , %f) --> (%f , %f)", hs.lon, hs.lat, he.lon, he.lat);

	/* check for cache directory */
	if (stat(cfg.cachepath, &sb) == -1) {
		char fn[LEN_FILENAME];
		strncpy (fn, cfg.cachepath, LEN_FILENAME);
		fn[strlen(fn)-1] = 0;
		d_printf ("create cache dir:%s", fn);
 #if !defined(__MINGW32CE__) && !defined(_WIN32_WCE) && !defined(__MINGW32__)
		mkdir (fn, 0755);
 #else
		mkdir (fn);
 #endif
	}

	app.status = APPSTATUS_loadfromweb;
#if defined (_LINUX_)
	osm_load_from_web_end = he;
	osm_load_from_web_start = hs;
	app_status (-1, _("refresh from OpenStreetMap.org"), 0.0);

	for (ret = 0; ret < MLWEBMAX; ret++) wl[ret].p.used = 0;
	for (ret = 0; ret < 13; ret++) args[ret] = NULL;

	for (h.lon = hs.lon; h.lon < he.lon || cmpf(h.lon, he.lon); h.lon = h.lon + MAP_OSMWEB_DELTA) 
		for (h.lat = hs.lat; h.lat < he.lat || cmpf(h.lat, he.lat); h.lat = h.lat + MAP_OSMWEB_DELTA) {
				do {
					main_wnd_loop (-1,-1);
					/* check for any finished forked processes 
					 * if so, call osm_loadfile 				*/
					for (i = 0; i < MLWEBMAX; i++) {
						if (wl[i].p.used) {
							ret = execwait (&wl[i].p);
							if (ret == 1) {
								osm_loadfile (wl[i].fcache);
								app_status (-1, _("refresh from OpenStreetMap.org"), 0.0);
								main_wnd_update ();
							}
						}
					}

					for (i = 0; i < MLWEBMAX && wl[i].p.used == 1; i++);
				}
				while (i >= MLWEBMAX);		/* exit if we can fork another process */

				y1 = CALC_START (h.lon, MAP_OSMWEB_DELTA);
				x1 = CALC_START (h.lat, MAP_OSMWEB_DELTA);
			
				setlocale(LC_ALL, "C");
				sprintf (wl[i].fcache, "%s/c%.4f-%.4f-%.4f-%.4f.osm", cfg.cachepath, y1-MAP_OSMWEB_DELTA, x1-MAP_OSMWEB_DELTA, y1+MAP_OSMWEB_DELTA, x1+MAP_OSMWEB_DELTA);
				if (stat(wl[i].fcache, &sb) == -1) {
					setlocale(LC_ALL, "C");
					sprintf (cmd, "/usr/bin/wget");
					args[0] = cmd;
					sprintf (parm1, "-O");
					args[1] = parm1;
					sprintf (parm2, "%s", wl[i].fcache);
					args[2] = parm2;
					sprintf (url, "http://api.openstreetmap.org/api/0.6/map?bbox=%.5f,%.5f,%.5f,%.5f", y1-MAP_OSMWEB_DELTA, x1-MAP_OSMWEB_DELTA, y1+MAP_OSMWEB_DELTA, x1+MAP_OSMWEB_DELTA);
					args[3] = url;
					setlocale(LC_ALL, NULL);
					ret = execcall(&wl[i].p, cmd, args);
				}
				else {
					osm_loadfile (wl[i].fcache);
					main_wnd_update ();
				}
			}
	do {
		main_wnd_loop (-1,-1);
		for (i = 0; i < MLWEBMAX; i++) {
			if (wl[i].p.used) {
				ret = execwait (&wl[i].p);
				if (ret == 1) {
					osm_loadfile (wl[i].fcache);
					main_wnd_update ();
				}
			}
		}

		for (ret = 0, i = 0; i < MLWEBMAX; i++) 
			if (wl[i].p.used == 1) ret = 1;
		}
	while (ret);
#endif
	app.status = APPSTATUS_nothing;
};


/***************************************************
 * displaying some informations on the screen 
 */
#ifdef HAVE_NCURSES
#include <curses.h>

void osm_convert_info () {
	int i;
	
	attrset(A_BOLD | COLOR_PAIR(3));
	mvprintw(6,10, "OSM HashNodes  Information");
	attrset(COLOR_PAIR(3));
	for (i = 0; i < 16; i++)
			mvprintw(7+i,1, "hid:     hash:          nodes:       kb");
	attrset(A_BOLD | COLOR_PAIR(2));
	
	for (i = 0; i < 16 && i < OSM_HASHNODES; i++) {
		if (hashnodes[i] == NULL) continue;
		mvprintw(7+i,5, "%d", hashnodes[i]->hid);
		mvprintw(7+i,15, "%d", hashnodes[i]->hash_cnt);
		mvprintw(7+i,31, "%d", hashnodes[i]->nodes_end/1024);
		if (hashnodes[i]->hash) mvprintw(7+i, 0, "*");
		else mvprintw(7+i, 0, " ");
	}
}

#endif
