if (!Detector.webgl)
{
	Detector.addGetWebGLMessage();
	document.getElementById('container').innerHTML = "";
}

var width = window.innerWidth, height = window.innerHeight, halfWidth = width/2, halfHeight = height/2, lastTime;
var WORLD_WIDTH = 128, WORLD_HEIGHT = 128;
var camera, light, scene, renderer;
var planeMesh, planeGeometry, cubeMesh, cubeVertex = [], particleSystem;
var loader, animator = new Animator();
var planeTexture = THREE.ImageUtils.loadTexture('textures/plane.png');
var particleTexture = THREE.ImageUtils.loadTexture('textures/particle_round.png');
var lookLock = true;

//helpers
function deg(n) { return n * 180/Math.PI; };
function rad(n) { return n * Math.PI/180; };
function fadeTo(from, to, step) { return (((to-from > 0) ? to-from : from-to) < .1) ? to : from + (to - from) / (step ? step : 50); }

function Animator()
{
	var animations = [];

	this.addAnimation = function(animation)
	{
		animations.push(animation);
	};

	this.render = function(time)
	{
		for(var i=0, l=animations.length; i<l; i++)
		{
			animations[i].render(time);
		}
	};
}

function Animation(aFunction, start, stop)
{
	var initialized, animateFunction = aFunction, startAt, stopAt;

	this.setTime = function(start, stop) { startAt = start || 0, stopAt = stop || -1; };
	this.init = function() {};
	this.set = function(func) { animateFunction = func; };

	this.render = function(time)
	{
		if(startAt <= time && (stopAt < 0 || time <= stopAt)) 
		{ 
			if(!initialized) { initialized = true; this.init(); }
			animateFunction(time);
		}
	}

	this.setTime(start, stop);
}

function init()
{
	camera = new THREE.PerspectiveCamera(60, width/height, 1, 10000);
	camera.position.set(0, 180, 9000);

	scene = new THREE.Scene();
	scene.fog = new THREE.FogExp2(0x000000, 0.0009);

	renderer = new THREE.WebGLRenderer({clearColor:0x000000, clearAlpha:1/*, antialias: true*/});
	renderer.setSize(width, height);

	light = new THREE.DirectionalLight(0xffffff);
	light.position = camera.position.clone();
	scene.add(light);

	// PLANE
	planeGeometry = new THREE.PlaneGeometry(10000, 10000, WORLD_WIDTH-1, WORLD_HEIGHT-1);
	planeGeometry.dynamic = true;

	planeGeometry.computeFaceNormals();
	planeGeometry.computeVertexNormals();

	//flacher untergrund
	for(var i=0, l=planeGeometry.vertices.length; i<l; i++)
	{
		planeGeometry.vertices[i].position.z = 0;
	}

	planeTexture.wrapS = planeTexture.wrapT = THREE.RepeatWrapping;
	planeTexture.repeat.set(16, 16);

	var planeMaterial = new THREE.MeshBasicMaterial({color:0x888888, map:planeTexture, reflectivity:false});

	planeMesh = new THREE.Mesh(planeGeometry, planeMaterial);
	planeMesh.rotation.x = rad(-90);
	scene.add(planeMesh);
	// PLANE END

	// PARTICLES
	var particlesGeometry = new THREE.Geometry();
	var vector, particlesMaterial;

	for(var i=0, l=1000; i<l; i++)
	{
		vector = new THREE.Vector3(Math.random()*3000-1500, Math.random()*3000-1500, Math.random()*3000-1500);
		particlesGeometry.vertices.push(new THREE.Vertex(vector));
	}

	particlesMaterial = new THREE.ParticleBasicMaterial({size:2, color:0xffffff, map:particleTexture, blending:THREE.AdditiveBlending, depthTest:false, transparent:true});
	particleSystem = new THREE.ParticleSystem(particlesGeometry, particlesMaterial);
	scene.add(particleSystem);
	// PARTICLES END

	var container = document.getElementById('screen');
	container.innerHTML = "";
	container.appendChild(renderer.domElement);

	// ROB1N
	loader = new THREE.JSONLoader();
	loader.load({model:'models/rob1n.js', callback:function(geometry)
	{
		cubeMesh = new THREE.ParticleSystem(geometry, new THREE.ParticleBasicMaterial({size:4, color:0xff0000, map:particleTexture, blending:THREE.AdditiveBlending, depthTest:false, transparent:true}));
		cubeMesh.scale.x = cubeMesh.scale.y = cubeMesh.scale.z = 70.0;
		cubeMesh.rotation.x = rad(90);
		for(var i=0, l=geometry.vertices.length; i<l; i++)
		{
			var p = geometry.vertices[i].position;
			cubeVertex[i] = new THREE.Vertex(p.clone());
			p.x = Math.random()*32-16;
			p.y = Math.random()*32-16;
			p.z = Math.random()*32-16;
		}
		scene.add(cubeMesh);

		setAnimations();
		animate();
	}});
	// ROB1N END

	//setAnimations();
}

function setAnimations()
{
	var waveSize = 0, sinWave;
	var randomPosition = [];
	for(var i=0, l=cubeVertex.length; i<l; i++)
	{
		randomPosition[i] = [Math.random()*600-300, Math.random()*600-300, Math.random()*600-300];
	}
	
	animator.addAnimation(new Animation(function(time)
	{
		particleSystem.rotation.x += 0.0002;
		particleSystem.rotation.y += 0.0003;

		if(lookLock) { camera.lookAt(cubeMesh.position); }
	}, 0));

	animator.addAnimation(new Animation(function(time)
	{
		camera.position.z = fadeTo(camera.position.z, 200, 140);
	}, 0, 1));

	animator.addAnimation(new Animation(function(time)
	{
		camera.position.x = fadeTo(camera.position.x, Math.sin(time*4) * 900);
		camera.position.z = fadeTo(camera.position.z, Math.cos(time*3.9) * 900);
	}, 1, 4));

	animator.addAnimation(new Animation(function(time)
	{
		camera.position.x = fadeTo(camera.position.x, Math.cos(time) * 900, 70);
		camera.position.z = fadeTo(camera.position.z, Math.sin(time/2) * 800, 70);
	}, 4));

	//init rob1n transformation
	var startTime = 1, lifeStart, lifeEnd, anim, cv = cubeMesh.geometry.vertices, cl = cv.length;
	for(var i=0, l=cl; i<l; i++)
	{
		(function addAni(i)
		{
			lifeStart = startTime+(i+1)/300, lifeEnd = lifeStart+1;
			animator.addAnimation(new Animation(function(time)
			{
				var fadeSpeed = Math.random()*60+10;
				cv[i].position.x = fadeTo(cv[i].position.x, cubeVertex[i].position.x, fadeSpeed);
				cv[i].position.y = fadeTo(cv[i].position.y, cubeVertex[i].position.y, fadeSpeed);
				cv[i].position.z = fadeTo(cv[i].position.z, cubeVertex[i].position.z, fadeSpeed);
				cubeMesh.geometry.__dirtyVertices = true;
			}, lifeStart, lifeEnd));
		})(i);
	}

	//start wave
	animator.addAnimation(new Animation(function(time)
	{
		//camera.position.y += .2;
		waveSize = fadeTo(waveSize, 30);

		for(var i=0, l=planeMesh.geometry.vertices.length; i<l; i++)
		{
			sinWave = waveSize * Math.sin(i/5 + (time*90+i)/7);
			planeMesh.geometry.vertices[i].position.z = sinWave;
		}

		/*for(var i=0, l=cubeMesh.geometry.vertices.length-1; i<l; i++)
		{
			cubeMesh.geometry.vertices[i].position.z = sinWave;
		}

		cubeMesh.geometry.__dirtyVertices = true;*/
		planeMesh.geometry.__dirtyVertices = true;
	}, 5, 8));

	//stop wave
	animator.addAnimation(new Animation(function(time)
	{
		if(waveSize !== 0) { waveSize = fadeTo(waveSize, 0); }

		for(var i=0, l=planeMesh.geometry.vertices.length; i<l; i++)
		{
			planeMesh.geometry.vertices[i].position.z = waveSize * Math.sin(i/5 + (time*90+i)/7);
		}
		planeMesh.geometry.__dirtyVertices = true;
	}, 6.9, 8));

	//dropping dots
	var startTime = 4, lifeStart, lifeEnd, anim;
	for(var i=0, l=cubeMesh.geometry.vertices.length; i<l; i++)
	{
		(function addAni(i)
		{
			lifeStart = startTime+(i+1)/600, lifeEnd = lifeStart+2;
			animator.addAnimation(new Animation(function(time)
			{
				//camera.position.y += .0008;

				cubeMesh.geometry.vertices[i].position.z += 1*cubeMesh.geometry.vertices[i].position.z/10;
				cubeMesh.geometry.__dirtyVertices = true;

				//verfolge den letzten partikel
				/*if(i==l-1)
				{
					lookLock = false;
					camera.lookAt(cubeMesh.geometry.vertices[i]);
					camera.position.z = fadeTo(camera.position.z, cubeMesh.geometry.vertices[i].position.z + 10);
				}*/
			}, lifeStart, lifeEnd));
		})(i);
	}

	//transform to rob1n formation
	animator.addAnimation(new Animation(function(time)
	{
		var cv = cubeMesh.geometry.vertices, cl = cv.length;

		for(var i=0; i<cl; i++)
		{
			cv[i].position.x = fadeTo(cv[i].position.x, cubeVertex[i].position.x, Math.random()*50+10);
			cv[i].position.y = fadeTo(cv[i].position.y, cubeVertex[i].position.y, Math.random()*50+10);
			cv[i].position.z = fadeTo(cv[i].position.z, cubeVertex[i].position.z, Math.random()*50+10);
		}
		cubeMesh.geometry.__dirtyVertices = true;

		//camera.position.y -= .01;
	}, 11, 13));
}

function animate()
{
	requestAnimationFrame(animate);
	render();
}

function render()
{
	var t = new Date().getTime()*0.0001, timer;
	lastTime = lastTime || t;
	timer = (t - lastTime);

	animator.render(timer);

	renderer.render(scene, camera);
}

init();
