'use strict';

THREE.Flame = function (options) {

	options = options || {};

	options.skew = typeof(options.skew) !== "undefined" ? options.skew : new THREE.Vector3(0, 0, 0);
	options.withLight = typeof(options.withLight) !== "undefined" ? options.withLight : false;
	options.seed = typeof(options.seed) !== "undefined" ? options.seed : 100;
	options.wiggle = typeof(options.wiggle) !== "undefined" ? options.wiggle : 5;

	THREE.Object3D.call( this );
	this.type = 'Flame';

	var points = [];
	var y = 0, 
		width = 4, 
		height1 = 5,
		height2 = 15,
		s1 = 3,
		s2 = 7;

	var segmentHeight1 = height1 / s1;
	var segmentHeight2 = height2 / s2;
	var currentHeight = 0;

	Math.seedrandom(options.seed);

	for ( var i = 0; i < s1; i++ ) {
		points.push( new THREE.Vector3( easeOne('easeOutExpo', (i / s1)) * width, 0, currentHeight ));
		currentHeight += segmentHeight1;
	}
	for ( var i = 0; i < s2; i++ ) {
		points.push( new THREE.Vector3( (1 - easeOne('easeInOutQuad', (i / s2))) * width, 0, currentHeight ) );
		currentHeight += segmentHeight2;
	}
	points.push( new THREE.Vector3( 0, 0, currentHeight ) );

	points[0].z = 1;

	var geom = new THREE.LatheGeometry(points, 10);

	var twistAxis = new THREE.Vector3( 0, 0, 1 );
	var wrinkle = 1;

	for(var i = 0; i < geom.vertices.length; i++) {
		var v = geom.vertices[i];
		var angle = deg2rad(2 * v.z);
		
		geom.vertices[i] = v.applyAxisAngle(twistAxis, angle);
		if(v.z < 15) {
			geom.vertices[i].x += (Math.random() * wrinkle) - (wrinkle / 2);
			geom.vertices[i].y += (Math.random() * wrinkle) - (wrinkle / 2);	
		}
	}

	geom.computeFaceNormals();
	geom.computeVertexNormals();

	var flameShaderDetails = {
		"uniforms": THREE.UniformsUtils.merge([
			{ 
				"c1": 	 { type: "c", value: new THREE.Color("#C66300") },
				"c2": 	 { type: "c", value: new THREE.Color("#F4D93E") },			
				"t": 	 { type: "f", value: 0.0 },
				"skew":  { type: "v3", value: new THREE.Vector3(0, 0, 0) },
				"wiggle":{ type: "f", value: 10 }
			}
		]),
		"attributes": {
	    	"fNormal": { type: "v3", value: [], boundTo: 'faces' }
		},
		"vertexShader": THREE.ShaderChunk['flameVertex'],
		"fragmentShader": THREE.ShaderChunk['flameFragment']
	};

	this.matFlame = new THREE.ShaderMaterial({ 
		uniforms: THREE.UniformsUtils.clone(flameShaderDetails.uniforms),
		vertexShader: flameShaderDetails.vertexShader,
		fragmentShader: flameShaderDetails.fragmentShader,
		attributes: flameShaderDetails.attributes
	});

	this.matFlame.attributes.fNormal.value = new Array(geom.faces.length);
	for (var i=0; i < geom.faces.length; i++) {
    	this.matFlame.attributes.fNormal.value[i] = geom.faces[i].normal;
	}

	this.matFlame.uniforms.skew.value.copy(options.skew);
	this.matFlame.uniforms.wiggle.value = options.wiggle;

	this.mesh = new THREE.Mesh( geom, this.matFlame );
	this.mesh.rotation.x = deg2rad(-90);
	this.mesh.position.y = -1;
	this.add(this.mesh);

	if(options.withLight) {
		this.lightSource = new THREE.PointLight( 0xF4D93E, 1, 30 );
		this.add(this.lightSource);	
	}
};

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

THREE.Flame.prototype.animate = function(t) {
	this.matFlame.uniforms['t'].value = t;
}