"use strict";
///////////////////////////////////////////////
//
//  Copyright 2014 David Gross
//  Not for distribution of modification of any kind without explicit written permission!
//
//  Level object, contains a 2d array of [tile, rot, height], list of objects and actors. 
//

var tilesize = 3.0; // Each tile is 3.0 meters.

//Helper to make a blank level.
function makeemptylevel(x,y){
	var params = new Object();
	params.tiles = new Array();
	params.size = [x,y];
	
	params.objects = new Array();
	params.actors = new Array();
		
	for(var a=0; a<x*y; a+=1) params.tiles.push([null, 0, 0]);
	
	return params;
}


// Takes a serialized JSON of level.
function level(params){
	glevel = this;
	this.tiles = new Array();
	this.size = params.size;
	
	this.campos = [tilesize * params.size[0] * .5 + .5, tilesize * params.size[1] * .5 + .5];
	
	for(var a=0; a<params.tiles.length; a+=1){
		if(params.tiles[a][0] != null) this.tiles.push([get_tile_by_name(params.tiles[a][0]), params.tiles[a][1], params.tiles[a][2]]);
		else this.tiles.push(params.tiles[a]);
	}
	
	this.drawables = new Array();
	this.actors = new Array();
	this.bullets = new Array();
	
	
	// Do loop for objects
	// Do loop for actors
	// Other params need to be fleshed out.
	
}
level.prototype.postinit = function(){
	console.log("DO ME.");
	return;
	var x;
	for(x=0;x<64;x+=1){
		var a = vec3.create();
		a[0] = Math.random() * this.size[0] * tilesize;
		a[1] = Math.random() * this.size[1] * tilesize;
		var t = new enemy(a, "butts", Math.random() > .5);
		this.actors.push(t);
	}
	for(x=0; x<16; x+=1){
		var a = vec3.create();
		a[0] = (((Math.random() * this.size[0]) | 0)) * tilesize;
		a[1] = (((Math.random() * this.size[1]) | 0)) * tilesize;
		var b = vec3.create();
		var q = (Math.random() * 4) | 0;
		if(q == 0) b[0] = tilesize;
		if(q == 1) b[1] = tilesize;
		if(q == 2) b[0] = -tilesize;
		if(q == 3) b[1] = -tilesize;
		vec3.add(b, b, a);
		var t = new movewall(a, b, .0625, Math.random() > .5);
		this.actors.push(t);
	}
}


// Turns a bunch of tiles.drawables into a large drawable for easy rendering!
var CHUNK_SIZE = 16;
var numtris = 0;
level.prototype.create_level_model = function(os){
	tmpasd = 1;
	//console.log("CREATING LEVEL MODEL");
	var index = 0;
	var d = new create_blank_PNU_obj;
	d.name = "level";
	
	var x;
	var y;
	var i;
	var tiles_tested = 0;
	var ti;
	var v=[0,0,0];
	var n=[0,0,0];
	var u=[0,0];
	var t;
	var a,aa,pnu_len;
	var xx,yy,zz;
	
	var numverts = 0;
	var numind = 0;
	var curvert = 0;
	var curind = 0;
	for(y=os[1]; (y<this.size[1]) && (y<os[1]+CHUNK_SIZE); y+=1){
		for(x=os[0]; (x<this.size[0]) && (x<os[0]+CHUNK_SIZE); x+=1){
			i = this.size[0] * y + x;
			t = 0;
			//for(t=0; t<this.tiles[i].length; t+=3)
			if(this.tiles[i][t+0]){
				numind += this.tiles[i][t+0].draw.indices;
			}
		}
	}
	
	if(numind){
		d.indices[numind-1] = null;
		d.data[(numind-1) * 3] = null;
	}
	
	for(y=os[1]; (y<this.size[1]) && (y<os[1]+CHUNK_SIZE); y+=1){
		for(x=os[0]; (x<this.size[0]) && (x<os[0]+CHUNK_SIZE); x+=1){
			i = this.size[0] * y + x;
			t = 0;
			//for(t=0; t<this.tiles[i].length; t+=3)
			if(this.tiles[i][t+0]){
				tiles_tested++;
				//this.tiles[i][t+0].render([x * tilesize, y * tilesize, this.tiles[i][t+1]], this.tiles[i][t+2]);
				
				ti = this.tiles[i][t+0];
				
				
				// THIS WON'T SUPPORT ROTATION YET.
				xx = tilesize * x;
				yy = tilesize * y;
				zz = this.tiles[i][t+1];
				{

					for(a in ti.draw.indices){
						numtris++;
						aa = ti.draw.indices[a] * 8;

						d.data[curvert++] = ti.draw.data[aa++] + xx;
						d.data[curvert++] = ti.draw.data[aa++] + yy;
						d.data[curvert++] = ti.draw.data[aa++] + zz;
						d.data[curvert++] = ti.draw.data[aa++];
						d.data[curvert++] = ti.draw.data[aa++];
						d.data[curvert++] = ti.draw.data[aa++];
						d.data[curvert++] = ti.draw.data[aa++];
						d.data[curvert++] = ti.draw.data[aa++];

						d.indices[curind++] = d.indices.length;
					}
				}
			}
			i++;
		}
	}
	//console.log("tiles_tested, ", tiles_tested);
	//console.log(d);
	
	if(!d.data.length){
		console.log("NULL drawable.  :~(");
		return null;
	}
	
	d.texture_diffuse = "tiles_test.png";
	
	var draw = create_drawable(d);
	//console.log(draw);
	
	return draw;
	//return draw;
}

var tmpasd = 0;
var render_dist = 20;
//tile_rot_mats
var tmpp = 0;
level.prototype.render = function(){
	
	// Assign cam.
	if(!tmpasd){
		
		var x;
		var y;
		for(x in this.drawables) if(this.drawables[x]) this.drawables[x].clear();
		this.drawables = [];
		var d = new Date();
		for(y=0; y<this.size[1]; y+=CHUNK_SIZE)
			for(x=0; x<this.size[0]; x+=CHUNK_SIZE)
				this.drawables.push(this.create_level_model([x,y]));
		var dd = new Date();
		console.log("GENERATION TOOK: ", (dd.getTime() - d.getTime()) / 1000);
		_debug = (dd.getTime() - d.getTime()) / 1000;
		_debug += ", " + this.drawables.length;
		_debug += ", tris: " + (numtris/3);
	}
	
	var x;
	for(x in this.drawables) if(this.drawables[x]) this.drawables[x].render([0,0,0,0], no_rot, [1,1,1]);
	
	
	for(x in this.actors){
		this.actors[x].render();
	}
	for(x in this.bullets){
		this.bullets[x].render();
	}
	player.render();
	// OLD RENDERER.  PLEASE REDO LATER.
	/*
	var x;
	var y;
	var i = 0;
	var num = 0;
	var badnum = 0;
	for(y=0; y<this.size[1]; y+=1){
		for(x=0; x<this.size[0]; x+=1){
			//console.log(this.tiles[i]);
			var t = 0;
			//for(t=0; t<this.tiles[i].length; t+=3)
			if(this.tiles[i][t+0]){
				if(Math.abs(x * tilesize - this.campos[0]) < render_dist){
					if(Math.abs(y * tilesize - this.campos[1]) < render_dist){
						this.tiles[i][t+0].render([x * tilesize, y * tilesize, this.tiles[i][t+1]], this.tiles[i][t+2]);
						num++;
					}
				}
			} else badnum++;
			i++;
		}
	}/**/
	//console.log("level.render, ", num, ", ", badnum);
}

level.prototype.move = function(start,end,height){
	var sh = this.getz(start[0], start[1]);
	var eh = this.getz(end[0], end[1]);
	
	if(!sh || !eh) return start;
	//console.log(sh, ", ", eh, ", ", eh);
	if(Math.abs(sh[0] - eh[0]) <= height) return end;
	return start;
	// THIS IS SHIT. REPLACE LATER ON.
}

level.prototype.getz = function(x,y){
	var tx = ((x + 1.5) / 3) | 0;
	var ty = ((y + 1.5) / 3) | 0;
	var xx = x - tx * 3;
	var yy = y - ty * 3;
	if(tx < 0 || ty < 0 || tx >= this.size[0] || ty >= this.size[1]) return null; // OOB
	var i = this.size[0] * ty + tx;
	
	if(i < 0 || i >= this.tiles.length) return null; // OOB
	
	
	// Todo:  Make it search more than one tile for a z-pos.
	if(this.tiles[i][0]){
		if(this.tiles[i][2]){
			var t = [xx,yy,0];
			vec3.transformMat4(t,t,tile_rot_mats[this.tiles[i][2]]);
			return this.tiles[i][0].testpos(t);
		}else{
			return this.tiles[i][0].testpos([xx,yy,0]);
		}
	}
	return null;
	
}

//Casts towards something by step, will return false if it goes under the terrain.
level.prototype.raycast = function(start,end,step){
	if(start == end) return true;
	
	
	var dist = dist2d(start[0],start[1],end[0],end[1]);
	dist = Math.ceil((dist * .999) / step) - 1;
	var dir = vec3.clone(end);
	vec3.sub(dir, dir, start);
	
	
	dir[0] /= dist;
	dir[1] /= dist;
	dir[2] /= dist;
	
	
	var p = vec3.clone(start);
	var a;
	for(a=0; a<dist; a+=1){
		vec3.add(p, p, dir);
		var t = this.getz(p[0], p[1]);
		if(t == null){
			return 0;
		}
		if(p[2] < t[0]) {
			return 0;
		}
	}
	
	return 1;
	
}


level.prototype.tick = function(){
	var a;
	player.tick();
	for(a in this.actors){
		if(this.actors[a].tick()){
			this.actors.splice(a, 1);
		}
	}
	//console.log(this.bullets);
	for(a in this.bullets){
		if(this.bullets[a].tick()){
			this.bullets.splice(a, 1);
		}
	}
	
	var x;
	for(x in this.actors){ // Lets push actors away from one another slightly.  SLOW.
		for(a in this.actors){
			var act = this.actors[a];
			if(a == 0) act = player;
			if(a > x || a == 0){ // Don't need to recheck 'em.
				var cs = this.actors[x].size + act.size;
				if(vec3.dist(this.actors[x].pos, act.pos) < cs){
					cs /= 5.0;
					if(cs < .2) cs = .2;
					var v = vec3.clone(act.pos);
					vec3.sub(v, v, this.actors[x].pos);
					vec3.normalize(v, v);
					v[0] *= cs;
					v[1] *= cs;
					v[2] = 0;
					act.move(v);
					v[0] *= -cs;
					v[1] *= -cs;
					this.actors[x].move(v);
				}
			}
		}
	}
	
	
	
	//TODO:  If actor ticks return true, delete them from the array.
}







