require(['Renderer','Skybox','DeltaTimer','makeTextureSphere','local_audio_visualizer'],

function(Renderer,Skybox,DeltaTimer,makeTextureSphere,LocalAudioVisualizer){
	'use strict';

	//map function to be used to map values from leap into proper degrees (0-360)
	function map(value, inputMin, inputMax, outputMin, outputMax){
		var outVal = ((value - inputMin) / (inputMax - inputMin) * (outputMax - outputMin) + outputMin);  
		if(outVal >  outputMax){
			outVal = outputMax;
		}
		if(outVal <  outputMin){
			outVal = outputMin;
		} 
		return outVal;
	}

	$(document).ready(function(){

		var earthSize = {radius: 150, segments: 40, rings: 40},
			earthSphere = makeTextureSphere(_(earthSize).extend({
				map: 'img/earth-bump-lo.jpg',
				bumpMap: 'img/earth-bump-lo.jpg',
				castShadow: true,
				receiveShadow: true,
				opacity: 1
			})),
			cloudSize = {radius: 153, segments: 40, rings: 40},
			cloudSphere = makeTextureSphere(_(cloudSize).extend({
				map: 'img/cloudmap-lo.jpg',
				opacity: 0.35
			})),
			moonSize = {radius: 40, segments: 12, rings: 12},
			moonSphere = makeTextureSphere(_(moonSize).extend({
				map: 'img/moon.jpg',
				bumpMap: 'img/moon.jpg',
				castShadow: true,
				receiveShadow: true,
				opacity: 1
			})),
			// interaction vars
			mouseX = 0, mouseLastX = 0,
			mouseY = 0, mouseLastY = 0,
			accelX = 0, accelY = 0, accelDist = 0, theta = 0, phi = 0.2,
			dragging = false,
			// scene vars
			lightDistance = 4200,
			moonDistance = 4000,//4500,
			cameraDistance = 400,
			cameraNearest = 250,
			cameraFurthest = moonDistance * 2,
			// visualizer
			sampleSize = 5,
			geometryCache = _(earthSphere.geometry.vertices).map(function(vect){
				return {
					x: vect.x,
					y: vect.y,
					z: vect.z
				};
			}),
			tickCount = 0;

		earthSphere.rotation.y = -Math.PI/4;
		cloudSphere.rotation.y = -Math.PI/4;

		Renderer.add(earthSphere,cloudSphere,moonSphere,Skybox);

		Renderer.addLight({x: lightDistance, y: 0, z: lightDistance, castShadow: true, shadowCameraNear: lightDistance});
		Renderer.addAmbientLight({colour: 0x444444});


		// animation
		DeltaTimer.onTick(function(){
			// mouse related calculations
			if(dragging){
				accelX += (mouseLastX - mouseX) / 2500;
				accelY -= (mouseLastY - mouseY) / 2500;
			}
			mouseLastX = mouseX;
			mouseLastY = mouseY;
			tickCount++;

			// objects
			earthSphere.rotation.y += 0.0001;
			cloudSphere.rotation.y += 0.00014;
			moonSphere.position.x = Math.sin(tickCount*0.0001+(Math.PI/2)) * moonDistance;
			moonSphere.position.z = Math.cos(tickCount*0.0001+(Math.PI/2)) * moonDistance;
			moonSphere.rotation.y = earthSphere.rotation.y * 0.1;

			// camera
			theta += (accelX*0.2);
			phi += (accelY*0.2);
			cameraDistance += (accelDist*2);
			if(cameraDistance<cameraNearest){
				cameraDistance = cameraNearest;
			}
			if(cameraDistance>cameraFurthest){
				cameraDistance = cameraFurthest;
			}
			Renderer.setPosition({
				x: Math.sin(theta) * cameraDistance,
				y: Math.cos(phi-(Math.PI/2)) * cameraDistance,
				z: Math.cos(theta) * cameraDistance
			});

			// friction
			accelX *= 0.975;
			accelY *= 0.975;
			accelDist *= 0.975;
		});

		// Leap motion
		var firstValidFrame, lastZ = 300;
		Leap.loop({enableGestures: true}, function(frame) {
			if(frame.valid) {
				if(!firstValidFrame){
					firstValidFrame = frame;	
				}

				var t = firstValidFrame.translation(frame),
					z = -_(frame.fingers).find(function(finger){
						return finger && finger.tipPosition;
					}).tipPosition[2],
					curY = map(t[1], -300, 300, 0, 179),
					rotateX = t[0],
					rotateY = -curY,
					zoom;

				if(!z){
					z = lastZ;
				}else{
					lastZ = z;
				}
				zoom = Math.min(300,Math.max(0, z))/300;
				cameraDistance = Math.min(1500,((1/zoom)*cameraNearest));

				earthSphere.rotation.y = -(rotateX * 0.01) - Math.PI/2;
				cloudSphere.rotation.y = -(rotateX * 0.01) - Math.PI/2;
				earthSphere.rotation.x = -(rotateY+290) * 0.03 + (Math.PI*4);
				cloudSphere.rotation.x = -(rotateY+290) * 0.03 + (Math.PI*4);
			}
		});

		// interaction
		$(document).mousemove(function(e){
			mouseX = e.pageX;
			mouseY = e.pageY;
		}).mousedown(function(e){
			dragging = true;
		}).mouseup(function(e){
			dragging = false;
		}).mousewheel(function(e, delta, deltaX, deltaY){
			accelDist += deltaY;
		});

		function getVertex(radius, segmentsWidth, segmentsHeight, index){
			var phiStart = 0,
				phiLength = Math.PI * 2,
				thetaStart = 0,
				thetaLength = Math.PI,
				y = Math.floor(index / (segmentsWidth+1)),
				x = index - (y*(segmentsWidth+1)),
				u = x / segmentsWidth,
				v = y / segmentsHeight,
				xpos = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ),
				ypos = radius * Math.cos( thetaStart + v * thetaLength ),
				zpos = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
			return {x:xpos,y:ypos,z:zpos, iy: y, ix: x};
		}

		var vis = new LocalAudioVisualizer(document.getElementById('dropandload'), document.getElementById('loadingmessage'), function(byteFreq){
			var vertLen = earthSphere.geometry.vertices.length + 400,
				byteLen = byteFreq.length,
				cVert;

			_(earthSphere.geometry.vertices).each(function(vert,i){
				var byteIndex = Math.floor((i/vertLen)*byteLen),
					scale = byteFreq[byteIndex] / 4,
					scaledVert = getVertex(earthSize.radius + scale, earthSize.segments, earthSize.rings, i),
					cloudVert = getVertex(cloudSize.radius + scale, cloudSize.segments, cloudSize.rings, i);

				vert.x = scaledVert.x;
				vert.y = scaledVert.y;
				vert.z = scaledVert.z;

				cloudSphere.geometry.vertices[i].x = cloudVert.x;
				cloudSphere.geometry.vertices[i].y = cloudVert.y;
				cloudSphere.geometry.vertices[i].z = cloudVert.z;
			});

			earthSphere.geometry.verticesNeedUpdate = true;
			cloudSphere.geometry.verticesNeedUpdate = true;

			cloudSphere.rotation.y += ((earthSphere.rotation.y - cloudSphere.rotation.y)/200);
			// _(byteFreq).reduce(function(memo,n){
				// return memo+n;
			// },0);
		});

		var loadClicked = false;
		$('#loadingmessage').click(function(){
			if(loadClicked){ return; }
			$(this).text('Loading');
			$('#filename').text("Say A-Ha (Tepr Remix)").fadeIn('slow');
			vis.loadUrl('a-ha.mp3');
			loadClicked = true;
		});

		// start
		$('#container').append(Renderer.el);
		Renderer.start();

	});
});