#include <stdio.h>
#include <conio.h>
#include <stdarg.h>
#include <math.h>

#include "geo.h"
#include "bgraphic.h"


void set_map_palette()
{
	// set palette .............. slot ....... color
	GraphicsHandler->Palette (	MAGENTA,		 0	);
	GraphicsHandler->Palette (	BLUE,			 8	);
	GraphicsHandler->Palette (	LIGHTBLUE, 		 1	);
	GraphicsHandler->Palette (	LIGHTMAGENTA,	 9	);
	GraphicsHandler->Palette (	BROWN,			 6	);
	GraphicsHandler->Palette (	YELLOW,			22	);
	GraphicsHandler->Palette (	LIGHTGREEN,		 2	);
	GraphicsHandler->Palette (	GREEN,			16	);
	GraphicsHandler->Palette (	CYAN,			24	);
	GraphicsHandler->Palette (	LIGHTCYAN,		56	);
	GraphicsHandler->Palette (	LIGHTGRAY,		 7	);
	GraphicsHandler->Palette (	WHITE,			63	);
}

//***********************************************************************
//
//	Display map in graphics mode
//
//***********************************************************************


void map_erase ()
{
	BOX_TYPE b;

	b.x1 = 0;
	b.y1 = 0;
	b.x2 = GraphicsHandler->ScreenWidth();
	b.y2 = 369;
	GraphicsHandler->FillBox (BLACK, &b);
}

#define PI 3.141592654

inline int k(int x, int y)
{
	float H = cos(y*(PI/SIZE)) * (SIZE/2);
	return int(H + SIZE/2);
}

inline int h(int x, int y)
{
	float H = sin((y*PI)/SIZE);
	return int(H * (x-SIZE) + SIZE);
}

inline void map_plot(int color, int x, int y)
{
//	int h,k;		// rectangular (x,y) is mapped to sinusoidal (h,k)

	GraphicsHandler->Color(color);
	lineto(h(x,y),k(x,y));
}


inline int k2(int x, int y)
{
	return y;
}

inline int h2(int x, int y)
{
	// h = (x-SIZE)* sqrt(sin((y*PI) / SIZE)) + SIZE

	float H;
	int ofs;

	if (x>SIZE)
	{
		ofs = SIZE-1;
		x -= SIZE;
	}
	else ofs = 0;

	H = sin((y*PI)/SIZE);

	return ofs + int(H * (x-(SIZE/2)) + (SIZE/2));
}

inline void map_plot2(int color, int x, int y)
{
	GraphicsHandler->Color(color);
	lineto(h2(x,y),k(x,y));
}

inline int k4(int x, int y)
{
	return y;
}

inline int h4(int x, int y)
{
	// h = (x-SIZE)* sqrt(sin((y*PI) / SIZE)) + SIZE

	float H;
	int ofs;

	if (x>((SIZE2*3)/4))
	{
		ofs = SIZE+SIZE/2-4;
		x -= ((SIZE2*3)/4);
	}
	else if (x>(SIZE2/2))
	{
		ofs = SIZE-3;
		x -= (SIZE2/2);
	}
	else if (x>(SIZE2/4))
	{
		ofs = SIZE/2-1;
		x -= (SIZE2/4);
	}
	else ofs = 0;

	H = sin((y*PI)/SIZE);

	return ofs + int(H * (x-(SIZE/4)) + (SIZE/4));
}

inline void map_plot4(int color, int x, int y)
{
	GraphicsHandler->Color(color);
	lineto(h4(x,y),k(x,y));
}

inline void map_plot_begin(int mode)
{
//	int h,k;		// rectangular (x,y) is mapped to sinusoidal (h,k)

	if (mode==1)
	{
		setcolor(LIGHTGRAY);
		ellipse(h(SIZE,SIZE/2)-1,k(SIZE,SIZE/2)-1, 0, 360, SIZE+2,SIZE/2+2);
	}
	else if (mode==2)
	{
		setcolor(LIGHTGRAY);
		circle(h(SIZE/2,SIZE/2)-1,k(SIZE/2,SIZE/2)-1,SIZE/2+1);
		circle(h((SIZE*3)/2,SIZE/2)-1,k((SIZE*3)/2,SIZE/2)-1,SIZE/2+1);
	}
}
inline void map_plot_vertex(int mode, int x)
{
	int H;

	if (mode==1) H = h(x,0);
	else if (mode==2) H = h2(x,0);
	else if (mode==3) H = h4(x,0);

	moveto(H,k(x,0));
}

#define ENLARGE(x) ((x)*enlargek)
long tot_land;
long tot_water;


void map_draw(int mode) // mercator=1 sinusoidal=0
{
	BOX_TYPE	b;

	int			x,y;
	int			c; 			// color
	int			xx;			// wrapped x
	int			step;		// step size
	int 		enlarge,	// parameters needed to draw the map
				enlargek,
				enlargej;
	int			OVERLAP;
	int			x_ofs_1;
	int			y_ofs_1;
	int			x_ofs_2;
	int			y_ofs_2;

	int			pr_overlap;	// boolean: print overlap?

	tot_land=0;
	tot_water=0;

	set_map_palette();

	enlargek = 1;
	if (GEO_LEVEL<=7) enlargek=2;

	// screen coordinate offsets
	x_ofs_1 = 33;
	y_ofs_1 = 33;
	x_ofs_2 = x_ofs_1 + 512 + 2 + enlargek;
	y_ofs_2 = y_ofs_1 + 256 + 2 + enlargek;


	enlarge = pow(2, GEO_LEVEL-LEVEL);
	OVERLAP = pow(2, GEO_LEVEL-3);
	step = enlarge;

	if (overlap && LEVEL>=4) pr_overlap = 1;
	else pr_overlap = 0;

	if (LEVEL<8) enlarge = ENLARGE(enlarge);

	enlargej = enlargek;

	// print left overlap

	GraphicsHandler->clreol (0,400);
	GraphicsHandler->printf (LIGHTRED, 0,400, "Drawing level %d",LEVEL);

	if (mode)
	{
//		map_plot_begin(mode);
		pr_overlap=0;
	}

	if (pr_overlap)
	{
		for (x=0; x<OVERLAP; x+=step)
		{
			xx = SIZE2-1-x;
			b.x1 = ENLARGE(x);
			if (x==SIZE2-1)
			{
				b.x2 = b.x1 + enlargek;
			}
			else b.x2 = b.x1 + enlarge - 1;

			// TOP LEFT
			for (y=0; y<OVERLAP; y+=step)
			{
				c = get_color (OVERLAP-x-step,OVERLAP-y-step,step);

				b.y1 = ENLARGE(y);
				b.y2 = b.y1 + enlarge - 1;
				GraphicsHandler->FillBox (c, &b);
			}

			// LEFT CENTER
			for (y=0; y<SIZE; y+=step)
			{
				c = get_color (x+SIZE2-1-OVERLAP+step,y,step);

				b.y1 = ENLARGE(y) + y_ofs_1;
				if (y==SIZE-1)
				{
					b.y2 = b.y1 + enlargej;
				}
				else b.y2 = b.y1 + enlarge - 1;
				GraphicsHandler->FillBox (c, &b);
			}

			// BOTTOM LEFT
			for (y=0; y<OVERLAP; y+=step)
			{
				c = get_color (OVERLAP-x-step,SIZE-1-y,step);

				b.y1 = ENLARGE(y) + y_ofs_2;
				b.y2 = b.y1 + enlarge - 1;
				GraphicsHandler->FillBox (c, &b);
			}
		}
	}

	// print main map

	for (x=0; x<SIZE2; x+=step)
	{
		xx = SIZE2-1-x;

		b.x1 = ENLARGE(x) + x_ofs_1;

		if (x==SIZE2-1)
		{
			b.x2 = b.x1 + enlargek;
		}
		else b.x2 = b.x1 + enlarge - 1;

		// TOP CENTER
		if (pr_overlap)
		{
			for (y=0; y<OVERLAP; y+=step)
			{
				c = get_color (xx,OVERLAP-y-step,step);

				b.y1 = ENLARGE(y);
				b.y2 = b.y1 + enlarge - 1;
				GraphicsHandler->FillBox (c, &b);
			}
		}

		// CENTER (MAIN MAP)

		if (mode) map_plot_vertex(mode,x);
		for (y=0; y<SIZE; y+=step)
		{
			c = get_color (x,y,step);

			if (mode==0)
			{
				b.y1 = ENLARGE(y) + y_ofs_1;

				if (y==SIZE-1)
				{
					b.y2 = b.y1 + enlargej;
				}
				else b.y2 = b.y1 + enlarge - 1;

				GraphicsHandler->FillBox (c, &b);
			}
			else if (mode==1)
				map_plot(c,x,y);
			else if (mode==2)
				map_plot2(c,x,y);
			else if (mode==3)
				map_plot4(c,x,y);
		}

		// BOTTOM CENTER
		if (pr_overlap)
		{
			for (y=0; y<OVERLAP; y+=step)
			{
				c = get_color (xx,SIZE-1-y,step);

				b.y1 = ENLARGE(y) + y_ofs_2;
				b.y2 = b.y1 + enlarge - 1;
				GraphicsHandler->FillBox (c, &b);
			}
		}

	}

	// print right overlap

	if (pr_overlap)
	{
		for (x=0; x<OVERLAP; x+=step)
		{
			xx = SIZE2-1-x;
			b.x1 = ENLARGE(x) + x_ofs_2;
			if (x==SIZE2-1)
			{
				b.x2 = b.x1 + enlargej;
			}
			else b.x2 = b.x1 + enlarge - 1;

			// TOP RIGHT
			for (y=0; y<OVERLAP; y+=step)
			{
				c = get_color (xx,OVERLAP-y-step,step);

				b.y1 = ENLARGE(y);
				b.y2 = b.y1 + enlarge - 1;
				GraphicsHandler->FillBox (c, &b);
			}

			// RIGHT CENTER
			for (y=0; y<SIZE; y+=step)
			{
				c = get_color (x,y,step);

				b.y1 = ENLARGE(y) + y_ofs_1;
				if (y==SIZE-1)
				{
					b.y2 = b.y1 + enlargej;
				}
				else b.y2 = b.y1 + enlarge - 1;
				GraphicsHandler->FillBox (c, &b);
			}

			// BOTTOM RIGHT
			for (y=0; y<OVERLAP; y+=step)
			{
				c = get_color (xx,SIZE-1-y,step);

				b.y1 = ENLARGE(y) + y_ofs_2;
				b.y2 = b.y1 + enlarge - 1;
				GraphicsHandler->FillBox (c, &b);
			}
		}
	}

	GraphicsHandler->clreol (0,400);

	long tot_cells = tot_land + tot_water;

	GraphicsHandler->printf(LIGHTGRAY,0,400,"Land: %3ld%%  Water:  %3ld%%",
		((tot_land*100)/tot_cells),((tot_water*100)/tot_cells));
	return;
}


int get_color (int x, int y, int step)
{
	CELL z;		// elevation
	CELL k;		// iterator used in finding contour lines

	CELL north,south,east,west;
	int x1,y1,x2,y2;

	z = cell[x][y].elev - sea;

#if sizeof(CELL)==1
	z >>= 2;
#else
	z /= 1000;
#endif

	if (z<0) tot_water++;
	else tot_land++;


	if (contours)
	{
		x1 = x-step;
		y1 = y-step;
		x2 = x+step;
		y2 = y+step;

		if (x1<0) x1=SIZE2-1; else if (x2>=SIZE2) x2=0;
		if (y1<0) y1=SIZE-1;  else if (y2>=SIZE ) y2=0;

		north = cell [x ][y1].elev - sea;
		south = cell [x ][y2].elev - sea;
		east  = cell [x1][y ].elev - sea;
		west  = cell [x2][y ].elev - sea;

#if sizeof(CELL)==1
		north >>= 2;
		south >>= 2;
		east  >>= 2;
		west  >>= 2;
#else
		north /= 1000;
		south /= 1000;
		east  /= 1000;
		west  /= 1000;
#endif
		if (colors==4)	// shade as if light from SE (NW on printer!)
		{
			if (z<0) return BLUE;

			else if (north>south)
			{
				if (east>west)			// south-west slope
				{
					return LIGHTGREEN;
				}
				else if (west>east)		// south-east slope
				{
					return GREEN;
				}
				else					// south slope
				{
					return GREEN;
				}
			}
			else if (south>north)
			{
				if (east>west)			// north-west slope
				{
					return YELLOW;
				}
				else if (west>east)		// north-east slope
				{
					return LIGHTGREEN;
				}
				else					// north slope;
				{
					return YELLOW;
				}

			}
			else // north == south
			{
				if (east>west)			// west slope
				{
					return YELLOW;
				}
				else if (west>east)		// east slope
				{
					return GREEN;
				}
				else					// level
				{
					return LIGHTGREEN;
				}
			}
		}
		else if (colors!=0)	// do colored contour lines
		{
			int good=0;
			for (k=0; k<20; k++)
				if (z>=k && (north<k || south<k || east<k || west<k))
				{
					good=1;
					break;
				}
			if (!good) return BLACK;
		}
		else		// do black & white contour lines
		{
			for (k=0; k<20; k++)
				if (z>=k && (north<k || south<k || east<k || west<k))
					return WHITE;
			return BLACK;
		}
	}

	if (colors == 1)
	{
		if		(z<-3)	return BLUE;
		else if	(z<-1)	return LIGHTBLUE;
		else if (z< 0)	return LIGHTMAGENTA;	// lblue
		else if (z< 1)	return YELLOW;
		else if	(z< 2)	return BROWN;
		else if	(z< 3)	return LIGHTGREEN;
		else if	(z< 4)	return GREEN;
		else if	(z< 5)	return LIGHTCYAN;
		else if	(z< 6)	return CYAN;
		else if	(z< 7)	return LIGHTGRAY;
		else			return WHITE;
	}
	else if (colors == 2)
	{
		if		(z<-3)	return BLUE;
		else if	(z<-1)	return LIGHTBLUE;
		else if (z< 0)	return LIGHTMAGENTA;	// lblue
		else if (z< 1)	return GREEN;			// dgreen
		else if (z< 2)	return LIGHTGREEN;		// green
		else if (z< 3)	return BROWN;			// brown
		else if (z< 4)	return RED;				// red
		else if (z< 5)	return LIGHTCYAN;		// gray
		else if (z< 6)	return LIGHTGRAY;		// lgray
		else			return WHITE;			// white
	}
	else if (colors == 3)
	{
		if		(z<-3)	return BLUE;
		else if	(z<-1)	return LIGHTBLUE;
		else if (z< 0)	return LIGHTMAGENTA;	// lblue
		else if (z< 1)	return YELLOW;			// lgreen
		else if (z< 2)	return LIGHTGREEN;		// green
		else if (z< 3)	return BROWN;			// brown
		else if (z< 4)	return RED;				// red
		else if (z< 5)	return LIGHTGRAY;		// lgray
		else			return WHITE;			// white

	}
	else if (colors == 4)
	{
		if		(z<-2)	return BLUE;
		else if	(z< 0)	return LIGHTBLUE;
		else if (z< 2)	return YELLOW;			// lgreen
		else if (z< 4)	return BROWN;			// brown
		else if (z< 6)	return RED;				// red
		else if (z< 8)	return LIGHTGRAY;		// lgray
		else			return WHITE;
	}
	else
	{
		if (z<0)	return LIGHTBLUE;
		else		return BLACK;
	}
}

