#include "trackmap.h"
#include <float.h>
#ifdef __APPLE__
#include "SDL_gfxPrimitives.h"
#else
#include <SDL/SDL_gfxPrimitives.h>
#endif

TRACKMAP::TRACKMAP(TRACK *t)
{
	track = t;
	BuildMap();
	cardot0.Load("hud/cardot0.png", false);
	cardot1.Load("hud/cardot1.png", false);
	CalcPosition();
}

TRACKMAP::~TRACKMAP()
{
	if (surface)
	{
		SDL_FreeSurface(surface);
	}
	track_map.Unload();
	cardot0.Unload();
	cardot1.Unload();
}

void TRACKMAP::CalcPosition()
{
	int w,h;
        settings.Get("display.width", w);
        settings.Get("display.height", h);
	screen_w = (float)w;
	screen_h = (float)h;
        position_x = 1.0 - MAP_WIDTH / screen_w;
        position_y = 0.12;
        width = MAP_WIDTH / screen_w;
        height = MAP_HEIGHT / screen_h;
	dot_w_half = cardot0.GetTexture()->w / 2.0 / screen_w; 
	dot_h_half = cardot0.GetTexture()->h / 2.0 / screen_h; 
}
	
void TRACKMAP::BuildMap()
{
	int outsizex = MAP_WIDTH;
	int outsizey = MAP_HEIGHT;
	
	Uint32 rmask, gmask, bmask, amask;

	/* SDL interprets each pixel as a 32-bit number, so our masks must depend
	   on the endianness (byte order) of the machine */
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
	rmask = 0xff000000;
	gmask = 0x00ff0000;
	bmask = 0x0000ff00;
	amask = 0x000000ff;
#else
	rmask = 0x000000ff;
	gmask = 0x0000ff00;
	bmask = 0x00ff0000;
	amask = 0xff000000;
#endif
	
	surface = SDL_CreateRGBSurface(SDL_SWSURFACE, outsizex, outsizey, 32, rmask, gmask, bmask, amask);
	
	//find the map width and height
	map_w = 0.0;
	map_h = 0.0;
	map_w_min = FLT_MAX;
	map_w_max = FLT_MIN;
	map_h_min = FLT_MAX;
	map_h_max = FLT_MIN;

	ROADSTRIPNODE * curnode = track->GetRoads();

	while (curnode != NULL)
	{
		for (list <BEZIER>::iterator curp = curnode->road.patchnodes.begin();
			curp != curnode->road.patchnodes.end(); curp++)
		{
			int i,j;
			for (i = 0; i < 4; i++)
			{
				for (j = 0; j < 4; j++)
				{
					VERTEX p = curp->points[i][j];
					if (p.x < map_w_min)
					{
						map_w_min = p.x;
					}
					if (p.x > map_w_max)
					{
						map_w_max = p.x;
					}
					if (p.z < map_h_min)
					{
						map_h_min = p.z;
					}
					if (p.z > map_h_max)
					{
						map_h_max = p.z;
					}
				}
			}
                }

                curnode = curnode->next;
        }

	map_w = map_w_max - map_w_min;
	map_h = map_h_max - map_h_min;

	//determine the scaling factor
	//we will leave a 1 pixel border
	float scale_w = (outsizex-2) / map_w;
	float scale_h = (outsizey-2) / map_h;
	scale = (scale_w < scale_h)?scale_w:scale_h;

	boxRGBA(surface, 0, 0, outsizex-1, outsizey-1, 0, 0, 0, 0);

        curnode = track->GetRoads();

        while (curnode != NULL)
        {
		for (list <BEZIER>::iterator curp = curnode->road.patchnodes.begin();
			curp != curnode->road.patchnodes.end(); curp++)
                {
			Sint16 x[4], y[4];

                        VERTEX back_l = curp->points[3][0];
                        VERTEX back_r = curp->points[3][3];
                        VERTEX front_l = curp->points[0][0];
                        VERTEX front_r = curp->points[0][3];

			x[0] = int((back_l.x - map_w_min) * scale) + 1;
			y[0] = int((back_l.z - map_h_min) * scale) + 1;
			x[1] = int((front_l.x - map_w_min) * scale) + 1;
			y[1] = int((front_l.z - map_h_min) * scale) + 1;
			x[2] = int((front_r.x - map_w_min) * scale) + 1;
			y[2] = int((front_r.z - map_h_min) * scale) + 1;
			x[3] = int((back_r.x - map_w_min) * scale) + 1;
			y[3] = int((back_r.z - map_h_min) * scale) + 1;
			filledPolygonRGBA(surface, x, y, 4, 255, 255, 255, 255);
			aapolygonRGBA(surface, x, y, 4, 255, 255, 255, 255);
                }

                curnode = curnode->next;
        }

	//draw the starting line
	BEZIER* startpatch = track->GetLapSequence(0);
	if (startpatch)
	{
		VERTEX startline_l = startpatch->points[3][0];
		VERTEX startline_r = startpatch->points[3][3];
		int x1 = int((startline_l.x - map_w_min) * scale) + 1;
		int y1 = int((startline_l.z - map_h_min) * scale) + 1;
		int x2 = int((startline_r.x - map_w_min) * scale) + 1;
		int y2 = int((startline_r.z - map_h_min) * scale) + 1;
		aalineRGBA(surface, x1, y1, x2, y2, 255, 0, 0, 255);
		filledCircleRGBA(surface, x1, y1, 2, 255, 0, 0, 255);
		filledCircleRGBA(surface, x2, y2, 2, 255, 0, 0, 255);
	}

	//draw a black border around the track
	int x,y;
	Uint32* rawpixels = (Uint32*)surface->pixels;
	Uint32 rgbmask = rmask | gmask | bmask;

	for (x = 0; x < outsizex; x++)
	{
		for (y = 0; y < outsizey; y++)
		{
			//if this pixel is black
			if (rawpixels[outsizex * y + x] == 0)
			{
				//if the pixel above this one is non-black
				if ((y > 0) && ((rawpixels[outsizex * (y-1) + x] & rgbmask) > 0))
				{
					//set this pixel to non-transparent
					rawpixels[outsizex * y + x] |= amask;
				}
				//if the pixel left of this one is non-black
				if ((x > 0) && ((rawpixels[outsizex * y + x - 1] & rgbmask) > 0))
				{
					//set this pixel to non-transparent
					rawpixels[outsizex * y + x] |= amask;
				}
				//if the pixel right of this one is non-black
				if ((x < (outsizex - 1)) && ((rawpixels[outsizex * y + x + 1] & rgbmask) > 0))
				{
					//set this pixel to non-transparent
					rawpixels[outsizex * y + x] |= amask;
				}
				//if the pixel below this one is non-black
				if ((y < (outsizey - 1)) && ((rawpixels[outsizex * (y+1) + x] & rgbmask) > 0))
				{
					//set this pixel to non-transparent
					rawpixels[outsizex * y + x] |= amask;
				}
			}
		}
	}

	track_map.Load("track.map", surface);
	
	/*if (surface)
	{
		SDL_FreeSurface(surface);
		surface = NULL;
	}*/
}

void TRACKMAP::DrawCarDot(int car_index, Vamos_Geometry::Three_Vector position)
{
	VERTEX car_pos;
	car_pos.x = position[0];
	car_pos.y = position[2];
	car_pos.z = -position[1];

	float x = position_x + ((car_pos.x - map_w_min) * scale + 1) / screen_w;
	float y = position_y + ((car_pos.z - map_h_min) * scale + 1) / screen_h;

	if (car_index == 0) // player car
	{
		utility.Draw2D(x - dot_w_half, y - dot_h_half, x + dot_w_half, y + dot_h_half, &cardot0);
	}
	else // opponent car
	{
		utility.Draw2D(x - dot_w_half, y - dot_h_half, x + dot_w_half, y + dot_h_half, &cardot1);
	}
}
