#include <math.h>

#include "geo.h"
#include "bgraphic.h"
#include "util.h"

CELL val(int x, int y)
{
	if (wrap)
	{
		if (y<0) y=SIZE-1;
		else if (y>=SIZE) y=0;

		if (x<0) x=SIZE2-1;
		else if (y==0 || y>=SIZE) x=0;
		else if (x>=SIZE2) x=0;
	}
	else
	{
		if (y<0) y=0; else if (y>=SIZE) y=SIZE-1;
		if (x<0) x=0; else if (x>=SIZE2) x=SIZE2-1;
	}

	return cell[x][y].elev;
}

void delta(int x, int y, int &x1, int &y1, int &x2, int &y2, int step)
{
	x1 = x-step;
	y1 = y-step;
	x2 = x+step;
	y2 = y+step;

	if (wrap)
	{
		if (y1<0) y1=SIZE-1; else if (y1>=SIZE) y1=0;
		if (y2<0) y2=SIZE-1; else if (y2>=SIZE) y2=0;

		if (x1<0) x1=SIZE2-1;
		else if (y==0 || y>=SIZE || x1>=SIZE2) x1=0;

		if (x2<0) x2=SIZE2-1;
		else if (y==0 || y>=SIZE || x2>=SIZE2) x2=0;
	}
	else
	{
		if (x1<0) x1=0; else if (x1>=SIZE2) x1=SIZE2-1;
		if (x2<0) x2=0; else if (x2>=SIZE2) x2=SIZE2-1;
		if (y1<0) y1=0; else if (y1>=SIZE ) y1=SIZE -1;
		if (y2<0) y2=0; else if (y2>=SIZE ) y2=SIZE -1;
	}
}


void rescale()
{
	int x,y;

	CELL2 e;
	CELL2 min = -1;
	CELL2 max = +1;

	GraphicsHandler->clreol (0,400);
	GraphicsHandler->printf (LIGHTRED, 0,400, "Scanning");

	int step = pow(2,GEO_LEVEL-LEVEL);

	for (x=0; x<SIZE2; x+=step)
	{
		if ( (x & 0x000F) == 0)
			GraphicsHandler->printf (LIGHTRED,0,400,"Scanning %3d%%",
				int((long(x)*100)/SIZE2));

		for (y=0; y<SIZE; y+=step)
		{
			e = cell[x][y].elev - sea;

			if (e < min) min = e;
			if (e > max) max = e;
		}
	}

	GraphicsHandler->clreol (0,400);
	GraphicsHandler->printf (LIGHTRED, 0,400, "Rescaling");

	// to keep everything within bounds, we need to scale to
	// reasonable values:
	//
	// if (sea)  e = (sealevel * e) / min
	// if (land) e = (max_el * e) / max

	min = - min;

	for (x=0; x<SIZE2; x+=step)
	{
		if ( (x & 0x000F) == 0)
			GraphicsHandler->printf (LIGHTRED,0,400,"Rescaling %3d%%",
				int((long(x)*100)/SIZE2));

		for (y=0; y<SIZE; y+=step)
		{
			e = cell[x][y].elev - sea;

			if (e < 0)
			{
				e *= sea;
				e /= min;
			}
			else
			{
				e *= GEO_NORM_EL;
				e /= max;
			}
			e += sea;
			cell[x][y].elev = e;
		}
	}
	GraphicsHandler->clreol (0,400);
	map_wrap(wrap);
}

#if sizeof(CELL)==1
#define SQ_CONST 6
#else
#define SQ_CONST 100
#endif

void square_filter()
{
	int x,y;
	int step = pow(2,GEO_LEVEL-LEVEL);
//	CELL2 S=sqrt(sea);

	GraphicsHandler->clreol (0,400);
	GraphicsHandler->printf (LIGHTRED, 0,400, "Squaring");

	for (x=0; x<SIZE2; x+=step)
	{
		if ( (x & 0x000F) == 0)
			GraphicsHandler->printf (LIGHTRED,0,400,"Square %3d%%",
				int((long(x)*100)/SIZE2));

		for (y=0; y<SIZE; y+=step)
		{
			CELL2 e = cell[x][y].elev;

			if (e > sea)
			{
				e -= sea;
				e /= SQ_CONST;
				e *= e;
				e += sea;
			}
/*
			else
			{
//				e = sea-e;		// find depth
				e /= S;
				e *= e;
//				e = sea-e;		// turn into sea again
//				if (e<0) e=0;	// check bounds!
			}
*/
			cell[x][y].elev = e;
		}
	}
	GraphicsHandler->clreol (0,400);
	map_wrap(wrap);
}

void sqrt_filter()
{
	int x,y;

	GraphicsHandler->clreol (0,400);
	GraphicsHandler->printf (LIGHTRED, 0,400, "UnSquaring");

	int step = pow(2,GEO_LEVEL-LEVEL);
	for (x=0; x<SIZE2; x+=step)
	{
		if ( (x & 0x000F) == 0)
			GraphicsHandler->printf (LIGHTRED,0,400,"UnSquare %3d%%",
				int((long(x)*100)/SIZE2));

		for (y=0; y<SIZE; y+=step)
		{
			CELL2 e = cell[x][y].elev;

			if (e > sea)
			{
				e -= sea;
				e = CELL2(sqrt(e));
				e *= SQ_CONST;
				e += sea;
				cell[x][y].elev = e;
			}
		}
	}
	GraphicsHandler->clreol (0,400);
	map_wrap(wrap);
}


void new_map()
{
	int x,y;

	// initialize
	GraphicsHandler->clreol (0,420);
	GraphicsHandler->printf (LIGHTGRAY, 0,420,"Seeding");

	int step = pow(2,GEO_LEVEL-LEVEL);

	for (x=0; x<SIZE2; x+=step)
		for (y=0; y<SIZE; y+=step)
			cell[x][y].elev = map_init();

	// mountain ranges
/*
	int x1,y1,x2,y2;

	GraphicsHandler->clreol(0,420);
	GraphicsHandler->printf (LIGHTGRAY, 0,420,"Mountain ranges");
	x2 = SIZE2/step;
	y2 = SIZE/step;
	for (int i=dice(3,8); i>0; --i) // # of ranges
	{
		x  = random(x2) * step;
		y  = random(y2) * step;
		x1 = random(x2) * step;
		y1 = random(y2) * step;

		if (x>x1)
		{
			int tmp = x;
			x = x1;
			x1 = tmp;
		}
		if (y>y1)
		{
			int tmp = y;
			y = y1;
			y1 = tmp;
		}

		while (x!=x1 && y!=y1) // walk from (x,y) to (x1,y1)
		{
			cell [x][y].elev += random(4000) + 4000;
			if (cell[x][y].elev > 18000)
				cell[x][y].elev = 18000;

			if (x < x1) x += (random(2)*step);
			if (y < y1) y += (random(2)*step);
		}

	}
*/
	// map sure the edges of the map match

	GraphicsHandler->clreol(0,420);
	map_wrap(wrap);
}

void map_calc (int level)
{
	int x,y;
	int step,offset;

	if (level<1) return;

	GraphicsHandler->printf (LIGHTGRAY, 0,420,"Level %d ",level);

	step = pow(2,GEO_LEVEL-level+1);
	offset = step>>1;

	if (step<=0) return; // paranoia check to catch endless loops

	GraphicsHandler->printf (LIGHTGRAY, 400,420,"Offset =%3d     Step =%3d",
		offset, step);


	// calculate top and bottom horizontal edges
	for (x=offset; x<=SIZE2-offset; x+=step)
	{
		if(!wrap)
		{
			cell [x][     0].elev = map_ave2 (
						val( x-offset, 0),
						val( x+offset, 0));

			cell [x][SIZE-1].elev = map_ave2 (
						val( x-offset, SIZE-1),
						val( x+offset, SIZE-1));
		}
	}

	// calculate left & right vertical edges

	for (y=offset; y<SIZE; y+=step)
	{
		cell[0][y].elev = map_ave2 (
			val(0, y-offset),
			val(0, y+offset));

		if (wrap)
			cell[SIZE2-1][y].elev = cell[0][y].elev;
		else
			cell[SIZE2-1][y].elev = map_ave2 (
			 val(SIZE2-1,y-offset),
			 val(SIZE2-1,y+offset));
	}

	// calculate verticals

	for (x=step; x<SIZE2; x+=step)
		for (y=offset; y<SIZE; y+=step)
			cell [x][y].elev = map_ave2 (
				val(x, y-offset),
				val(x, y+offset));

	// calculate horizontals

	for (y=step; y<SIZE; y+=step)
		for (x=offset; x<SIZE2; x+=step)
			cell [x][y].elev = map_ave2 (
				val(x-offset, y),
				val(x+offset, y));

	// calculate the odd rows

	for (x=offset; x<SIZE2; x+=step)
		for (y=offset; y<SIZE; y+=step)

			cell [x][y].elev = map_ave8 (
				val (x-offset, y-offset),
				val (x-offset, y       ),
				val (x-offset, y+offset),
				val (x       , y-offset),
				val (x       , y+offset),
				val (x+offset, y-offset),
				val (x+offset, y       ),
				val (x+offset, y+offset));

	GraphicsHandler->clreol(0,420);
	map_wrap(wrap);
}


// This is a huge process;  it traces the runoff from every cell on the
// map until it reaches sea level
/*
void calc_runoff ()
{
	int X,Y,x,y,low,i,z;
	int cx[8], cy[8];

	for (X=0; X<SIZE2; X++)
		for (Y=0; Y<SIZE; Y++)
		{
			GraphicsHandler->printf(LIGHTGRAY,400,430,"X=%3d  Y=%3d",X,Y);
			x = X;
			y = Y;

			for (;;)
			{
				z = cell[x][y].elev;
				if (z<4000) break;			// 4000 is min sea level

				cx[0] = x-1; cy[0] = y-1;
				cx[1] = x-1; cy[1] = y  ;
				cx[2] = x-1; cy[2] = y+1;
				cx[3] = x  ; cy[3] = y-1;
				cx[4] = x  ; cy[4] = y+1;
				cx[5] = x+1; cy[5] = y-1;
				cx[6] = x+1; cy[6] = y  ;
				cx[7] = x+1; cy[7] = y+1;

				low = 30000;

				for (i=0; i<8; i++)
				{
					if (cell [cx[i]][cy[i]].elev < low)
						low = cell [cx[i]][cy[i]].elev;
				}
				if (x<=low) break;		// no place to go from here
				for (i=0; i<8; i++)
				{
					if (cell [cx[i]][cy[i]].elev == low)
					{
						x = cx[i];
						y = cy[i];
						break;
					}
				}
				if (x<0 || y<0 || x>=SIZE2 || y>=SIZE) break;	// bounds

				if (cell[x][y].runoff < 255)
					cell [x][y].runoff++;
			}
		}

}
*/


