var container, camera, renderer, effectcomposer, container, controls, stats, light, music, audigain;


var wWidth = 0;
var wHeight = 0;
var music_started = 0;
var audio_delay = 0;

var final_pass_shader;

var globe, globe_glow;

var buffer1, buffer2, buffer3, buffer4; // full screen buffers

// 22:46 <@NiteLite> noise funksjoner for webgl: https://github.com/ashima/webgl-noise/tree/master/src
// sol-shader: http://alteredqualia.com/three/examples/webgl_shader_fireball.html
// http://blog.thematicmapping.org/2013/09/creating-webgl-earth-with-threejs.html noen har gjort det før.
// Borealis videos:
// http://www.youtube.com/watch?v=NYXwRU2Vrq0

//var texture_dir = 'http://login.lynet.no/~chr/gfx/';
var texture_dir = 'gfx/';
var tex = {};

var syncDevice = new JSRocket.SyncDevice(),

	//Beats per minute of your demo tune
	BPM = 140,

	//The resolution between two beats, four is usually fine,- eight adds a bit more finer control
	ROWS_PER_BEAT = 4,

	//we calculate this now, so we can translate between rows and seconds later on
	ROW_RATE = BPM / 60 * ROWS_PER_BEAT,

	//the current row we're on
	row,

	// Are we live?!
	demoMode = false;


var rocketTracks = {
	"volume": 0,
	"terrain_aurora": 0,
	"terrain_torus": 0,
	"terrain_x": 0,
	"terrain_y": 0,
	"terrain_z": 0,
	"terrain_opacity1": 0,
	"terrain_opacity2": 0,
	"terrain_opacity3": 0,
	"terrain_opacity4": 0,
	"terrain_amp1": 0,
	"terrain_amp2": 0,
	"terrain_amp3": 0,
	"terrain_amp4": 0,
};

var _audio = new Audio();

var shaders = function(){};

var geos = function(){}; // geometries

var meshes = function(){};
var materials = function(){};
var lights = function(){};
var scenes = function(){};


var scene_composer = new scene_composer();

var clock = new THREE.Clock();
var dt = 0.0; // demo-time. clock that starts after loading.

function demo_init()
{
	create_loading_console();

	SHADER_LOADER.load(
		function (data)
		{
			loading_console_write("Shady shaders are shady");

			loading_console_write(" * Glow shader");
			shaders.vertexShader_stars = data.stars.vertex;
			shaders.fragmentShader_stars = data.stars.fragment;

			loading_console_write(" * Glow shader");
			shaders.vertexShader_glow = data.glow.vertex;
			shaders.fragmentShader_glow = data.glow.fragment;

			loading_console_write(" * Planet shader");
			shaders.vertexShader_globe = data.globe.vertex;
			shaders.fragmentShader_globe = data.globe.fragment;

			loading_console_write(" * Cloud shader");
			shaders.vertexShader_globeclouds = data.globeclouds.vertex;
			shaders.fragmentShader_globeclouds = data.globeclouds.fragment;

			loading_console_write(" * Sun shader");
			shaders.vertexShader_sun = data.sun.vertex;
			shaders.fragmentShader_sun = data.sun.fragment;

			loading_console_write(" * Boris shader");
			shaders.vertexShader_aurora = data.aurora.vertex;
			shaders.fragmentShader_aurora = data.aurora.fragment;

			loading_console_write(" * Boris blurshader");
			shaders.vertexShader_aurorablur = data.aurorablur.vertex;
			shaders.fragmentShader_aurorablur = data.aurorablur.fragment;

			loading_console_write(" * Terrain: Aurora shader");
			shaders.vertexShader_terrain_auroraobj = data.terrain_auroraobj.vertex;
			shaders.fragmentShader_terrain_auroraobj = data.terrain_auroraobj.fragment;

			loading_console_write(" * Terrain: Mountain shader");
			shaders.vertexShader_terrain_mountain = data.terrain_mountain.vertex;
			shaders.fragmentShader_terrain_mountain = data.terrain_mountain.fragment;

			shaders.fragmentShader_final_pass = data.final_pass.fragment;
			shaders.fragmentShader_overlay = data.overlay.fragment;

			loading_console_write(" * Star shader");
			//shaders.vertexShader_stars = data.stars.vertex;
			//shaders.fragmentShader_stars = data.stars.fragment;
			
			console.log("loaded shaders");
			

			demo_init2();
		}
	);
}

// load audio
function demo_init2()
{
	window.AudioContext = window.AudioContext || window.webkitAudioContext;
	audiocontext = new AudioContext();

	demo_init3();
}

// The shader loader is non-blocking, so we split the
// loading function in two to get our code executed in the right order.
function demo_init3()
{
	loading_console_write("I have no idea what I'm doing..");
	console.log("demo init stage 2")
	//scene = new THREE.Scene();
	
	$(document).keypress(function(){
		if (event.keyCode == 'm'.charCodeAt())
		{
			_audio.muted = !_audio.muted;
		}
	});

	// ===============================================
	// Set up the WebGL renderer

	var SCREEN_WIDTH = window.innerWidth
	var SCREEN_HEIGHT = window.innerHeight;
	var VIEW_ANGLE = 45;
	var ASPECT = SCREEN_WIDTH/SCREEN_HEIGHT;
	var ASPECT = 16/9;
	var NEAR = 0.1;
	var FAR = 20000;

	renderer = new THREE.WebGLRenderer(
		{
			antialias: true,
			autoClearColor: true,
			alpha: true,
			premultipliedAlpha: false
		}
	);
	renderer.setClearColor(0x000000, 0);
	
	// ===============================================
	// Automatically set the viewport to 16/9 and add borders if needed.
	resize_window();
	window.onresize = function(){
		resize_window();
	};
	THREEx.FullScreen.bindKey({ charCode : 'f'.charCodeAt(0) });

	container = document.getElementById("container");
	container.appendChild(renderer.domElement);


	// ===============================================
	// Add FPS stats

	stats = new Stats();
	stats.domElement.style.position = 'absolute';
	stats.domElement.style.bottom = '0px';
	stats.domElement.style.zIndex = 100;
	container.appendChild( stats.domElement );

	// ===============================================
	// Load the final pass post-processing shader
	load_final_pass_shader();

	effectcomposer = new THREE.EffectComposer(renderer);

	// ===============================================
	// Initialize full screen texture buffers
	buffer1 = new THREE.WebGLRenderTarget( wWidth, wHeight, {
		minFilter: THREE.LinearFilter,
		magFilter: THREE.NearestFilter,
		format: THREE.RGBAFormat
	});

	buffer2 = new THREE.WebGLRenderTarget( wWidth, wHeight, {
		minFilter: THREE.LinearFilter,
		magFilter: THREE.NearestFilter,
		format: THREE.RGBAFormat
	});

	buffer3 = new THREE.WebGLRenderTarget( wWidth, wHeight, {
		minFilter: THREE.LinearFilter,
		magFilter: THREE.NearestFilter,
		format: THREE.RGBAFormat
	});

	buffer4 = new THREE.WebGLRenderTarget( wWidth, wHeight, {
		minFilter: THREE.LinearFilter,
		magFilter: THREE.NearestFilter,
		format: THREE.RGBAFormat
	});



	// ===============================================
	// Load the scenes

	//scenes.globe = new scene_globe();
	//scenes.globe.load();
	//scenes.tunnel = new scene_tunnel();
	//scenes.tunnel.load();
	scenes.terrain = new scene_terrain();
	scenes.terrain.load();

	//scenes.title_screen = new scene_titlescreen();
	//scenes.title_screen.load();

	// ===============================================
	// Define display sequence.
	//load_timeline(); // from timeline.js

	// add(scene objekt, scene funksjon, duration, {transition effects});
	scene_composer.add(scenes.terrain, scenes.terrain.render, 120, {in: ['black', 1], out: ['black', 1],});

/*
	scene_composer.add(scenes.globe, scenes.globe.slow_zoom_to_earth, 17, {in: ['black', 7], out: ['black', 1],});

	scene_composer.add(scenes.globe, scenes.globe.render_test2, 1, {in: ['black', 0.2], out: ['black', 0.2],});
	scene_composer.add(scenes.globe, scenes.globe.zoom_into_earth, 3, {in: ['black', 0.5], out: ['black', 0.2],});
	scene_composer.add(scenes.globe, scenes.globe.zoom_into_earth, 3, {in: ['black', 0.5], out: ['black', 0.5],});
	scene_composer.add(scenes.globe, scenes.globe.zoom_into_earth, 3, {in: ['black', 0.5], out: ['black', 0.5],});
	scene_composer.add(scenes.globe, scenes.globe.render_test2, 1);
	scene_composer.add(scenes.globe, scenes.globe.zoom_into_earth, 3);
*/
	//scene_composer.add(scenes.globe, scenes.globe.render_test2, 5);	
	//scene_composer.add(scenes.globe, scenes.globe.orbit1, 10);
	//scene_composer.add(scenes.globe, scenes.globe.render_test2, 5);	
	//scene_composer.add(scenes.globe, scenes.globe.orbit1, 10);

	//scene_composer.add(scenes.globe, scenes.globe.render_test2, 1);
	//scene_composer.add(scenes.globe, scenes.globe.render_test, 3);
	//scene_composer.add(scenes.globe, scenes.globe.render_test2, 4);
	

	// Prep the composer
	scene_composer.prepare();

	// Prepare to load megatextures into GPU memory
	prepare_texture_preloader();

	// Wait for loading to complete, and start renderloop.
	//renderwait();
	preload_texture();

	prepareSync();
}

function prepareAudio() 
{
	loading_console_write("Loading music");

	_audio.src = 'sfx/epic.ogg';
	_audio.preload = true;
	_audio.muted = true;
	_audio.load();
	_audio.addEventListener('canplay', onAudioReady);
}

function onAudioReady() 
{
	if(demoMode) { 
		render();
		_audio.play();
	} else {
		_audio.pause();
		_audio.currentTime = (row / ROW_RATE);
	}
}

function prepareSync() {
	loading_console_write("Loading timings from rocket...");

	if (demoMode) {
		syncDevice.setConfig({'rocketXML':'cube.rocket'});
		syncDevice.init("demo");
	} else {
		//_syncDevice.setConfig({'socketURL':'ws://192.168.0.100:1338'});
		syncDevice.init();
	}

	syncDevice.on('ready', onSyncReady);
	syncDevice.on('update', onSyncUpdate);
	syncDevice.on('play', onPlay);
	syncDevice.on('pause', onPause);
}

function onSyncReady() {
	for (var key in rocketTracks) {
		if (rocketTracks.hasOwnProperty(key)) {
			rocketTracks[key] = syncDevice.getTrack(key);
		}
	}

	prepareAudio();
}

function onSyncUpdate(newRow){
	//row is only given if you navigate, or change a value on the row in Rocket
	//on interpolation change (hit [i]) no row value is sent, as the current there is the upper row of your block
	if (!isNaN(newRow)) {
		row = newRow;
	}

	//console.log("[onSyncUpdate] time in seconds", row / ROW_RATE);

	//update your view
	render();
}

function onPlay() {
	_audio.currentTime = (row / ROW_RATE);
    _audio.play();
	console.log("[onPlay] time in seconds", row / ROW_RATE);
    render();
}


function onPause(){
	row = _audio.currentTime * ROW_RATE;
	window.cancelAnimationFrame(render, document);
	_audio.pause();
}

function render()
{
	if(_audio.paused === false) {
		//otherwise we may jump into a point in the audio where there's
		//no timeframe, resulting in Rocket setting row 2 and we report
		//row 1 back - thus Rocket spasming out
		row = _audio.currentTime * ROW_RATE;

		// this informs Rocket where we are
		syncDevice.update(row);
	}

	//console.log("Row: " + row);
	demo_time = row / ROW_RATE;

	_audio.volume = rocketTracks.volume.getValue(row);
	//console.log("[render] aurora is now", rocketTracks.terrain_aurora.getValue(row));
	/*
	var td = clock.getDelta();
	demo_time += td;

	if (music_started == 0)
	{
		//audio_delay = demo_time;
		demo_time = 0;
		music.start(0);
		music_started = 1;
	}
	*/

	//audiogain.gain.value = Math.sin(demo_time)*0.5+0.5;

	document.getElementById('demotime').innerHTML = demo_time.toFixed(3);

	// FPS counter
	stats.update();

	// Requests the next frame after 1/60 sec from browser.
	if((demoMode === true)  || (_audio.paused === false))
		window.requestAnimationFrame(render, document);
	else
		window.cancelAnimationFrame(render, document);
	//renderer.render(scene, camera);

	// ===============================================
	// Vise riktig scene til rett tid.
	scene_composer.play(demo_time);

	// ===============================================
	// Playground for debugging scenes

	//scenes.globe.render_test(demo_time);
	//scenes.globe.orbit_test(demo_time);
	//scenes.terrain.render_test(demo_time);
	//scenes.globe.inside_earth(demo_time);
	//scenes.globe.aurora_test(demo_time,0);
	//scenes.globe.descend(demo_time,0);

	//scenes.tunnel.render(demo_time);
}

function renderwait()
{
	console.log("Renderwait...");
	if (loadable_elements>loaded_elements)
	{
		setTimeout(function(){ renderwait() },100);
	} else
	{
		destroy_loading_console();
		render();
	}
}

function resize_window()
{
	// Window is too high
	if (window.innerWidth/window.innerHeight <= 16/9)
	{
		var width = window.innerWidth;
		var height = Math.floor(width/16*9);
		var top = Math.floor((window.innerHeight-height)/2);
		var left = 0;

	// Window is too wide
	} else
	{
		var height = window.innerHeight;
		var width = Math.floor(height/9*16);
		var top = 0;
		var left = Math.floor((window.innerWidth-width)/2);
	}

	document.getElementById('container').style.top = top+'px';
	document.getElementById('container').style.left = left+'px';
	document.getElementById('container').style.width = width+'px';
	document.getElementById('container').style.height = height+'px';

	renderer.setSize(width, height);

	wWidth = width;
	wHeight = height;
}


function morph (x1, x2, factor)
{
	if (x1<x2)
	{
		return (x1+(x2-x1)*factor);
	} else
	{
		return (x1-(x1-x2)*factor);
	}
}