"use strict";
///////////////////////////////////////////////
//
//  Copyright 2014 David Gross
//  Not for distribution of modification of any kind without explicit written permission!
//
//  Tiles are 3x3 meter chunks of geometry.  They contain a drawable, a series of triangles
//	needed for collision, and helper functions.
//


// Tiles can be rotated, so we create some mats,
//	using mat4s just so we can share the mats between physics calcs, and rendering.
var tile_rot_mats = new Array();
var tile_rot_quats = new Array();
var tile_palette = {};

var __tile_debug_draw = 1; // &1 = draw model, &2 = draw debug

function get_tile_by_name(s){
	if(s in tile_palette){
		return tile_palette[s];
	}
	console.log("Missing tile: ", s);
	return null;
}

var TRI_LEN = 9; // So we can easily switch to a different format in the future.

// Requires an object with the following:
// name: name, tris: [series of TRI_LEN floats], 
function tile(tile_data){
	//console.log(tile_data);
	
	if(tile_rot_mats.length == 0) {
		tile_rot_mats.push(mat4.create());
		tile_rot_mats.push(mat4.create());
		tile_rot_mats.push(mat4.create());
		tile_rot_mats.push(mat4.create());
		
		mat4.rotate(tile_rot_mats[1], tile_rot_mats[1], Math.PI * 0.5, [0, 0, 1]);
		mat4.rotate(tile_rot_mats[2], tile_rot_mats[2], Math.PI * 1.0, [0, 0, 1]);
		mat4.rotate(tile_rot_mats[3], tile_rot_mats[3], Math.PI * -.5, [0, 0, 1]);
		
		tile_rot_quats.push(quat.create());
		tile_rot_quats.push(quat.create());
		tile_rot_quats.push(quat.create());
		tile_rot_quats.push(quat.create());
		
		// Huh, for whatever reason I had to invert these.  Whatev.
		quat.rotateZ(tile_rot_quats[1], tile_rot_quats[1], Math.PI * -.5);
		quat.rotateZ(tile_rot_quats[2], tile_rot_quats[2], Math.PI * 1.0);
		quat.rotateZ(tile_rot_quats[3], tile_rot_quats[3], Math.PI * 0.5);
		
		console.log("created tile rot mats and quats");
	}
	
	
	this.name			= tile_data.name;
	//this.tris			= tile_data.tris;
	this.draw			= null;
	this.debug_draw		= null;
	//this.physic_tris	= new Array(); // We precompute all rotations first, and store 'em.
	this.physic_tris	= tile_data.tris;
	//console.log(this.name, this.physic_tris.length);
	
	if(__tile_debug_draw & 2){
		var data	= new create_blank_PNU_obj;
		//var norms	= new Array();
		//var indices	= new Array();
		//var uvs		= new Array();
		
		for(var a = 0; a < this.physic_tris.length; a += TRI_LEN){
			var norm = [0,0,0];
			var v0 = [this.physic_tris[a+0], this.physic_tris[a+1], this.physic_tris[a+2]];
			var v1 = [this.physic_tris[a+3], this.physic_tris[a+4], this.physic_tris[a+5]];
			var v2 = [this.physic_tris[a+6], this.physic_tris[a+7], this.physic_tris[a+8]];
			norm = triangleNormal(v0, v1, v2, norm);

			for(var b = 0; b < TRI_LEN; b += 3){
				data.data.push(this.physic_tris[a+b+0]);
				data.data.push(this.physic_tris[a+b+1]);
				data.data.push(this.physic_tris[a+b+2]);
				
				data.data.push(norm[0]);
				data.data.push(norm[1]);
				data.data.push(norm[2]);
				
				data.data.push(this.physic_tris[a+b+0] * .5);
				data.data.push(this.physic_tris[a+b+1] * .5);
				
				data.indices.push(data.indices.length);
			}
		}
		data.name = this.name + "_physics";
		//console.log(data);
		this.debug_draw = create_drawable(data, 1);
	}
}


// We assume the drawable exists already.
function tile_from_drawable_data(data){
	var type;
	if(data.normals == 1 && data.color_channels == 0 && data.uv_channels == 1) type = DRAWABLE_PNU;
	if(data.normals == 1 && data.color_channels == 0 && data.uv_channels == 2) type = DRAWABLE_PNUU;
	if(!((type == DRAWABLE_PNU) || (type == DRAWABLE_PNUU))) {console.log("bad data"); return null;}
	
	var w = 3+3+2; //PNU
	if(type == DRAWABLE_PNUU) w += 2;
	
	var tile_data = {};
	tile_data.tris = new Array();
	tile_data.name = data.name;
	
	var a;
	for(a=0; a<data.indices.length; a+=1){
		tile_data.tris.push(data.data[data.indices[a] * w + 0]);
		tile_data.tris.push(data.data[data.indices[a] * w + 1]);
		tile_data.tris.push(data.data[data.indices[a] * w + 2]);
	
	}
	var t = new tile(tile_data);
	t.draw = drawables[data.name];
	tile_palette[t.name] = t;
	return t;
	
}

tile.prototype.render = function(pos,rot){
	if(!this.draw) return;
	if(__tile_debug_draw & 1){
		this.draw.render(pos, tile_rot_quats[rot], [1,1,1]);
	}
	if(__tile_debug_draw & 2){
		//Should be rendered without depth checking at a transparent value.
		this.debug_draw.render(pos, tile_rot_quats[rot], [1,1,1]);
	}
}

// The level should normalize the position and stuff for this function. (pos rotated, and set to -1.5 ... 1.5)
tile.prototype.testpos = function(p){
	//mod of: https://koozdra.wordpress.com/2012/06/27/javascript-is-point-in-triangle/
	//credit: http://www.blackpawn.com/texts/pointinpoly/default.html
	
	var ret = new Array();
	
	var os;
	for(os=0; os<this.physic_tris.length; os+=TRI_LEN){
		var v0 = [this.physic_tris[os + 6]-this.physic_tris[os + 0],this.physic_tris[os + 7]-this.physic_tris[os + 1]];
		var v1 = [this.physic_tris[os + 3]-this.physic_tris[os + 0],this.physic_tris[os + 4]-this.physic_tris[os + 1]];
		var v2 = [p[0]-this.physic_tris[os + 0],p[1]-this.physic_tris[os + 1]];

		var dot00 = (v0[0] * v0[0]) + (v0[1] * v0[1]);
		var dot01 = (v0[0] * v1[0]) + (v0[1] * v1[1]);
		var dot02 = (v0[0] * v2[0]) + (v0[1] * v2[1]);
		var dot11 = (v1[0] * v1[0]) + (v1[1] * v1[1]);
		var dot12 = (v1[0] * v2[0]) + (v1[1] * v2[1]);

		var invDenom = 1 / (dot00 * dot11 - dot01 * dot01);

		var u = (dot11 * dot02 - dot01 * dot12) * invDenom;
		var v = (dot00 * dot12 - dot01 * dot02) * invDenom;
		
		if((u >= 0) && (v >= 0) && (u + v <= 1)){
			ret.push(
					this.physic_tris[os + 8] * u + 
					this.physic_tris[os + 5] * v +
					this.physic_tris[os + 2] * (1 - (u + v)));
		}
	}
	//console.log(p,ret);
	return ret;
}

tile.prototype.del = function(){
	if(this.draw) this.draw.del();
	if(tile_palette[s]) tile_palette[s] = null; // Lazy, will cause issues if tiles share the same name, but that should never be the case.
}


function dist2d(x,y,xx,yy){
	return Math.sqrt(((xx-x)*(xx-x))+((yy-y)*(yy-y)));
}








