/*    Zonic the Hog.  A silly Sonic-like game written for Speedhack 2007
 *    Copyright (c) 2007 Steven Wallace / Chedda Cheeze
 *    email: steven.t.wallace @ gmail. com
 *
 *    This program 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 2 of the License, or
 *    (at your option) any later version.
 *
 *    This program 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, write to the Free Software Foundation, Inc.,
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
 
#include <math.h>
#include <allegro.h>
#include "Level.h"
#include <stdio.h>
#include "Logfile.h"
#include "QuadMap.h"
#include "GlCompat.h"


Level::Level() {
	typemap.reserve(1000);
	heightmap.reserve(1000);
	background = 0;
}



void Level::Save(const char *filename) {
	FILE *f = fopen(filename, "wb");
	if(!f) {
		allegro_message("Error writing to %s", filename);
		return;
	}
	
	
	// First 8 ints: sizes of various things
	int sizes[8] = { heightmap.size(), apples.size(), 0, 0, 0, 0, 0, 0 };
	fwrite(sizes, 8, sizeof(*sizes), f);
	
	// Now save all elements from each size listed
	int i;
	
	// ground data
	for(i=0; i<(int)heightmap.size(); i++) {
		int temp[2] = { heightmap[i], typemap[i] };
		fwrite(temp, 2, sizeof(*temp), f);
	}
	
	// apple data
	list<Apple*>::const_iterator apple_it;
	for(apple_it=apples.begin(); apple_it!=apples.end(); apple_it++) {
		int temp[3] = { (*apple_it)->GetX(), (*apple_it)->GetY(), (*apple_it)->GetType() };
		fwrite(temp, 3, sizeof(*temp), f);
	}
	
	// All other data is nonexistant, so we stop here
	background->Serialize(f);
	fclose(f);
	
	printf("Map saved to %s\n", filename);
}


void Level::Load(const char *filename) {
	printf("Opening level file %s\n", filename);
	FILE *f = fopen(filename, "rb");
	if(!f) {
		allegro_message("Error reading %s", filename);
		//exit(1);
		return;
	}

	// Clear everything in the level first
	printf("Clearing any current data for the level.\n");
	if(!heightmap.empty()) heightmap.clear();
	if(!typemap.empty()) typemap.clear();
	if(!apples.empty()) apples.clear();
	if(background) delete background;
	background = new QuadMap(100000, 100000, 0, 0);

	// First 8 ints: sizes
	printf("Reading sizes...\n");
	int sizes[8];
	fread(sizes, 8, sizeof(*sizes), f);
	
	// Now read the elements from each size listed
	int i;
	
	// ground data
	heightmap.resize(sizes[0]);
	typemap.resize(sizes[0]);
	printf("Reading %d height blocks.\n", sizes[0]);
	for(i=0; i<sizes[0]; i++) {
		int temp[2];
		fread(temp, 2, sizeof(*temp), f);
		heightmap[i] = temp[0];
		typemap[i] = temp[1];
	}
	
	// apple data
	printf("Reading %d apples.\n", sizes[1]);
	for(i=0; i<sizes[1]; i++) {
		if(feof(f)) {
			printf("Unexpected end of file!\n");
		}
		int temp[3];
		fread(temp, 3, sizeof(*temp), f);
		apples.push_back(new Apple(temp[0], temp[1], temp[2]));
	}
	
	// All other data is nonexistant, so we stop here
	background->Deserialize(f);
	fclose(f);
}




void Level::Draw(BITMAP *buffer, int cx, int cy) {
	
	// First draw the checkerboard pattern
	int i, j;
	/*int w = SCREEN_W/256 + 3;
	int h = SCREEN_H/256 + 3;
	int starti = cx/256-1;
	int startj = cy/256-1;
	for(i=starti; i<starti+w; i++) for(j=startj; j<startj+h; j++)
		gl_rectfill(buffer, i*256 - cx, j*256 - cy, (i+1)*256 - cx, (j+1)*256 - cy, ((i+j)&1)?makecol(255,255,255):0);*/
	
	// First draw all the bg stuff
	list<Object*> bg;
	background->GetObjects(&bg, cx, cy, cx + SCREEN_W, cy + SCREEN_H);
	
	list<Object*>::const_iterator it;
	for(it=bg.begin(); it!=bg.end(); it++) {
		(*it)->Draw(buffer, cx, cy);
	}
	
	
	
	static int grass_col[2], ground_col[2], ice_col[3], hay_col[2], wood_col[2], sky_col;
	static bool first=true;
	if(first) {
		first = false;
		grass_col[0] = makecol(0,186,22);
		grass_col[1] = makecol(23,159,12);
		
		ice_col[0] = makecol(57,165,181);
		ice_col[1] = makecol(43,147,224);
		ice_col[2] = makecol(132,233,248);
		
		ground_col[0] = makecol(159,85,12);
		ground_col[1] = makecol(181,117,55);
		
		hay_col[0] = makecol(222,215,10);
		hay_col[1] = makecol(229,161,42);
		
		wood_col[0] = makecol(116,86,34);
		wood_col[1] = makecol(162,118,67);
		
		sky_col = makecol(8, 192, 234);
	}
	
	
	int first_block = MAX(0, cx / BLOCK_W - 5);
	int last_block = MIN((int)heightmap.size()-1, first_block + SCREEN_W / BLOCK_W + 7);
	
	for(i=first_block; i<MIN((int)heightmap.size(), last_block); i++) {
		int x1 = i * BLOCK_W - cx;
		int y1 = heightmap[i] * BLOCK_H - cy;
		int y2 = heightmap[i+1] * BLOCK_H - cy;
		int top_height = BLOCK_W*8;
		int checker_height = BLOCK_W*32;
		int checker_width = 32;
		
		// Draw the top of the ground
		int pts[10] = { x1,	 		y1, 
				x1 + 16, 		y1 - 12,
				x1 + 16 + BLOCK_W - 1, 	y2 - 12, 
				x1 + BLOCK_W - 1,	y2 + top_height + 1,
				x1, 			y1 + top_height + 1
		};
		int col;
		switch(typemap[i]) {
		case 0:	// grass
			col = grass_col[i&1];
			break;
		
		case 1: // ice
			col = ice_col[i&1];
			break;
		
		case 2: // hay
			col = hay_col[i&1];
			break;
		
		case 3: // wood
			col = wood_col[i&1];
			break;
		}
		gl_polygon(buffer, 5, pts, col);
		
		
	
		// Determine how many pixels into the pattern we are
		int start_px = (y1+top_height + cy)%checker_height;
	
		// Draw the first bit of the pattern
		int k, j = y1 + top_height + checker_height - start_px;
		int kstart = ((j+cy)/checker_height)&1;
		int pts2[8] = { x1, 		y1 + top_height, 
				x1 + BLOCK_W, 	y2 + top_height,
				x1 + BLOCK_W,	y1 + top_height + checker_height - start_px,
				x1,		y1 + top_height + checker_height - start_px
		};
		
		switch(typemap[i]) {
		case 1: // ice
			col = ice_col[2];
			break;

		case 0: // grass
		case 2: // hay
		case 3: // wood
			col = ground_col[(((i/checker_width)&1)==0?((kstart+1)&1):(kstart&1))];
			break;
		}
		gl_polygon(buffer, 4, pts2, col);
			
		//gl_rectfill(buffer, x1, y1+top_height, x1 + BLOCK_W, y1+top_height + checker_height - start_px, 
			
			
		
		// Now cycle through and draw the rest
		for(k=kstart; j < SCREEN_H; k++) {
			gl_rectfill(buffer, x1, j, x1 + BLOCK_W, j + checker_height, ground_col[((i/checker_width)&1)==0?(k&1):((k+1)&1)]);
			j += checker_height;
		}
	}
	
	
	
	// Draw all apples
	list<Apple*>::const_iterator ait;
	for(ait=apples.begin(); ait!=apples.end(); ait++) {
		(*ait)->Draw(buffer, cx, cy);
	}
}



void Level::Plot(int x, int y, int type) {
	if(x < 0 || y < 0) return;
		
	
	x /= BLOCK_W;
	y /= BLOCK_H;
	
	if((int)heightmap.size() < x) {
		heightmap.resize(x+1);
		typemap.resize(x+1);
	}
	
	heightmap[x] = y;
	typemap[x] = type;
}



void Level::AddApple(int x, int y, int type) {
	apples.push_back(new Apple(x,y,type));
}


void Level::AddBgItem(int x, int y, int type) {
	Object *o = new Object(x,y,0,type);
	background->Insert(o);
}



void Level::UpdateApples(float dt) {
	// Update all apples
	list<Apple*>::iterator it;
	for(it=apples.begin(); it!=apples.end(); it++) {
		if((*it)->Update(dt)) {
			delete *it;
			apples.erase(it++);
		}
	}
}



void Level::SpawnItem(int type, int x, int y) {
	Apple *a = new Apple(x, y, type);
	a->Activate();
	a->Invalidate();

	float vel = 500 + rand()%1000 / 4.0;
	float angle = (235 + (rand()%360)/5.0) / 180.0 * M_PI;

	a->SetVelocities(vel*cos(angle), vel*sin(angle));
	apples.push_back(a);
}


