/**
Platform
 */

var globalPlatformGeometry = false;
var globalPlatformObjects = [];

THREE.Platform = function(seed) {

	seed = seed || 1;
	Math.seedrandom(seed)
	//console.log('Seeding platform widht '+seed);

	THREE.Object3D.call(this);


	this.rockbaseWidth = 25;
	this.rockbaseHeight = 25;
	this.bumpFactor = 0.2; // how "bumpy" is the base?

	this.numRocks = 4000;

	/*for (var i=0; i<this.numRocks; i++)
	{

	}*/

	// Keep track of previous rocks to implement somewhat of an overlap avoidance..
	this.rockCoordinates = [];

	this.coordsInsideRockBase = function(coord)
	{
		if (coord.y > 0)
		{
			return false;
		} else if (coord.y < -this.rockbaseHeight)
		{
			return false;
		} else
		{
			// Based on the y coordinate, figure out if the x/z coordinate is within
			//console.log('testing at y '+coord.y);

			var center = new THREE.Vector3(0, coord.y ,0);
			var dist = center.distanceTo(coord);

			//console.log('distance is '+dist);

			var depth = 1-(coord.y/-this.rockbaseHeight);

			//console.log('depth is '+depth);

			var depth = easeOne('easeOutSine',depth);
			var inside = depth*this.rockbaseWidth/2;


			//console.log('inside is ' + inside);

			if (dist < inside)
			{
				return true;
			} else
			{
				return false;
			}

			/*if (coord.x > this.rockbaseWidth/2 || coord.z > this.rockbaseWidth/2)
			{
				return false;
			}
			return true;
			*/
		}
	}

	this.wiggleVertices = function(geo, scale)
	{
		for (var i=0; i<geo.vertices.length; i++)
		{
			geo.vertices[i].x += (Math.random()-0.5*2)*scale;
			geo.vertices[i].y += (Math.random()-0.5*2)*scale;
			geo.vertices[i].z += (Math.random()-0.5*2)*scale;
		}
	}

	this.makeRock = function(size)
	{
		var r = Math.floor(Math.random()*1);

		var sizex = size + (Math.random()-0.5)*2 * 0.7;
		var sizey = size + (Math.random()-0.5)*2 * 0.7;
		var sizez = size + (Math.random()-0.5)*2 * 0.7;

		if (r == 0)
		{
			var geo = new THREE.SphereGeometry(sizex,4,3);
			geo = reduceGeometry(geo, 0.8);
		} else if (r == 1)
		{
			var geo = new THREE.BoxGeometry(sizex,sizey,sizez,1,1,1);
			this.wiggleVertices(geo,0.1);
			var modifier = new THREE.SubdivisionModifier(1);
			modifier.modify(geo);
			geo = reduceGeometry(geo, 0.5);
		}

		var rotx = (Math.random()-0.5)*Math.PI*2;
		var roty = (Math.random()-0.5)*Math.PI*2;
		var rotz = (Math.random()-0.5)*Math.PI*2;

		geo.applyMatrix(new THREE.Matrix4().makeRotationX(rotx).makeRotationY(roty).makeRotationZ(rotz));
		geo.computeVertexNormals();

		return geo;
	}


	this.rockmat = new THREE.ShaderMaterial({
		name: 'platform_rock_material'+seed,
		uniforms: THREE.UniformsUtils.clone(platform_shader.uniforms),
		vertexShader: platform_shader.vertexShader,
		fragmentShader: platform_shader.fragmentShader,
		shading: THREE.FlatShading,
		ambient: 0x999999,
		color: 0x4A2200,
		emissive: 0x6a2323,
		lights: true,
		shadows: true,
		vertexColors: THREE.FaceColors,
		attributes: {
			endPosition: {type: 'v3', value: [] },
			distToCenter: {type: 'f', value: [] }
		}
	});
	this.rockmat.uniforms.lowestPoint.value = new THREE.Vector3(0,-this.rockbaseHeight*(1+this.bumpFactor),0);

	if (globalPlatformGeometry == false)
	{

		globalPlatformGeometry = this.makeRock(1); // Add the first one manually so we have something to merge with.
		globalPlatformObjects.push({ vertices: globalPlatformGeometry.vertices.length+0 });

		for (var i=0; i<this.numRocks; i++)
		{
			var newRock = this.makeRock(1.2);
			globalPlatformGeometry.merge(newRock);
			globalPlatformObjects.push({ vertices: newRock.vertices.length });
		}
	}

	for (var r=0; r<globalPlatformObjects.length; r++)
	{
		var inside = false;

		while (inside == false)
		{
			var x = (Math.random()-0.5)*this.rockbaseWidth*1.5;
			var z = (Math.random()-0.5)*this.rockbaseWidth*1.5;
			var y = Math.random()*-this.rockbaseHeight;

			var coord = new THREE.Vector3(x,y,z);
			inside = this.coordsInsideRockBase(coord)
		}

		coord.x += (Math.random()-0.5)*2 * this.rockbaseWidth/2*this.bumpFactor;
		coord.z += (Math.random()-0.5)*2 * this.rockbaseWidth/2*this.bumpFactor;
		coord.y += Math.random()*-1 * this.rockbaseWidth/2*this.bumpFactor;

		var distToCenter = coord.distanceTo(new THREE.Vector3(0,0,0));

		for (var v=0; v<globalPlatformObjects[r].vertices; v++)
		{
			this.rockmat.attributes.endPosition.value.push(coord);
			this.rockmat.attributes.distToCenter.value.push(distToCenter);
		}
	}

	this.rockmat.attributes.endPosition.needsUpdate = true;
	this.rockmat.attributes.distToCenter.needsUpdate = true;

	this.rockMesh = new THREE.Mesh(globalPlatformGeometry, this.rockmat);
	this.rockMesh.frustumCulled = false;
	this.add(this.rockMesh);

	//console.log(this.rockmat.attributes.endPosition.value[100]);

	this.animate = function(n)
	{
		this.rockmat.uniforms.time.value = n;
	}

};

THREE.Platform.prototype = Object.create(THREE.Object3D.prototype);
THREE.Platform.prototype.constructor = THREE.Poff;


var platform_shader = {

		uniforms: THREE.UniformsUtils.merge( [

			THREE.UniformsLib[ "common" ],
			THREE.UniformsLib[ "fog" ],
			THREE.UniformsLib[ "lights" ],
			THREE.UniformsLib[ "shadowmap" ],

			{
				"ambient"  : { type: "c", value: new THREE.Color( 0xffffff ) },
				"emissive" : { type: "c", value: new THREE.Color( 0x000000 ) },
				"wrapRGB"  : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) },
				'time'     : { type: 'f', value: 0.0 },
				'lowestPoint': { type: 'v3', value: new THREE.Vector3(0,0,0) }
			}

		] ),

		vertexShader: [

			"#define LAMBERT",

			"varying vec3 vLightFront;",
			"uniform float time;",
			"uniform vec3 lowestPoint;",
			"attribute float transAmount;",
			"attribute vec3 endPosition;",
			"attribute float distToCenter;",

			"#ifdef DOUBLE_SIDED",

			"	varying vec3 vLightBack;",

			"#endif",

			THREE.ShaderChunk[ "map_pars_vertex" ],
			THREE.ShaderChunk[ "lightmap_pars_vertex" ],
			THREE.ShaderChunk[ "envmap_pars_vertex" ],
			THREE.ShaderChunk[ "lights_lambert_pars_vertex" ],
			THREE.ShaderChunk[ "color_pars_vertex" ],
			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
			THREE.ShaderChunk[ "skinning_pars_vertex" ],
			THREE.ShaderChunk[ "shadowmap_pars_vertex" ],
			THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ],


			"void main() {",

				THREE.ShaderChunk[ "map_vertex" ],
				THREE.ShaderChunk[ "lightmap_vertex" ],
				THREE.ShaderChunk[ "color_vertex" ],

				THREE.ShaderChunk[ "morphnormal_vertex" ],
				THREE.ShaderChunk[ "skinbase_vertex" ],
				THREE.ShaderChunk[ "skinnormal_vertex" ],
				THREE.ShaderChunk[ "defaultnormal_vertex" ],

				THREE.ShaderChunk[ "morphtarget_vertex" ],
				THREE.ShaderChunk[ "skinning_vertex" ],
				THREE.ShaderChunk[ "default_vertex" ],
				THREE.ShaderChunk[ "logdepthbuf_vertex" ],

				THREE.ShaderChunk[ "worldpos_vertex" ],
				THREE.ShaderChunk[ "envmap_vertex" ],
				THREE.ShaderChunk[ "lights_lambert_vertex" ],
				THREE.ShaderChunk[ "shadowmap_vertex" ],

				//"vec3 pos = position;",

				THREE.ShaderChunk[ "platform_vertex_main" ],

				//"pos.y = pos.y + time*transAmount;",
				//"pos = pos + (endPosition*time);",

				//"gl_Position = projectionMatrix * modelViewMatrix * pos4;",

			"}"

		].join("\n"),

		fragmentShader: [

			"uniform float opacity;",

			"varying vec3 vLightFront;",

			"#ifdef DOUBLE_SIDED",

			"	varying vec3 vLightBack;",

			"#endif",

			THREE.ShaderChunk[ "color_pars_fragment" ],
			THREE.ShaderChunk[ "map_pars_fragment" ],
			THREE.ShaderChunk[ "alphamap_pars_fragment" ],
			THREE.ShaderChunk[ "lightmap_pars_fragment" ],
			THREE.ShaderChunk[ "envmap_pars_fragment" ],
			THREE.ShaderChunk[ "fog_pars_fragment" ],
			THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
			THREE.ShaderChunk[ "specularmap_pars_fragment" ],
			THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ],

			"void main() {",

			"	gl_FragColor = vec4( vec3( 1.0 ), opacity );",

				THREE.ShaderChunk[ "logdepthbuf_fragment" ],
				THREE.ShaderChunk[ "map_fragment" ],
				THREE.ShaderChunk[ "alphamap_fragment" ],
				THREE.ShaderChunk[ "alphatest_fragment" ],
				THREE.ShaderChunk[ "specularmap_fragment" ],

			"	#ifdef DOUBLE_SIDED",

					//"float isFront = float( gl_FrontFacing );",
					//"gl_FragColor.xyz *= isFront * vLightFront + ( 1.0 - isFront ) * vLightBack;",

			"		if ( gl_FrontFacing )",
			"			gl_FragColor.xyz *= vLightFront;",
			"		else",
			"			gl_FragColor.xyz *= vLightBack;",

			"	#else",

			"		gl_FragColor.xyz *= vLightFront;",

			"	#endif",

				//THREE.ShaderChunk[ "redcolor" ],

				THREE.ShaderChunk[ "lightmap_fragment" ],
				THREE.ShaderChunk[ "color_fragment" ],
				THREE.ShaderChunk[ "envmap_fragment" ],
				THREE.ShaderChunk[ "shadowmap_fragment" ],

				THREE.ShaderChunk[ "linear_to_gamma_fragment" ],

				THREE.ShaderChunk[ "fog_fragment" ],
				

			"}"

		].join("\n")

};