#define ALLEGRO_STATICLINK 
#include <allegro.h>
#include <assert.h>

#include "maze.h"
#include "data.h"


//This code is evil, you should use a counter, and increment it
// and decrement it, but with 6 second timer, i guess it really doesnt matter
volatile bool poison_flag = false;
void poison_flag_handler()
{
	poison_flag = true;
}
END_OF_FUNCTION(poison_flag_handler)

volatile int move_count = 0;
void move_count_handler()
{
	if (move_count > 0) move_count--;
}
END_OF_FUNCTION(move_count_handler)

volatile bool quitting = false;

int end_x, end_y;


void render(BITMAP *buffer, MAZE *maze, int x_offset = 0, int y_offset = 0, int scale = 5)
{
	clear_to_color(buffer, makecol(255,255,255));
	int _x, _y;
	for (_x = 0; _x < maze->width; _x++)
	{
		for (_y = 0; _y < maze->height; _y++)
		{
			putpixel(buffer, x_offset + scale * _x, y_offset + scale * _y, makecol(0,0,0));
			if (maze->wall[_y][_x][N])
				line(buffer, x_offset + scale * _x, y_offset + scale * _y, x_offset + scale * (_x + 1), y_offset + scale * _y, makecol(0,0,0));

			if (maze->wall[_y][_x][W])
				line(buffer, x_offset + scale * _x, y_offset + scale * _y, x_offset + scale * _x, y_offset + scale * (_y + 1), makecol(0,0,0));
		}
	}

	for (_y = 0; _y < maze->height; _y++)
	{
		if (maze->wall[_y][maze->width - 1][E])
			line(buffer, x_offset + scale * (maze->width), y_offset + scale * _y, x_offset + scale * (maze->width), y_offset + scale * (_y + 1), makecol(0,0,0));
	}
	for (_x = 0; _x < maze->width; _x++)
	{
			if (maze->wall[maze->height - 1][_x][S])
				line(buffer, x_offset + scale * _x, y_offset + scale * (maze->height), x_offset + scale * (_x + 1), y_offset + scale * (maze->height), makecol(0,0,0));
	}
}

void draw_quad(BITMAP *buffer, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, int c1, int c2)
{
	int point[8];

	point[0] = (int)x1; point[1] = (int)y1;
	point[2] = (int)x2; point[3] = (int)y2;
	point[4] = (int)x3; point[5] = (int)y3;
	point[6] = (int)x4; point[7] = (int)y4;
    
	polygon(buffer, 4, point, c1);

	line(buffer, (int)x1, (int)y1, (int)x2, (int)y2, c2);
	line(buffer, (int)x2, (int)y2, (int)x3, (int)y3, c2);
	line(buffer, (int)x3, (int)y3, (int)x4, (int)y4, c2);
	line(buffer, (int)x4, (int)y4, (int)x1, (int)y1, c2);
}

#define LEFT	0x1
#define RIGHT	0x2
#define END		0x4

#define MAX_WALL_LENGTH		32
#define MAX_SEE_DISTANCE	8
int wall[MAX_WALL_LENGTH];
int wall_length = 0;
bool capped = false;

void draw(BITMAP *buffer, int *wall, int wall_length , BITMAP *start)
{
	float q_x1, q_y1;
	float q_x2, q_y2;
	float q_x3, q_y3;
	float q_x4, q_y4;

	float hs = (160.0f - 10.0f)/ 160.0f;
	float vs = (100.0f - 10.0f)/ 160.0f;

	int end_depth = (wall_length * 20);
	int start_depth = (wall_length * 20);

	if (capped)
	{
		q_x1 =   0 + end_depth * hs; q_y1 = 0 + end_depth * vs;
		q_x2 =   0 + end_depth * hs; q_y2 = 200 - end_depth * vs;
		q_x3 = 320 - end_depth * hs; q_y3 = 200 - end_depth * vs;
		q_x4 = 320 - end_depth * hs; q_y4 = 0 + end_depth * vs;
	
		draw_quad(buffer, q_x1, q_y1, q_x2, q_y2, q_x3, q_y3, q_x4, q_y4, makecol(255,0,0), makecol(0,0,255));
	}

	for (int p = (wall_length - 1); p >= 0; p--)
	{
		end_depth = ((p+ 1) * 20);
		start_depth = (p * 20);

		if (wall[p] & LEFT)
		{
			q_x1 =   0 + start_depth * hs; q_y1 =   0 + start_depth * vs;
			q_x2 =   0 +   end_depth * hs; q_y2 =   0 +   end_depth * vs;
			q_x3 =   0 +   end_depth * hs; q_y3 = 200 -   end_depth * vs;
			q_x4 =   0 + start_depth * hs; q_y4 = 200 - start_depth * vs;
			draw_quad(buffer, q_x1, q_y1, q_x2, q_y2, q_x3, q_y3, q_x4, q_y4, makecol(255,0,0), makecol(0,0,255));
		}
		else
		{
			q_x1 =   0 +           0 * hs; q_y1 =   0 +   end_depth * vs;
			q_x2 =   0 +   end_depth * hs; q_y2 =   0 +   end_depth * vs;
			q_x3 =   0 +   end_depth * hs; q_y3 = 200 -   end_depth * vs;
			q_x4 =   0 +           0 * hs; q_y4 = 200 -   end_depth * vs;
			draw_quad(buffer, q_x1, q_y1, q_x2, q_y2, q_x3, q_y3, q_x4, q_y4, makecol(255,0,0), makecol(0,0,255));
		}

		if (wall[p] & RIGHT)
		{
			q_x1 = 320 - start_depth * hs; q_y1 =   0 + start_depth * vs;
			q_x2 = 320 -   end_depth * hs; q_y2 =   0 +   end_depth * vs;
			q_x3 = 320 -   end_depth * hs; q_y3 = 200 -   end_depth * vs;
			q_x4 = 320 - start_depth * hs; q_y4 = 200 - start_depth * vs;
			draw_quad(buffer, q_x1, q_y1, q_x2, q_y2, q_x3, q_y3, q_x4, q_y4, makecol(255,0,0), makecol(0,0,255));
		}
		else
		{
			q_x1 = 320 +           0 * hs; q_y1 =   0 +   end_depth * vs;
			q_x2 = 320 -   end_depth * hs; q_y2 =   0 +   end_depth * vs;
			q_x3 = 320 -   end_depth * hs; q_y3 = 200 -   end_depth * vs;
			q_x4 = 320 +           0 * hs; q_y4 = 200 -   end_depth * vs;
			draw_quad(buffer, q_x1, q_y1, q_x2, q_y2, q_x3, q_y3, q_x4, q_y4, makecol(255,0,0), makecol(0,0,255));
		}
		
		if (wall[p] & END)
		{
			q_x1 =  00 + (end_depth + start_depth) / 2 * hs; q_y1 =   0 + (end_depth + start_depth) / 2 * vs;
			q_x2 =  00 + (end_depth + start_depth) / 2 * hs; q_y2 = 200 - (end_depth + start_depth) / 2 * vs;
			q_x3 = 320 - (end_depth + start_depth) / 2 * hs; q_y3 = 200 - (end_depth + start_depth) / 2 * vs;
			q_x4 = 320 - (end_depth + start_depth) / 2 * hs; q_y4 =   0 + (end_depth + start_depth) / 2 * vs;

			float _w = q_x3 - q_x1;
			float _h = q_y3 - q_y1;

			masked_stretch_blit(start, buffer, 0, 0, 300, 200, (int)q_x1, (int)q_y1, (int)_w, (int)_h);
			line(buffer, (int)q_x1, (int)q_y1 + (int)_h, (int)q_x1 + (int)_w, (int)q_y1 + (int)_h, makecol(0,0,0));
		}

	}
}

bool is_wall(BITMAP *m, int x, int y)
{
	int c = getb(getpixel(m, x, y));
	if (c == 0)
		return true;
	return false;
}

void build_corridor(BITMAP *m, int x, int y, int direction)
{
	int c1, c2;
	for (int c = 0; c < MAX_WALL_LENGTH; c++)
	{
		wall[c] = 0;
	}
	wall_length = 0;
	capped = false;
	
//	for (int c = 0; c < MAX_WALL_LENGTH; c++)
	for (int c = 0; c < MAX_SEE_DISTANCE; c++)
	{
		switch (direction)
		{
			case N:
				if ((x == end_x) && ((y - c) == end_y))
					wall[wall_length] = wall[wall_length] | END;			
				if (is_wall(m, x - 1, y - c))
				{
					wall[wall_length] = wall[wall_length] | LEFT;
					putpixel(m, x - 1, y - c, makecol(0,0,255));
				} 
				if (is_wall(m, x + 1, y - c))
				{
					wall[wall_length] = wall[wall_length] | RIGHT;
					putpixel(m, x + 1, y - c, makecol(0,0,255));
				} 
				wall_length++;

				if (is_wall(m, x, y - c - 1))
				{
					capped = true;
					return;
				}
				break;
			case S:
				if ((x == end_x) && ((y + c) == end_y))
					wall[wall_length] = wall[wall_length] | END;			
				if (is_wall(m, x - 1, y + c))
				{
					wall[wall_length] = wall[wall_length] | RIGHT;
					putpixel(m, x - 1, y + c, makecol(0,0,255));
				} 
				if (is_wall(m, x + 1, y + c))
				{
					wall[wall_length] = wall[wall_length] | LEFT;
					putpixel(m, x + 1, y + c, makecol(0,0,255));
				} 
				wall_length++;
				if (is_wall(m, x, y + c + 1))
				{
					capped = true;
					return;
				}
				break;
			case E:
				if (((x + c) == end_x) && (y == end_y))
					wall[wall_length] = wall[wall_length] | END;			
				if (is_wall(m, x + c, y - 1))
				{
					wall[wall_length] = wall[wall_length] | LEFT;
					putpixel(m, x + c, (y - 1), makecol(0,0,255));
				} 
				if (is_wall(m, x + c, y + 1))
				{
					wall[wall_length] = wall[wall_length] | RIGHT;
					putpixel(m, x + c, (y + 1), makecol(0,0,255));
				} 
				wall_length++;
				if (is_wall(m, (x + c) + 1, y))
				{
					capped = true;
					return;
				}
				break;
			case W:
				if (((x - c) == end_x) && (y == end_y))
					wall[wall_length] = wall[wall_length] | END;
				if (is_wall(m, x - c, y - 1))
				{
					wall[wall_length] = wall[wall_length] | RIGHT;
					putpixel(m, x - c, (y - 1), makecol(0,0,255));
				} 
				if (is_wall(m, x - c, y + 1))
				{
					wall[wall_length] = wall[wall_length] | LEFT;
					putpixel(m, x - c, (y + 1), makecol(0,0,255));
				} 
				wall_length++;
				if (is_wall(m, (x - c) - 1, y))
				{
					capped = true;
					return;
				}
				break;
			default:
				allegro_message("dah");
		}
	}

	
}

void invert_bitmap(BITMAP *buffer)
{
	int c, r, g, b;
	for (int x = 0; x < buffer->w; x++)
	{
		for (int y = 0; y < buffer->h; y++)
		{
			c = getpixel(buffer, x, y);
			r = 255 - getr(c);
			g = 255 - getg(c);
			b = 255 - getb(c);
			putpixel(buffer, x, y, makecol(r, g, b));
		}
	}
}

void poison(BITMAP *buffer, int amount)
{
	int c, r, g, b;
	for (int x = 0; x < buffer->w; x++)
	{
		for (int y = 0; y < buffer->h; y++)
		{
			c = getpixel(buffer, x, y);
			r = getr(c) + (((255 - getr(c) - getr(c)) * amount) / 100);
			g = getg(c) + (((255 - getg(c) - getg(c)) * amount) / 100);
			b = getb(c) + (((255 - getb(c) - getb(c)) * amount) / 100);
			putpixel(buffer, x, y, makecol(r, g, b));
		}
	}
}

void reset_maze(MAZE *maze, int *p_x, int *p_y, int *p_dir, int *e_x, int *e_y)
{
	maze->generate();
	*p_x = (rand() % MAZE::width) * 2 + 1;
	*p_y = (rand() % MAZE::height) * 2 + 1;
	*p_dir = rand() % 4;
	*e_x = (rand() % MAZE::width) * 2 + 1;
	*e_y = (rand() % MAZE::height) * 2 + 1;

}



int main(int argc, char **argv)
{
	srand(time(NULL));
	
	allegro_init();
	install_keyboard();
	install_mouse();


	LOCK_VARIABLE(poison_flag);
	LOCK_FUNCTION(poison_flag_handler);

	LOCK_VARIABLE(move_count);
	LOCK_FUNCTION(move_count_handler);




	set_color_depth(32);


	if (argc > 1)
	{
		set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);
	}
	else
	{
		set_gfx_mode(GFX_AUTODETECT_FULLSCREEN, 640, 480, 0, 0);
	}
	
	fixup_datafile(data);


	BITMAP *buffer = create_bitmap(320, 200);
	
	MAZE maze;
	int player_x, player_y;
	int player_direction;
	
	clear(buffer);
	textout_ex(buffer, font, "You are poisened!", 92, 8, makecol(0,0,0), makecol(255,0,0));	
	textout_ex(buffer, font, "You are ", 92, 8, makecol(255,0,0), makecol(0,0,0));	

	textout_centre_ex(buffer, font, "The madman has thrown you into his", 160, 24, makecol(255,0,0), makecol(0,0,0));	
	textout_centre_ex(buffer, font, "dungeon, he cackles gleefully,", 160, 32, makecol(255,0,0), makecol(0,0,0));	
	textout_centre_ex(buffer, font, " \"If you make it out I might", 160, 48, makecol(255,0,0), makecol(0,0,0));	
	textout_centre_ex(buffer, font, "just give you the antidote.\"", 160, 56, makecol(255,0,0), makecol(0,0,0));	

	textout_centre_ex(buffer, font, "Can you escape the 3 levels?", 160, 72, makecol(255,0,0), makecol(0,0,0));	

	textout_centre_ex(buffer, font, "Turn Left:                Left", 160, 88 +  8, makecol(255,0,0), makecol(0,0,0));	
	textout_centre_ex(buffer, font, "Turn Right:              Right", 160, 88 + 16, makecol(255,0,0), makecol(0,0,0));	
	textout_centre_ex(buffer, font, "Move Forward:               Up", 160, 88 + 24, makecol(255,0,0), makecol(0,0,0));	
	textout_centre_ex(buffer, font, "Move Back:                Down", 160, 88 + 32, makecol(255,0,0), makecol(0,0,0));	
	textout_centre_ex(buffer, font, "Start:                   Space", 160, 88 + 40, makecol(255,0,0), makecol(0,0,0));	
	textout_centre_ex(buffer, font, "Quit:                   Escape", 160, 88 + 48, makecol(255,0,0), makecol(0,0,0));	
	textout_centre_ex(buffer, font, "Push Start to Continue (space)", 160, 88 + 72, makecol(255,0,0), makecol(0,0,0));	

	textout_centre_ex(buffer, font, "Dedicated to Everyone", 160, 176, makecol(255,0,0), makecol(0,0,0));	
	textout_centre_ex(buffer, font, "Especially Vicky", 160, 184, makecol(255,0,0), makecol(0,0,0));	
	textout_centre_ex(buffer, font, "http://www.howqua.net/speedhack", 160, 192, makecol(255,0,0), makecol(0,0,0));	
	
	acquire_screen();
	stretch_blit(buffer, screen, 0, 0, 320, 200, 0, 40, 640, 400);
	release_screen();

	while (!key[KEY_SPACE])
	{
		if(key[KEY_ESC])
		{
			quitting = true;
			break;
		}

	}

	reset_maze(&maze, &player_x, &player_y, &player_direction, &end_x, &end_y);

	BITMAP *end = create_bitmap(300, 200);
	blit((BITMAP *)data[0].dat, end, 0, 0, 0, 0, 300, 200);
	BITMAP *map = create_bitmap(MAZE::width * 2 + 1, MAZE::height * 2 + 1);

	bool inverted = false;
	int poison_amount = 0;
	int maze_number = 0;
	
	int exit_type = 0;

	bool left_pressed = false;	bool right_pressed = false;	bool up_pressed = false;	bool down_pressed = false;

	install_int(poison_flag_handler, 2000);
	install_int(move_count_handler, 20);
	while (!quitting) 
	{
		if (poison_flag)
		{
			poison_amount++;
			if ((rand() % 2) == 0)
			{
				inverted = !inverted;
			}
			

			poison_flag = false;
		}



		clear_to_color(buffer, makecol(255,255,255));

		if (key[KEY_ESC])
			quitting = true;

		render(map, &maze, 0, 0, 2);
		build_corridor(map, player_x, player_y, player_direction);
		draw(buffer, wall, wall_length, end);
		putpixel(map, player_x, player_y, makecol(0,255,0));
		

		pivot_scaled_sprite(buffer, map, 50, 50, player_x, player_y, -player_direction * (64 << 16), 3 << 16);
		
		
		if ((!left_pressed) && (key[KEY_LEFT]))
		{
			move_count = 10;
			player_direction--;
			if (player_direction < 0) player_direction += 4;
			left_pressed = true;
		}
		if (!key[KEY_LEFT]) left_pressed = false;

		if ((!right_pressed) && (key[KEY_RIGHT]))
		{
			move_count = 10;
			player_direction = (player_direction + 1) % 4;
			right_pressed = true;
		}
		if (!key[KEY_RIGHT]) right_pressed = false;

		if ((!up_pressed) && (key[KEY_UP]))
		{
			move_count = 5;
			switch (player_direction)
			{
				case N:
					if (!is_wall(map, player_x, player_y - 1)) player_y--;
					break;
				case E:
					if (!is_wall(map, player_x + 1, player_y)) player_x++;
					break;
				case S:
					if (!is_wall(map, player_x, player_y + 1)) player_y++;
					break;
				case W:
					if (!is_wall(map, player_x - 1, player_y)) player_x--;
					break;
				default:
					allegro_message("m0f0");
					break;
			}

			up_pressed = true;
		}
		if (!key[KEY_UP]) up_pressed = false;


		if ((!down_pressed) && (key[KEY_DOWN]))
		{
			move_count = 5;
			switch (player_direction)
			{
				case N:
					if (!is_wall(map, player_x, player_y + 1)) player_y++;
					break;
				case E:
					if (!is_wall(map, player_x - 1, player_y)) player_x--;
					break;
				case S:
					if (!is_wall(map, player_x, player_y - 1)) player_y--;
					break;
				case W:
					if (!is_wall(map, player_x + 1, player_y)) player_x++;
					break;
				default:
					allegro_message("m0f0");
					break;
			}

			down_pressed = true;
		}
		if (!key[KEY_DOWN]) down_pressed = false;


		if (move_count == 0)
		{
			up_pressed = false;
			left_pressed = false;
			right_pressed = false;
			up_pressed = false;
			down_pressed = false;
		}




		if (inverted) invert_bitmap(buffer);
		poison(buffer, poison_amount);



		if ((player_x == end_x) && (player_y == end_y))
		{
			maze_number++;

			if (!inverted)
			{
				draw_quad(buffer, 20, 66, 20, 92, 300, 92, 300, 66, makecol(0,0,0), makecol(255,0,0));
				textprintf_centre_ex(buffer, font, 160, 72, makecol(255,0,0), makecol(0,0,0), "Level %d Complete", maze_number);
				textout_centre_ex(buffer, font, "Push Start to Continue (Space) ", 160, 80, makecol(255,0,0), makecol(0,0,0));	
			}
			else
			{
				draw_quad(buffer, 20, 66, 20, 92, 300, 92, 300, 66, makecol(255,255,255), makecol(0,255,255));
				textprintf_centre_ex(buffer, font, 160, 72, makecol(0,255,255), makecol(255,255,255), "Level %d Complete", maze_number);
				textout_centre_ex(buffer, font, "Push Start to Continue (Space) ", 160, 80, makecol(0,255,255), makecol(255,255,255));	
			}
			
//			poison(buffer, poison_amount);
//			if (inverted) invert_bitmap(buffer);

			acquire_screen();
			stretch_blit(buffer, screen, 0, 0, 320, 200, 0, 40, 640, 400);
			release_screen();

			while (!key[KEY_SPACE])
			{
				if(key[KEY_ESC])
				{
					quitting = true;
					break;
				}
			}
			reset_maze(&maze, &player_x, &player_y, &player_direction, &end_x, &end_y);

			if (maze_number >= 3)
			{
				exit_type = 1;
				quitting = true;
			}
		}

		if (poison_amount >= 50)
		{
			exit_type = 2;
			quitting = true;
		}

		acquire_screen();
		stretch_blit(buffer, screen, 0, 0, 320, 200, 0, 40, 640, 400);
		release_screen();
	}
	
	if (exit_type == 2)
	{
		clear(buffer);
		
		textout_centre_ex(buffer, font, "The madman has won.", 160, 24, makecol(255,0,0), makecol(0,0,0));	
		textout_centre_ex(buffer, font, "You have died.", 160, 32, makecol(255,0,0), makecol(0,0,0));	
		
		textout_centre_ex(buffer, font, "http://www.howqua.net/speedhack", 160, 192, makecol(255,0,0), makecol(0,0,0));	
		
		acquire_screen();
		stretch_blit(buffer, screen, 0, 0, 320, 200, 0, 40, 640, 400);
		release_screen();
		while (!key[KEY_ESC]);
	}

	if (exit_type == 1)
	{
		clear(buffer);
		
		textout_centre_ex(buffer, font, "You have survived", 160, 24, makecol(255,0,0), makecol(0,0,0));	
		textout_centre_ex(buffer, font, "The madman gives you the antidote,", 160, 32, makecol(255,0,0), makecol(0,0,0));	
		textout_centre_ex(buffer, font, "he then throws you out into the forest.", 160, 40, makecol(255,0,0), makecol(0,0,0));	
		textout_centre_ex(buffer, font, "You hear wolves cry in the distance.", 160, 56, makecol(255,0,0), makecol(0,0,0));	

		textout_centre_ex(buffer, font, "To be continued...", 160, 64, makecol(255,0,0), makecol(0,0,0));	
		
		textout_centre_ex(buffer, font, "Push Quit to Exit (Escape)", 160, 80, makecol(255,0,0), makecol(0,0,0));	

		textout_centre_ex(buffer, font, "http://www.howqua.net/speedhack", 160, 192, makecol(255,0,0), makecol(0,0,0));	
		
		acquire_screen();
		stretch_blit(buffer, screen, 0, 0, 320, 200, 0, 40, 640, 400);
		release_screen();
		while (!key[KEY_ESC]);
	}


	destroy_bitmap(map);	
	destroy_bitmap(end);	
	destroy_bitmap(buffer);	

	return 0;
}
END_OF_MAIN()
