/* draw.c
 * Copyright (C) Steffen Pohle 2010 <steffen@gulpe.de>
 * 
 * main.c 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 3 of the License, or
 * (at your option) any later version.
 * 
 * main.c 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, see <http://www.gnu.org/licenses/>.
 */

#include <sys/time.h>
#include <math.h>

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


/**************************************************************************
 * color definitions, hopfully this can go out soon, need to find a way to 
 * specify only the rgb values like it is in HTML and thats it.
 * i.e. color = 0xFF0000; for red.
 */
struct line_style draw_linestyle[MWAY_MAX];
struct color color_polygon[MAREA_MAX];
struct color color_bg;
struct color color_fg;
struct color color[COLOR_MAX][COLOR_steps];


/**************************************************************************
 * current screen data, center of the screen? where we look at the scale,
 * and the drawing flags. All these values start with view_*
 */
float view_scale = 0.001;
float view_lon = 11.183;
float view_lat = 48.736;
int view_flags = DRAW_GPSFOLLOW;


/**************************************************************************
 * internal variables set by some functions within the drawing stuff and
 * from withing the *_gfx sources.. Some drawing functon will have vriables 
 * declared on top of the first function. (i.E. drawing lines, polygones.
 */
int draw_type[MAREA_MAX+MWAY_MAX];

/*
 * selection variables
 */
struct map_pos select_pos;
int select_enabled = 0;

char statusline_text[255] = "";
int statusline_progress = 0;

void draw_line (struct image *img, int x1, int y1, int x2, int y2, struct line_style style);
void draw_lineway (struct image *img, int x1, int y1, int x2, int y2, struct line_style style);
void draw_rectangle (struct image *img, int x1, int y1, int x2, int y2, struct line_style style);


/*************************************************************************
 * to prevent the flickering screen, we create two images inside the 
 * memory. One which keeps a larger area of the map (so we only draw 
 * the map once in a while) and a second map with the on screen data.
 * img_map: keeps the current map screen values.
 * img_screen: is the final data with the on screen data to copy on
 * the screen.
 */
struct image *img_map = NULL;		// image data of the current map
struct map_pos img_map_pos;			// position of the current map
float img_map_scale;				// scale of the current map


/**************************************************************************
 *
 * functions to convert between geo data and screen data
 *
 */
iPoint draw_geo2screen (float center_lon, float center_lat, float lon, float lat) {
	iPoint r;
	
	r.x = - (map_lon2km (center_lon - lon, lat) / view_scale);
	r.y = (map_lat2km (center_lat - lat) / view_scale);

	return r;
};


void draw_screen2geo (int x, int y, float *lon, float *lat) {
	y = y - gfx_screensize.y/2;
	x = x - gfx_screensize.x/2;

	*lat = -map_km2lat(((float)y) * view_scale);
	*lon = map_km2lon(((float)x) * view_scale, view_lat + *lat);
	*lat = view_lat + *lat;
	*lon = view_lon + *lon;
};


/******************************************************************************
 * set the new scale, and check what will have to be shown
 */
void draw_setscale (int newscale) {
	float scale = view_scale;

	if (newscale < 0) {
		scale = scale / 1.5;
	}
	else {
		scale = scale * 1.5;
	}
	d_printf ("scale: %f -> %f (i:%d)", view_scale, scale, newscale);
	draw_setscalef (scale);
};


void draw_setscalef (float newscale) {
	int i;

	view_scale = newscale;
	if (view_scale < 0.001) view_scale = 0.001;
	else if (view_scale > 0.5) view_scale = 0.5;
		
	/* change display settings */
	if (view_scale < 0.01) {
		for (i = 0; i < MWAY_MAX+MAREA_MAX; i++)
			draw_type [i] = TRUE;
	}
	else if (view_scale < 0.1) {
		for (i = 0; i < MWAY_MAX+MAREA_MAX; i++) {
			switch (i) {
				case (MWAY_tertiary):
				case (MWAY_highway):
				case (MWAY_MAX + MAREA_greenfield):
				case (MWAY_MAX + MAREA_water):
				case (MWAY_MAX + MAREA_industrial):
				case (MWAY_MAX + MAREA_residential):
					draw_type [i] = TRUE;
					break;
				default:
					draw_type [i] = FALSE;
					break;
			}
		}
	}
	else {
		for (i = 0; i < MWAY_MAX+MAREA_MAX; i++) {
			switch (i) {
				case (MWAY_highway):
				case (MWAY_MAX + MAREA_greenfield):
				case (MWAY_MAX + MAREA_wood):
				case (MWAY_MAX + MAREA_water):
				case (MWAY_MAX + MAREA_residential):
					draw_type [i] = TRUE;
					break;
				default:
					draw_type [i] = FALSE;
					break;
			}
		}
	}

	main_wnd_update();
};


void draw_set_flag (int flag) {
	view_flags |= flag;
};


void draw_del_flag (int flag) {
	view_flags &= (0xFFFF - flag);
};


/**************************************************************************+
 * drawing initial functions
 */
void draw_init () {
	int n;
	
	d_printf ("draw_init");
	draw_init_color ();
	for (n = 0; n < MAREA_MAX; n++)	draw_type[n] = 1;

	view_lon = cfg.last_lon;
	view_lat = cfg.last_lat;
	draw_setscalef (cfg.last_scale);
};

void draw_init_color () {
	int n, i, r,g,b;

	d_printf ("draw_init_color");

	for (n = 0; n < COLOR_MAX; n++) for (i = COLOR_steps-1; i >= 0; i--) {
		if (i == COLOR_steps-1) {
			if (n == COLOR_white) 			gfx_color_alloc (&color[n][i], 0xFFFF, 0xFFFF, 0xFFFF);
			else if (n == COLOR_red) 		gfx_color_alloc (&color[n][i], 0xFFFF, 0x0, 0x0);
			else if (n == COLOR_redgray) 	gfx_color_alloc (&color[n][i], 0xFFFF, 0xA000, 0xA000);
			else if (n == COLOR_blue) 		gfx_color_alloc (&color[n][i], 0x0, 0x0, 0xFFFF);
			else if (n == COLOR_bluegray) 	gfx_color_alloc (&color[n][i], 0xA000, 0xA000, 0xFFFF);
			else if (n == COLOR_green) 		gfx_color_alloc (&color[n][i], 0x0, 0xFFFF, 0x0);
			else if (n == COLOR_greengray) 	gfx_color_alloc (&color[n][i], 0xA000, 0xFFFF, 0xA000);
			else if (n == COLOR_brown)	 	gfx_color_alloc (&color[n][i], 0xFFFF, 0x8000, 0x0);
			else if (n == COLOR_pink) 		gfx_color_alloc (&color[n][i], 0xFFFF, 0x0, 0xFFFF);
			else if (n == COLOR_yellow) 	gfx_color_alloc (&color[n][i], 0xFFFF, 0xFFFF, 0x0000);
			else {
				d_printf ("%s:%d not all colors have been defined..", __FILE__, __LINE__);
				exit (1);
			}	
		}
		else {
			r = color[n][COLOR_steps-1].r;
			g = color[n][COLOR_steps-1].g;
			b = color[n][COLOR_steps-1].b;
			if (n == COLOR_white) {
				if (i == 0) {
					r = g = b = 0;
				}
				else {
					r = r*(i)/COLOR_steps-1;
					g = g*(i)/COLOR_steps-1;
					b = b*(i)/COLOR_steps-1;
				}
			}
			else {
				r = r*(i+1)/COLOR_steps;
				g = g*(i+1)/COLOR_steps;
				b = b*(i+1)/COLOR_steps;
			}
			gfx_color_alloc (&color[n][i], r, g, b);
		}

		gfx_color_alloc (&color_bg, 0,0,0);					 // background
		gfx_color_alloc (&color_fg, 0x8000,0x8000,0x8000);   // foreground
	}

	for (n = 0; n < MWAY_MAX; n++) {
		draw_linestyle[n].width = 0.0;
		gfx_color_alloc (&draw_linestyle[n].borderc, 0x8000, 0x8000,0x8000);

		switch (n) {
		case (MWAY_highway):
			draw_linestyle[n].width = 4.0;
			gfx_color_alloc (&draw_linestyle[n].c, 0xFFFF,0xFFFF,0x8000);
			break;
		case (MWAY_tertiary):
			draw_linestyle[n].width = 3.0;
			gfx_color_alloc (&draw_linestyle[n].c, 0xA000,0xA000,0x0000);
			break;
		case (MWAY_residential):
			draw_linestyle[n].width = 2.0;
			gfx_color_alloc (&draw_linestyle[n].c, 0xA000,0xA000,0xA000);
			break;
		case (MWAY_cycleway):
			gfx_color_alloc (&draw_linestyle[n].c, 0x4000,0xA000,0x4000);
			break;
		case (MWAY_footway):
			gfx_color_alloc (&draw_linestyle[n].c, 0x4000,0x4000,0xA000);
			break;
		case (MWAY_railway):
			gfx_color_alloc (&draw_linestyle[n].c, 0x8000,0x8000,0x8000);
			break;
		case (MWAY_unknown_railway):
			gfx_color_alloc (&draw_linestyle[n].c, 0x6000,0x6000,0x6000);
			break;
		case (MWAY_service):
			gfx_color_alloc (&draw_linestyle[n].c, 0x6000,0x6000,0x6000);
			break;
		case (MWAY_unknown):
		case (MWAY_unknown_way):
		default:
			gfx_color_alloc (&draw_linestyle[n].c, 0xA000,0x5000,0x5000);
			break;
		}
	}

	for (n = 0; n < MAREA_MAX; n++) switch (n) {
		case (MAREA_water):
			gfx_color_alloc (&color_polygon[n], 0x4000,0x4000,0xFFFF);
			break;
		case (MAREA_greenfield):
			gfx_color_alloc (&color_polygon[n], 0x2000,0x8000,0x2000);
			break;
		case (MAREA_wood):
			gfx_color_alloc (&color_polygon[n], 0x0000,0x6000,0x0000);
			break;
		case (MAREA_land):
			gfx_color_alloc (&color_polygon[n], 0x6000,0x6000,0x0000);
			break;
		case (MAREA_residential):
			gfx_color_alloc (&color_polygon[n], 0x2000,0x2000,0x2000);
			break;
		case (MAREA_farm):
			gfx_color_alloc (&color_polygon[n], 0x8000,0x4000,0x2000);
			break;
		case (MAREA_industrial):
			gfx_color_alloc (&color_polygon[n], 0x8000,0x6000,0x8000);
			break;
		case (MAREA_commercial):
			gfx_color_alloc (&color_polygon[n], 0x8000,0x0000,0x8000);
			break;
		case (MAREA_military):
			gfx_color_alloc (&color_polygon[n], 0x2000,0x2000,0x2000);
			break;
		case (MAREA_building):
			gfx_color_alloc (&color_polygon[n], 0x6000,0x6000,0x6000);
			break;
		default:
			gfx_color_alloc (&color_polygon[n],0xFFFF,0x0000,0x0000);
			break;
	}	
};

/**************************************************************************+
 * drawing subfunctions
 */

/*
 * rectangle
 */
void draw_rectangle (struct image *dimg, int x1, int y1, int x2, int y2, struct line_style style) {
	gfx_draw_line (dimg, x1, y1, x2, y1, style);
	gfx_draw_line (dimg, x2, y1, x2, y2, style);
	gfx_draw_line (dimg, x2, y2, x1, y2, style);
	gfx_draw_line (dimg, x1, y2, x1, y1, style);
};


void draw_fillrectangle (struct image *dimg, int x1, int y1, int x2, int y2, struct color *c) {
	struct line_style ls;

	ls.c = *c;
	ls.borderc = *c;
	ls.width = 1.0;

	iPoint points[4] = { {x1, y1},
			{x2, y1},
			{x2, y2},
			{x1, y2} };

	gfx_draw_polygon (dimg, points, 4, ls, c);
};


/*
 * lines
 */
void draw_line (struct image *dimg, int x1, int y1, int x2, int y2, struct line_style style) {
	int width, height;

	if (dimg == NULL) {
		width = gfx_screensize.x;
		height = gfx_screensize.y;
	}
	else {
		width = dimg->width;
		height = dimg->height;
	}
	
	if ((x1 >= 0 && x1 <= width && y1 >= 0 && y1 <= height) ||
        (x2 >= 0 && x2 <= width && y2 >= 0 && y2 <= height) ||
		(x1 <= 0 && x2 >= width) || (x2 <= 0 && x1 >= width) ||
	    (y1 <= 0 && y2 >= height) || (y2 <= 0 && y1 >= height))
			gfx_draw_line (dimg, x1, y1, x2, y2, style);
};


/*
 * draw a polygon..
 */
static iPoint _polypoints[POLYGON_MAX_POINTS];
static int _polycnt;

void draw_polygonstart () {
	_polycnt = 0;
};

void draw_polygonadd (int x, int y) {
	if (_polycnt >= POLYGON_MAX_POINTS) {
		printf ("%s:%d draw_polygonadd: too many points.\n", __FILE__, __LINE__);
		return;
	}
	_polypoints[_polycnt].x = x;
	_polypoints[_polycnt].y = y;
	_polycnt++;
};


void draw_polygonfinish (struct image *dimg, struct line_style ls, struct color *c, int border) {
	int i;

	gfx_draw_polygon (dimg, _polypoints, _polycnt, ls, c);

	if (border) {
		for (i = 1; i < _polycnt; i++) {
			gfx_draw_line (dimg, _polypoints[i-1].x, _polypoints[i-1].y, _polypoints[i].x, _polypoints[i].y, ls);
		}
		gfx_draw_line (dimg, _polypoints[_polycnt-1].x, _polypoints[_polycnt-1].y, _polypoints[0].x, _polypoints[0].y, ls);
	}
	_polycnt = 0;
};


void draw_lineway (struct image *dimg, int x1, int y1, int x2, int y2, struct line_style style) {
	struct line_style tmplinestyle = style;

	if (view_scale < 0.01) 
		tmplinestyle.width = tmplinestyle.width * (0.005/view_scale);

	draw_line (dimg, x1, y1, x2, y2, tmplinestyle);
};


/************************************************************************
 * the drawing stuff itself.
 * before drawing everything on the screen, check if we need to redraw 
 * the map or just copy a part of it into the gui image.
 * After copying the map into the gui screen draw the gui, afterwards 
 * copy the gui screen onto the display.
 */
void draw_map () {
	struct map_hash *mh;
	struct map_way *cway;
	struct map_area *carea;
	struct map_place *cplace;
	struct map_poi *cpoi;
	int w, n, i;
	struct map_hashpos h, hs, he;
	iPoint p1, p2;
	fPoint nd, v1, v2, v3;
	struct line_style tmplinestyle;
	iPoint center;
	struct map_pos hashstart, hashend;
	struct color *c;
	char text[255];

	d_printf ("view_lon: %f view_lat:%f", view_lon, view_lat);

	gfx_clear (img_map, &color_bg);
	center.x = img_map->width / 2;
	center.y = img_map->height / 2;

	tmplinestyle.width = 1.0;
	tmplinestyle.c = tmplinestyle.borderc = color[COLOR_red][2];
	
	hashstart.lat = view_lat - map_km2lat(view_scale * ((float)img_map->width));
	hashstart.lon = view_lon - map_km2lon(view_scale * ((float)img_map->height), hashstart.lat);
	hashend.lat = view_lat + map_km2lat(view_scale * ((float)img_map->height));
	hashend.lon = view_lon + map_km2lon(view_scale * ((float)img_map->width), hashend.lat);

	hs.ilon = map_geo2igeo (hashstart.lon);
	hs.ilat = map_geo2igeo (hashstart.lat);
	he.ilon = map_geo2igeo (hashend.lon);
	he.ilat = map_geo2igeo (hashend.lat);

	/*
	 * draw areas
	 */
	for (h.ilon = hs.ilon; h.ilon <= he.ilon; h.ilon++) 
		for (h.ilat = hs.ilat; h.ilat <= he.ilat; h.ilat++) {
			if (app.status == APPSTATUS_nothing) mh = map_hash_geti (h.ilon, h.ilat, MHLOAD_RELOAD);
			else mh = map_hash_geti (h.ilon, h.ilat, MHLOAD_NONE);
			if (mh) {
				carea = mh->areas;
				while (carea) {
					if (draw_type[carea->type + MWAY_MAX]) {
						draw_polygonstart ();
						for (n = 0; n < carea->p_cnt; n++) 
							if (n == 0 || n == carea->p_cnt-1 || view_scale < 0.01 
							    || ((view_scale < 0.1 && (n % 2) == 0) || carea->p_cnt < 5) 
							    || ((view_scale < 0.1 && (n % 4) == 0) || carea->p_cnt < 10)) {
									p1 = draw_geo2screen (view_lon, view_lat, carea->p[n].lon, carea->p[n].lat);
								//	if (n == 0) {
								//		draw_line (img_map, p1.x + center.x - 5, p1.y + center.y - 5, p1.x + center.x + 5, p1.y + center.y + 5, tmplinestyle);
								//		draw_line (img_map, p1.x + center.x + 5, p1.y + center.y - 5, p1.x + center.x - 5, p1.y + center.y + 5, tmplinestyle);
								//	}
								//	if (n == 0) sprintf (text, "%d:%d", n, carea->subid);
								//	else  sprintf (text, "%d", n);
								//	gfx_draw_text (img_map,  p1.x + center.x - 20, p1.y + center.y - 10, text, &color[COLOR_white][3]);
									draw_polygonadd (p1.x + center.x, p1.y + center.y);
							}
						draw_polygonfinish (img_map, tmplinestyle, &color_polygon[carea->type], 0);
					}
					carea = carea->next;	
				}
			}
		}

	/*
	 * draw ways
	 */
	/* draw outside */
	for (h.ilon = hs.ilon; h.ilon <= he.ilon; h.ilon++)
		for (h.ilat = hs.ilat; h.ilat <= he.ilat; h.ilat++) {
			/*
			 * draw the hash.. 
			 */
			if (app.status == APPSTATUS_nothing) mh = map_hash_geti (h.ilon, h.ilat, MHLOAD_RELOAD);
			else  mh = map_hash_geti (h.ilon, h.ilat, MHLOAD_NONE);
			if (mh) {
				/*
				 * ways
				 */
				cway = mh->ways;
				while (cway) {
					if (cway->id != 0 && draw_type[cway->type]) {
						/* go through all the nodes */
						tmplinestyle.width = draw_linestyle[cway->type].width * (0.005/view_scale) + 2;
						tmplinestyle.c = tmplinestyle.borderc = color[COLOR_white][1];
						if (view_scale < 0.01) {
							for (n = 0; n < cway->p_cnt; n++) {
								p2 = p1;
								nd.x = map_lon2km (view_lon - cway->p[n].lon, cway->p[n].lat);
								nd.y = map_lat2km (view_lat - cway->p[n].lat);
								p1.x = center.x - (nd.x / view_scale);
								p1.y = center.y + (nd.y / view_scale);
				
								if (n > 0) 
									draw_line (img_map, p1.x, p1.y, p2.x, p2.y, tmplinestyle);
							}
						}
						else {
							for (n = -1; n < cway->n_cnt;) {
								/* find next node */
								if (n == -1) {
									i = 0;
									n++;
								}
								else { 
									for (n = 0, w = cway->p_cnt; n < cway->n_cnt; n++) {
										if (cway->n[n].pnr > i && cway->n[n].pnr < w) w = cway->n[n].pnr;
									}
									if (w == cway->p_cnt) i = cway->p_cnt - 1;
									else {
										i = w;
										n = 1;
									}
								}
								p2 = p1;
								nd.x = map_lon2km (view_lon - cway->p[i].lon, cway->p[i].lat);
								nd.y = map_lat2km (view_lat - cway->p[i].lat);
								p1.x = center.x - (nd.x / view_scale);
								p1.y = center.y + (nd.y / view_scale);
				
								if (n > 0) 
									draw_line (img_map, p1.x, p1.y, p2.x, p2.y, tmplinestyle);
							}
						}

						/* draw the waynodes */
						for (n = 0; n < cway->n_cnt; n++) if (cway->n[n].pnr < cway->p_cnt) {
							p1 = draw_geo2screen (view_lon, view_lat, cway->n[n].d.lon, cway->n[n].d.lat);
							p2 = draw_geo2screen (view_lon, view_lat, cway->p[cway->n[n].pnr].lon, cway->p[cway->n[n].pnr].lat);
							p1.x += center.x;
							p1.y += center.y;
							p2.x += center.x;
							p2.y += center.y;
							draw_line (img_map, p1.x, p1.y, p2.x, p2.y, tmplinestyle);
						}
					}
					cway = cway->next;
				}
			}
		}

	/* ways inside */
	for (h.ilon = hs.ilon; h.ilon <= he.ilon; h.ilon++)
		for (h.ilat = hs.ilat; h.ilat <= he.ilat; h.ilat++) {
			/*
			 * draw the hash.. 
			 */
			if (app.status == APPSTATUS_nothing) mh = map_hash_geti (h.ilon, h.ilat, MHLOAD_RELOAD);
			else  mh = map_hash_geti (h.ilon, h.ilat, MHLOAD_NONE);
			if (mh) {
				/*
				 * ways
				 */
				cway = mh->ways;
				while (cway) {
					if (cway->id != 0 && draw_type[cway->type] && (cway->flags & MWAY_F_planed) == 0) {
						/* go through all the nodes */
						if (view_scale < 0.01) {
							for (n = 0; n < cway->p_cnt; n++) {
								p2 = p1;
								nd.x = map_lon2km (view_lon - cway->p[n].lon, cway->p[n].lat);
								nd.y = map_lat2km (view_lat - cway->p[n].lat);
								p1.x = center.x - (nd.x / view_scale);
								p1.y = center.y + (nd.y / view_scale);
								if (n > 0) {
									if (cway->type >= MWAY_MAX)
										draw_lineway (img_map, p1.x, p1.y, p2.x, p2.y, draw_linestyle[MWAY_unknown]);
									else
										draw_lineway (img_map, p1.x, p1.y, p2.x, p2.y, draw_linestyle[cway->type]);

									/* one way arrow */
									if (cway->flags & MWAY_F_oneway && view_scale < 0.004) {
										tmplinestyle.width = 1;
										tmplinestyle.c = tmplinestyle.borderc = color[COLOR_white][0];
										nd.x = (p1.x+p2.x)/2;
										nd.y = (p1.y+p2.y)/2;
										v1.x = p1.x-p2.x;
										v1.y = p1.y-p2.y;
										v1 = vec_one (v1);
										v2 = vec_turn90 (v1);
										v3 = vec_mirror (v2);
										v1 = vec_mul (v1, 3.0);
										v2 = vec_mul (v2, 3.0);
										v3 = vec_mul (v3, 3.0);
										v1 = vec_add (v1, nd);
										v2 = vec_add (v2, nd);
										v3 = vec_add (v3, nd);
										draw_line (img_map, v1.x, v1.y, v2.x, v2.y, tmplinestyle);
										draw_line (img_map, v1.x, v1.y, v3.x, v3.y, tmplinestyle);
									}
								}
							}
						}
						else {
							for (n = -1; n < cway->n_cnt;) {
								// d_printf ("LINE: %lld n_cnt:%d p_cnt:%d", cway->id, cway->n_cnt, cway->p_cnt);
								/* find next node */
								if (n == -1) {
									i = 0;
									n++;
								}
								else {
									for (n = 0, w = cway->p_cnt; n < cway->n_cnt; n++) {
										if (cway->n[n].pnr > i && cway->n[n].pnr < w) w = cway->n[n].pnr;
									}
									if (w == cway->p_cnt) i = cway->p_cnt - 1;
									else {
										i = w;
										n = 1;
									}
								}
								// d_printf ("   i:%d n:%d", i, n);
								p2 = p1;
								nd.x = map_lon2km (view_lon - cway->p[i].lon, cway->p[i].lat);
								nd.y = map_lat2km (view_lat - cway->p[i].lat);
								p1.x = center.x - (nd.x / view_scale);
								p1.y = center.y + (nd.y / view_scale);
				
								if (n > 0) {
									if (cway->type >= MWAY_MAX)
										draw_lineway (img_map, p1.x, p1.y, p2.x, p2.y, draw_linestyle[MWAY_unknown]);
									else
										draw_lineway (img_map, p1.x, p1.y, p2.x, p2.y, draw_linestyle[cway->type]);
								}
							}
						}

						/* draw the waynodes */
						for (n = 0; n < cway->n_cnt; n++) if (cway->n[n].pnr < cway->p_cnt) {
							p1 = draw_geo2screen (view_lon, view_lat, cway->n[n].d.lon, cway->n[n].d.lat);
							p2 = draw_geo2screen (view_lon, view_lat, cway->p[cway->n[n].pnr].lon, cway->p[cway->n[n].pnr].lat);
							p1.x += center.x;
							p1.y += center.y;
							p2.x += center.x;
							p2.y += center.y;
							if (cway->type >= MWAY_MAX)
								draw_lineway (img_map, p1.x, p1.y, p2.x, p2.y, draw_linestyle[MWAY_unknown]);
							else
								draw_lineway (img_map, p1.x, p1.y, p2.x, p2.y, draw_linestyle[cway->type]);
						}
						else d_printf ("%s:%d wayid:%lld cway->n[n].pnr(%d) < cway->p_cnt(%d) doesn't match", __FILE__, __LINE__, cway->id, cway->n[n].pnr, cway->p_cnt);
	
					}
					cway = cway->next;
				}
			}
		}

	/*
	 * draw places, pois just on top layers
	 */
	for (h.ilon = hs.ilon; h.ilon <= he.ilon; h.ilon++) 
		for (h.ilat = hs.ilat; h.ilat <= he.ilat; h.ilat++) {

			if (app.status == APPSTATUS_nothing) mh = map_hash_geti (h.ilon, h.ilat, MHLOAD_RELOAD);
			else mh = map_hash_geti (h.ilon, h.ilat, MHLOAD_NONE);
			if (mh) {
				/*
				 * places
				 */
				cplace = mh->places;
				i = 0;
				while (cplace) {
					if (view_scale < 0.01 
					       || cplace->type == MAP_PLACE_city
					       || cplace->type == MAP_PLACE_town 
					       || (cplace->type == MAP_PLACE_village && view_scale < 0.05)) {
						i++;
						p1 = draw_geo2screen(view_lon, view_lat, cplace->lon, cplace->lat);
						p1.x += center.x;
						p1.y += center.y;
						switch (cplace->type) {
							case (MAP_PLACE_city):
							case (MAP_PLACE_town):
							case (MAP_PLACE_village):
								gfx_draw_text (img_map, p1.x,p1.y, cplace->name, &color[COLOR_white][3]);
								break;
							case (MAP_PLACE_hamlet):
							case (MAP_PLACE_suburb):
								gfx_draw_text (img_map, p1.x,p1.y, cplace->name, &color[COLOR_bluegray][2]);
								break;
							default:
								gfx_draw_text (img_map, p1.x,p1.y, cplace->name,  &color[COLOR_bluegray][2]);
								break;
						}
					}
					cplace = cplace->next;
				}

				
				/*
				 * poi
				 */
				cpoi = mh->pois;
				i = 0;
				if (view_scale < 0.01) while (cpoi) {
					p1 = draw_geo2screen(view_lon, view_lat, cpoi->lon, cpoi->lat);
					p1.x += center.x;
					p1.y += center.y;
					if (cpoi->type != MAP_POI_unknown &&
					    ((view_scale < 0.01 && cpoi->type == MAP_POI_gasstation)
					    || (view_scale < 0.0015))) {
						switch (cpoi->type) {
							case (MAP_POI_campsite):
								sprintf (text, "C");
								c = &color[COLOR_greengray][3];
								break;
							default:
								sprintf (text, "?");
								c = &color[COLOR_red][3];
								break;
						}
						gfx_draw_text (img_map, p1.x-4, p1.y-4, text, c);
						gfx_draw_text (img_map, p1.x-strlen(cpoi->name)*2, p1.y+8, cpoi->name, c);
					}		
					cpoi = cpoi->next;
				}
			}
		}

	// tmplinestyle.width = 4.0;
	// tmplinestyle.c = tmplinestyle.borderc = color_red1;
	// draw_line (img_map, center.x-100, center.y, center.x+100, center.y, tmplinestyle);
	// draw_line (img_map, center.x, center.y-100, center.x, center.y+100, tmplinestyle);
	// draw_lines (img_map);
	// sprintf (text, "%f,%f", view_lon, view_lat);
	// gfx_img_draw_text (img_map, center.x,center.y, text, &color_blue1);
	
	/*
	 * save data of the map drawed
	 */
	img_map_pos.lon = view_lon;
	img_map_pos.lat = view_lat;
	img_map_scale = view_scale;
};


int draw_mapcopy () {
	iPoint p1, p2;

	p2 = draw_geo2screen (img_map_pos.lon, img_map_pos.lat, view_lon, view_lat);
	p1.x = img_map->width/2 + p2.x - gfx_screensize.x/2;
	p1.y = img_map->height/2 + p2.y - gfx_screensize.y/2;

	if (p1.x < 0 || p1.y < 0 
	    || p1.x > (img_map->width - gfx_screensize.x) 
	    || p1.y > (img_map->height - gfx_screensize.y)) return 0;
	
	gfx_draw_img (NULL, 0, 0, gfx_screensize.x, gfx_screensize.y, img_map, p1.x, p1.y);

	return 1;
};




void draw () {
	static int still_drawing = 0;
	
	/* only run once at the time.. */
	if (still_drawing) return;
	still_drawing = 1;

	while (view_lon > 180.0) view_lon -= 360.0;
	while (view_lon < -180.0) view_lon += 360.0;
	while (view_lat > 180.0) view_lat -= 360.0;
	while (view_lat < -180.0) view_lat += 360.0;

	/* do we need to alloc the screens */
	if (img_map != NULL && (img_map->width != gfx_screensize.x * 2 || img_map->height != gfx_screensize.y * 2)) {
		gfx_img_free (img_map);
		img_map = NULL;
	}
	if (img_map == NULL) {
	//	img_map = gfx_img_alloc (400 * 2, 400 * 2);
		img_map = gfx_img_alloc (gfx_screensize.x * 2, gfx_screensize.y * 2);
		img_map_scale = -1.0;
	}

	/* draw the map, if needed */
	if (img_map_scale < 0.0 || img_map_scale != view_scale) {
		draw_map ();
	}
	gfx_clear (NULL, &color[COLOR_white][0]);
	if (draw_mapcopy () == 0) {
		draw_map ();
		draw_mapcopy ();
	}

	draw_gui ();
	gfx_flip ();
	still_drawing = 0;
};


void draw_redrawmap () {
	img_map_scale = -1;
	draw ();
};
