/**
 * Windmill
 */


function makeBladeGeometry(width, length, thik, angle)
{
	var geo = new THREE.BoxGeometry(length, width, thik);
	geo.applyMatrix( new THREE.Matrix4().makeTranslation(-length/2,0,0) );
	var geoCSG = new ThreeBSP(geo);

	var removerDim = length * 2;

	var remover1 = new THREE.BoxGeometry(removerDim,removerDim,removerDim);
	remover1.applyMatrix( new THREE.Matrix4().makeTranslation(-removerDim/2, -removerDim/2, 0) );
	remover1.applyMatrix( new THREE.Matrix4().makeRotationZ(deg2rad(angle)) );

	var remover2 = new THREE.BoxGeometry(removerDim,removerDim,removerDim);
	remover2.applyMatrix( new THREE.Matrix4().makeTranslation(-removerDim/2, removerDim/2, 0) );
	remover2.applyMatrix( new THREE.Matrix4().makeRotationZ(deg2rad(-angle)) );

	geoCSG = geoCSG.subtract( new ThreeBSP(remover1) );
	geoCSG = geoCSG.subtract( new ThreeBSP(remover2) );

	//return remover1;

	return geoCSG.toGeometry();
}


// Lumber
THREE.Lumber = function(width, depth, length, rotX) {
	THREE.Object3D.call(this);
	this.type = 'Lumber';

	this.woodMat = new THREE.MeshLambertMaterial({
		//ambient: 0xADFFB2,
		color: 0x713B00,
		//emissive: 0x099723,
		shading: THREE.FlatShading,
		side: THREE.DoubleSide,
		wireframe: false,
		map: tex.perlintile_low
	});

	// The lumber will stand straight up, from 0,0,0

	this.geo = new THREE.BoxGeometry(width, length, depth);
	this.geo = bevelBoxEdges(this.geo, width/3);
	this.geo.applyMatrix( new THREE.Matrix4().makeTranslation(0, length/2, 0) );
	this.geo.applyMatrix( new THREE.Matrix4().makeRotationX(deg2rad(rotX)) );

	this.geo.computeFaceNormals();
	this.geo.computeVertexNormals();

	this.lumber = new THREE.Mesh(this.geo, this.woodMat);
	this.add(this.lumber);

	this.animate = function(n, s)
	{	
		this.lumber.rotation.set(deg2rad(n*90),0,0);
		this.lumber.visible = (s > 0.00001);
		this.lumber.scale.set(s,s,s);
	}

};
THREE.Lumber.prototype = Object.create(THREE.Object3D.prototype);
THREE.Lumber.prototype.constructor = THREE.Lumber;

// Blade
THREE.Blade = function(length, width, think, angle, tilt) {
	THREE.Object3D.call(this);
	this.type = 'Blade';

/*
	this.woodMat = new THREE.MeshLambertMaterial({
		//ambient: 0xADFFB2,
		color: 0xFFFFFF,
		//emissive: 0x099723,
		shading: THREE.FlatShading,
		side: THREE.DoubleSide,
		wireframe: false,
		map: tex.perlintile_low
	});
*/
	this.woodMat = new THREE.MeshLambertMaterial({
		color: 0x9F9F9F
	});

	var bladeGeo = makeBladeGeometry(width, length, think, angle);
	bladeGeo.applyMatrix( new THREE.Matrix4().makeTranslation(-length/10,0,0) );
	bladeGeo.applyMatrix( new THREE.Matrix4().makeRotationX(deg2rad(tilt)) );

	bladeGeo.computeFaceNormals();
	bladeGeo.computeVertexNormals();

	this.blade = new THREE.Mesh(bladeGeo, this.woodMat);
	this.add(this.blade);

	this.animate = function(n)
	{
		var m = 1-easeOne('easeOutBounce',n);
		this.blade.rotation.set(0,deg2rad(m*90),0);

		var g = segmentTransition(0.0, 0.1, n) + 0.000001;
		this.blade.scale.set(g,g,g);
	}

};
THREE.Blade.prototype = Object.create(THREE.Object3D.prototype);
THREE.Blade.prototype.constructor = THREE.Blade;


// Turbine
THREE.Turbine = function(radius, depth, blades) {
	THREE.Object3D.call(this);
	this.type = 'Turbine';

	this.woodMat = new THREE.MeshLambertMaterial({
		//ambient: 0xADFFB2,
		color: 0xC5C5C5,
		//emissive: 0x099723,
		shading: THREE.FlatShading,
		side: THREE.DoubleSide,
		wireframe: false,
		map: tex.perlintile_low
	});

	this.hubMat = new THREE.MeshLambertMaterial({
		//ambient: 0xADFFB2,
		color: 0xB3895C,
		//emissive: 0x099723,
		shading: THREE.FlatShading,
		side: THREE.DoubleSide,
		wireframe: false,
		map: tex.perlintile_low
	});
	
	this.blades = [];
	for (var i=0; i<blades; i++)
	{
		var bladeAngle = 360*(i*(1/blades));

		this.blades.push( new THREE.Blade(radius, radius, radius/20, 15, 25) );
		this.blades[i].rotation.z = deg2rad(bladeAngle);
		this.add(this.blades[i]);
	}

	this.hubGeo = new THREE.CylinderGeometry(radius/5, radius/5, depth);
	this.hub = new THREE.Mesh(this.hubGeo, this.hubMat);
	this.hub.rotation.set(deg2rad(90),0,0);
	this.add(this.hub);


	this.animate = function(n, s)
	{	
		var bladeN = n;

		for (var i=0; i<this.blades.length; i++)
		{
			this.blades[i].animate(bladeN);
		}
	}

};
THREE.Turbine.prototype = Object.create(THREE.Object3D.prototype);
THREE.Turbine.prototype.constructor = THREE.Turbine;

// IndustrialFan
THREE.IndustrialFan = function(radius, blades) {
	THREE.Object3D.call(this);
	this.type = 'IndustrialFan';

	var ductMat = new THREE.MeshLambertMaterial({
		//ambient: #999999,
		color: 0xA0A09F,
		//emissive: #222222,
		shading: THREE.FlatShading
	});

	var wfMat = new THREE.MeshBasicMaterial(
	{
		color: 0x00ff00,
		wireframe: true
	});
	var wfMat2 = new THREE.MeshBasicMaterial(
	{
		color: 0xff0000,
		wireframe: true
	});

	var ductGeo = new THREE.CylinderGeometry(radius, radius, radius*2, 9, 1);
	//var duct = new THREE.Mesh(ductGeo, wfMat);
	//this.add(duct);

	var ductRemoverGeo = new THREE.CylinderGeometry(radius*0.75, radius*0.75, radius*3, 9, 1);
	var ductBevelGeo = new THREE.CylinderGeometry(radius*0.4, radius*4.4, radius*4, 9, 1);
	ductBevelGeo.applyMatrix( new THREE.Matrix4().makeTranslation(0,-radius*0.5,0) );
	var ductCsg = new ThreeBSP(ductGeo);
	ductCsg = ductCsg.subtract(new ThreeBSP(ductRemoverGeo));
	ductCsg = ductCsg.intersect(new ThreeBSP(ductBevelGeo));

	var ductGeo = ductCsg.toGeometry();
	ductGeo.computeFaceNormals();
	ductGeo.computeVertexNormals();

	var duct = new THREE.Mesh(ductGeo, ductMat);
	duct.rotation.x = deg2rad(90);
	duct.position.z = -radius*0.8;
	this.add(duct);

	var rodGeo = new THREE.CylinderGeometry(radius*0.07, radius*0.07, radius*1.9, 7, 1);
	var rod = new THREE.Mesh(rodGeo, ductMat);
	rod.rotation.x = deg2rad(90);
	rod.position.z = -radius;
	this.add(rod);

	var blackGeo = new THREE.CylinderGeometry(radius*0.8, radius*0.8, radius*0.1, 9, 1);
	var black = new THREE.Mesh(blackGeo, new THREE.MeshBasicMaterial({color:0x000000}));
	black.rotation.x = deg2rad(90);
	black.position.z = -radius*0.2;
	this.add(black);

	this.turbine = new THREE.Turbine(radius*0.6, radius*0.1, blades);
	this.add(this.turbine);

	this.lastTime = 0;

	this.animate = function(n,t)
	{
		var tDiff = t-this.lastTime;
		this.turbine.rotation.z += tDiff*n;
		this.lastTime = t;
	}

};
THREE.IndustrialFan.prototype = Object.create(THREE.Object3D.prototype);
THREE.IndustrialFan.prototype.constructor = THREE.IndustrialFan;



// WindmillHead
THREE.WindmillHead = function(length) {
	THREE.Object3D.call(this);
	this.type = 'WindmillHead';

	this.woodMat = new THREE.MeshLambertMaterial({
		//ambient: 0xADFFB2,
		color: 0x713B00,
		//emissive: 0x099723,
		shading: THREE.FlatShading,
		side: THREE.DoubleSide,
		wireframe: false,
		map: tex.perlintile_low
	});

	this.woodMat2 = new THREE.MeshLambertMaterial({
		//ambient: 0xADFFB2,
		color: 0xB56003,
		//emissive: 0x099723,
		shading: THREE.FlatShading,
		side: THREE.DoubleSide,
		wireframe: false,
		map: tex.perlintile_low
	});

	var width = length/3;

	var mainGeo = new THREE.BoxGeometry(width*0.7, width, length);
	mainGeo = bevelBoxEdges(mainGeo,width*0.2)
	this.main = new THREE.Mesh(mainGeo, this.woodMat);
	this.main.position.y += width/2;
	this.add(this.main);


	var tailLength = length*1.5

	//var tailGeo = new THREE.BoxGeometry(width/5, tailLength, tailLength);

	var tailGeo = makeBladeGeometry(tailLength, tailLength, width/3, 30);


	//tailGeo.applyMatrix( new THREE.Matrix4().makeTranslation(0,0,-tailLength/2) );

	this.tail = new THREE.Mesh(tailGeo, this.woodMat2);
	this.tail.position.set(0,width/2,-length/2*0.25);
	this.tail.rotation.y = deg2rad(-90);
	this.add(this.tail)


	var turbineDepth = length/4;


	this.turbine = new THREE.Turbine(length*1.5, turbineDepth, 10);
	this.turbine.position.z = length/2 + turbineDepth/2;
	this.turbine.position.y = width/2;
	this.add(this.turbine);

	this.lastTime = 0;

	this.animate = function(n, s)
	{	
		var bladesN = segmentTransition(0.0, 0.5, n);
		var spinN = segmentTransition(0.3, 1.1, n);

		this.turbine.animate(bladesN, s);

		var sp = s - this.lastTime;

		sp = sp>0.0000001 ? sp : 0; // would otherwise return something bad... dunno..


		//this.turbine.rotation.set( this.turbine.rotation.x, this.turbine.rotation.y, this.turbine.rotation.z );
		this.turbine.rotation.set( this.turbine.rotation.x, this.turbine.rotation.y, this.turbine.rotation.z - sp*spinN );

		this.lastTime = s;
	}

};
THREE.WindmillHead.prototype = Object.create(THREE.Object3D.prototype);
THREE.WindmillHead.prototype.constructor = THREE.WindmillHead;


THREE.Windmill = function() {
	THREE.Object3D.call(this);
	this.type = 'Windmill';

	this.width = 5.5;


	// == on floats.. nope
	this.nearEnough = function(x, y)
	{
		if (x >= y-0.001 && x <= y+0.001)
			return true;
		return false;
	}

	this.wallMat = new THREE.MeshLambertMaterial({
		//ambient: 0xADFFB2,
		color: 0x9B9763,
		//emissive: 0x099723,
		shading: THREE.FlatShading,
		side: THREE.DoubleSide,
		wireframe: false,
		map: tex.wood_tile
	});

	this.woodMat = new THREE.MeshLambertMaterial({
		//ambient: 0xADFFB2,
		color: 0x713B00,
		//emissive: 0x099723,
		shading: THREE.FlatShading,
		side: THREE.DoubleSide,
		wireframe: false,
		map: tex.perlintile_low
	});

	this.windowMat = new THREE.MeshPhongMaterial({
		//ambient: 0xADFFB2,
		color: 0x30AEBE,
		//emissive: 0x099723,
		shading: THREE.FlatShading,
		side: THREE.DoubleSide,
		wireframe: false
	});

	this.roofMat = new THREE.MeshLambertMaterial({
		//ambient: 0xADFFB2,
		color: 0x402300,
		//emissive: 0x099723,
		shading: THREE.FlatShading,
		side: THREE.DoubleSide,
		wireframe: false,
		map: tex.rooftiles
	});

	this.chimneyMat = new THREE.MeshLambertMaterial({
		//ambient: 0xADFFB2,
		color: 0x402300,
		//emissive: 0x099723,
		shading: THREE.FlatShading,
		side: THREE.DoubleSide,
		wireframe: false,
		map: tex.brick_tile
	});

	this.fundationMat = new THREE.MeshLambertMaterial({
		//ambient: 0xADFFB2,
		//color: 0x402300,
		//emissive: 0x099723,
		shading: THREE.FlatShading,
		side: THREE.DoubleSide,
		wireframe: false,
		map: tex.rock_small_tile
	});

	// because == on floats...
	this.closeEnough = function(x, y)
	{
		if (x >= y-0.001 && x <= y+0.001)
			return true;
		return false;
	}

	this.createFoundation = function(width,height)
	{
		var geo = new THREE.BoxGeometry(width, height*2, width);
		geo = bevelBoxEdges(geo, width/3);
		//geo.applyMatrix( new THREE.Matrix4().makeTranslation(0,0,0) );
		var mesh = new THREE.Mesh(geo, this.fundationMat);
		return mesh;
	}

	// ===============================================================
	// Add stone foundations. one in each corner.

	var foundationWidth = this.width/2.8;
	this.foundationHeight = this.width/5;

	this.foundations = [];

	var foundation = this.createFoundation(foundationWidth, this.foundationHeight*1.2);
	foundation.position.set(this.width/2, 0, this.width/2);
	this.foundations.push(foundation);
	this.add(this.foundations[this.foundations.length-1]);

	var foundation = this.createFoundation(foundationWidth, this.foundationHeight*1.2);
	foundation.position.set(this.width/2, 0, -this.width/2);
	this.foundations.push(foundation);
	this.add(this.foundations[this.foundations.length-1]);

	var foundation = this.createFoundation(foundationWidth, this.foundationHeight*1.2);
	foundation.position.set(-this.width/2, 0, this.width/2);
	this.foundations.push(foundation);
	this.add(this.foundations[this.foundations.length-1]);

	var foundation = this.createFoundation(foundationWidth, this.foundationHeight*1.2);
	foundation.position.set(-this.width/2, 0, -this.width/2);
	this.foundations.push(foundation);
	this.add(this.foundations[this.foundations.length-1]);

	var beamWidth = this.width/8;
	var firstHeight = this.width;

	var fistBeamWidth = beamWidth*1.5;

	this.column1 = new THREE.Lumber(fistBeamWidth, fistBeamWidth, firstHeight*1.1, 20);
	this.column1.position.set(this.width/2, this.foundationHeight, this.width/2);
	this.column1.rotation.y = deg2rad(-135);
	this.add(this.column1);

	this.column2 = new THREE.Lumber(fistBeamWidth, fistBeamWidth, firstHeight*1.1, 20);
	this.column2.position.set(this.width/2, this.foundationHeight, -this.width/2);
	this.column2.rotation.y = deg2rad(-45);
	this.add(this.column2);

	this.column3 = new THREE.Lumber(fistBeamWidth, fistBeamWidth, firstHeight*1.1, 20);
	this.column3.position.set(-this.width/2, this.foundationHeight, this.width/2);
	this.column3.rotation.y = deg2rad(-135+90+180);
	this.add(this.column3);

	this.column4 = new THREE.Lumber(fistBeamWidth, fistBeamWidth, firstHeight*1.1, 20);
	this.column4.position.set(-this.width/2, this.foundationHeight, -this.width/2);
	this.column4.rotation.y = deg2rad(-45+90);
	this.add(this.column4);


	var firstWidth = this.width*0.5;

	this.beam1 = new THREE.Lumber(beamWidth, beamWidth, firstWidth, 90);
	this.beam1.position.set(firstWidth/2, this.foundationHeight + firstHeight, firstWidth/2);
	this.beam1.rotation.y = deg2rad(180);
	this.add(this.beam1);

	this.beam2 = new THREE.Lumber(beamWidth, beamWidth, firstWidth, 90);
	this.beam2.position.set(firstWidth/2, this.foundationHeight + firstHeight, -firstWidth/2);
	this.beam2.rotation.y = deg2rad(180+90);
	this.add(this.beam2);

	this.beam3 = new THREE.Lumber(beamWidth, beamWidth, firstWidth, 90);
	this.beam3.position.set(-firstWidth/2, this.foundationHeight + firstHeight, -firstWidth/2);
	this.beam3.rotation.y = deg2rad(180+90+90);
	this.add(this.beam3);

	this.beam4 = new THREE.Lumber(beamWidth, beamWidth, firstWidth, 90);
	this.beam4.position.set(-firstWidth/2, this.foundationHeight + firstHeight, firstWidth/2);
	this.beam4.rotation.y = deg2rad(180+90+90+90);
	this.add(this.beam4);


	var secondHeight = firstHeight*1.3


	this.secondColumn1 = new THREE.Lumber(beamWidth, beamWidth, secondHeight*1.0, 12);
	this.secondColumn1.position.set(firstWidth/2, this.foundationHeight + firstHeight, firstWidth/2);
	this.secondColumn1.rotation.y = deg2rad(-135);
	this.add(this.secondColumn1);

	this.secondColumn2 = new THREE.Lumber(beamWidth, beamWidth, secondHeight*1.0, 12);
	this.secondColumn2.position.set(firstWidth/2, this.foundationHeight + firstHeight, -firstWidth/2);
	this.secondColumn2.rotation.y = deg2rad(-45);
	this.add(this.secondColumn2);

	this.secondColumn3 = new THREE.Lumber(beamWidth, beamWidth, secondHeight*1.0, 12);
	this.secondColumn3.position.set(-firstWidth/2, this.foundationHeight + firstHeight, firstWidth/2);
	this.secondColumn3.rotation.y = deg2rad(-135+90+180);
	this.add(this.secondColumn3);

	this.secondColumn4 = new THREE.Lumber(beamWidth, beamWidth, secondHeight*1.0, 12);
	this.secondColumn4.position.set(-firstWidth/2, this.foundationHeight + firstHeight, -firstWidth/2);
	this.secondColumn4.rotation.y = deg2rad(-45+90);
	this.add(this.secondColumn4);


	this.rotatorGeo = new THREE.CylinderGeometry(this.width/6, this.width/6, this.width/6);
	this.rotator = new THREE.Mesh(this.rotatorGeo, this.woodMat);
	this.rotator.position.y = this.foundationHeight + firstHeight + secondHeight;
	this.add(this.rotator);

	this.head = new THREE.WindmillHead(this.width);
	this.head.position.y = this.foundationHeight + firstHeight + secondHeight + this.width/12;
	this.add(this.head);


	this.animate = function(n, t)
	{	

		var baseN = segmentTransition(0.0, 0.5, n);
		var headN = segmentTransition(0.5, 1.0, n);

		var foundationN = segmentTransition(0.0, 0.10, baseN);
		foundationN = easeOne('easeOutBack', foundationN);

		this.foundations[0].position.y = -this.foundationHeight*2 + foundationN*this.foundationHeight*2;
		this.foundations[1].position.y = -this.foundationHeight*2 + foundationN*this.foundationHeight*2;
		this.foundations[2].position.y = -this.foundationHeight*2 + foundationN*this.foundationHeight*2;
		this.foundations[3].position.y = -this.foundationHeight*2 + foundationN*this.foundationHeight*2;


		var firstBeamN = segmentTransition(0.0, 0.3, baseN);
		var firstBeamN2 = segmentTransition(0.0, 0.4, firstBeamN);
		var firstBeamE = easeOne('easeOutBounce',firstBeamN);

		this.column1.animate(1-firstBeamE, firstBeamN2);
		this.column2.animate(1-firstBeamE, firstBeamN2);
		this.column3.animate(1-firstBeamE, firstBeamN2);
		this.column4.animate(1-firstBeamE, firstBeamN2);

		var secondBeamN = segmentTransition(0.3, 0.6, baseN);
		var secondBeamN2 = segmentTransition(0.0, 0.3, secondBeamN);
		var secondBeamE = easeOne('easeOutBounce',secondBeamN);

		this.beam1.animate(1-secondBeamE, secondBeamN2);
		this.beam2.animate(1-secondBeamE, secondBeamN2);
		this.beam3.animate(1-secondBeamE, secondBeamN2);
		this.beam4.animate(1-secondBeamE, secondBeamN2);

		var thirdBeamN = segmentTransition(0.6, 1.0, baseN);
		var thirdBeamN2 = segmentTransition(0.0, 0.2, thirdBeamN);
		var thirdBeamE = easeOne('easeOutBounce',thirdBeamN);

		this.secondColumn1.animate(1-thirdBeamE, thirdBeamN2);
		this.secondColumn2.animate(1-thirdBeamE, thirdBeamN2);
		this.secondColumn3.animate(1-thirdBeamE, thirdBeamN2);
		this.secondColumn4.animate(1-thirdBeamE, thirdBeamN2);


		var rotatorN = segmentTransition(0.95,1.0, baseN) + 0.0000001;
		//rotatorN = easeOne('easeOutElastic', rotatorN) + 0.000000000001;
		this.rotator.scale.set(rotatorN, rotatorN, rotatorN);

		var headBodyN = easeOne('easeOutBack',segmentTransition(0.0, 0.1, headN)) + 0.0000001;
		var headTurbineN = segmentTransition(0.1, 1.0, headN);

		this.head.rotation.set(this.head.rotation.x, -0.1+segmentTransition(0.2, 1.0, headN)/4, this.head.rotation.z);

		this.head.visible = (headBodyN > 0.00001);
		this.head.scale.set(headBodyN, headBodyN, headBodyN);

		this.head.animate(headTurbineN, t);

	}

};

THREE.Windmill.prototype = Object.create(THREE.Object3D.prototype);
THREE.Windmill.prototype.constructor = THREE.Windmill;