var app, max = 150, observe, bezier;

observe = function (element, event, action) {
	this.addEventListener(event, action, false);
}

app = {
	init: function() {
		this.angle = new THREE.Vector3();
		this.velocity = new THREE.Vector3(0.005, 0.005, 0.005);
		this.mice = this.pmice = {x: 0, y: 0};
		
		this.camera = new THREE.Camera(0, 0, 1000);
		this.scene = new THREE.Scene();
		this.renderer = new THREE.CanvasRenderer();
		this.context = this.renderer.domElement.getContext('2d');
		this.resize();
		
		observe(window, 'resize', function(e) {app.resize(e);});
		observe(document, 'mousemove', function(e) {app.mousemove(e);});
		observe(document, 'mousedown', function(e) {app.mousedown(e);});
		observe(document, 'mouseup', function(e) {app.mouseup(e);});
		document.addEventListener('touchstart', function(e) {app.touchstart(e);}, false);
		document.addEventListener('touchmove', function(e) {app.touchmove(e);}, false);
		document.addEventListener('touchend', function(e) {app.touchend(e);}, false);
		document.body.appendChild(this.renderer.domElement);
		
		setInterval(function() {app.draw();}, 1);
	},
	rotate: function(p) {
		var t = p.position.clone(),
			tmp1, tmp2, cos, sin;
		
		cos = Math.cos(this.angle.y);
		sin = Math.sin(this.angle.y);
		tmp1 = t.y * cos - t.z * sin;
		tmp2 = t.y * sin + t.z * cos;
		t.y = tmp1;
		t.z = tmp2;
		
		cos = Math.cos(this.angle.x);
		sin = Math.sin(this.angle.x);
		tmp1 = t.x * cos - t.z * sin;
		tmp2 = t.x * sin + t.z * cos;
		t.x = tmp1;
		t.z = tmp2;
		
		p.position = t;
	},
	update: function() {
		this.angle.addSelf(this.velocity);
		if (Math.abs(this.velocity.x) > 0.005) {
			this.velocity.multiplyScalar(0.99);
		}
		if (this.handle) {
			if (this.mice_changed()) { 
				this.velocity.x = ((this.mice[0] - this.spin[0])*0.0004) % (Math.PI * 2);
				this.velocity.y = ((this.mice[1] - this.spin[1])*0.0004) % (Math.PI * 2); 
			}
		}
		this.renderer.project(this.scene, this.camera);
	},
	draw: function() {
		this.update();
		this.clear();
		this.context.strokeStyle = '6d6e71';
		var f = this.scene.objects[0];
		if (f) {
			this.context.moveTo(f.screen.x, f.screen.y);
			for (var i=1, len=this.scene.objects.length-1; i<len; i++) {
				var p = this.scene.objects[i],
					n = this.scene.objects[i+1];
				
				this.rotate(p);
				this.context.lineTo(n.screen.x, n.screen.y);
			}
			this.context.stroke();
			this.angle.multiplyScalar(0);
		}
	},
	clear: function() {
		this.context.strokeStyle = '111111';
		this.context.fillStyle = '111111';
		this.context.beginPath();
		this.context.rect(-this.size[0]/2-2, -this.size[1]/2-2, this.size[0]+4, this.size[1]+4);
		this.context.fill();
	},
	mousemove: function(e) {
		this.pmice = this.mice || [0, 0];
		this.mice = [e.clientX, e.clientY];
		this.move();
	},
	touchmove: function(e) {
		if (e.touches.length == 1) {
			e.preventDefault();
			this.pmice = this.mice || [0, 0];
			this.mice = [e.touches[0].pageX, e.touches[0].pageY];
			this.move();
		}
	},
	touchstart: function(e) {
		if (e.touches.length == 1) {
			e.preventDefault();
			this.handle = true;
			this.mice = [e.touches[0].pageX, e.touches[0].pageY];
			this.spin = this.mice;
		}
	},
	touchend: function(e) {
		if (e.touches.length == 1) {
			e.preventDefault();
			this.handle = false;
		}
	},
	move: function() {
		if (this.mice_changed()) {
			var p = new THREE.Particle();
			p.position.x = this.mice[0] - this.size[0]/2;
			p.position.y = this.size[1]/2 - this.mice[1];
			p.updateMatrix();
			this.scene.add(p);
		}
		
		var len = this.scene.objects.length;
		if (len > max) {
			this.scene.objects.splice(0, len-max);
		}
	},
	mousedown: function(e) {
		this.handle = true;
		this.spin = this.mice;
	},
	mouseup: function(e) {
		this.handle = false;
	},
	resize: function(e) {
		var body = document.body;
		this.size = [window.innerWidth, window.innerHeight];
		this.renderer.setSize(this.size[0], this.size[1]);
	},
	mice_changed: function() {
		return (Math.abs(this.mice[0] - this.pmice[0]) > 1 &&
			Math.abs(this.mice[1] - this.pmice[1]) > 1);
	}
}

window.addEventListener('load', function() {app.init();}, false);
