 /*
 /        instaFAIL
 /
 / Code: the_JinX / deFEEST
 /  Music: Cinder / deFEEST
*/

// screen size variables
var SCREEN_WIDTH = window.innerWidth,
    SCREEN_HEIGHT = window.innerHeight,
    HALF_WIDTH = window.innerWidth / 2,
    HALF_HEIGHT = window.innerHeight / 2,
    // canvas element and 2D context
    canvas = document.createElement( 'canvas' ),
    context = canvas.getContext( '2d' ),
    
    // to convert from degrees to radians, multiply by this number!
    TO_RADIANS = Math.PI / 180, 
    alpha = 0.4,

    // fps stuff, could be removed
    lastTime,
    //curTime,
	// more gayness
	offset = 0,
	horizontal = 0,
    // rainbow \o/          
    color, hue = [
    [255,   0,   0 ], // 0, Red,       0°
    [255, 255,   0 ], // 1, Yellow,   60°
    [  0, 255,   0 ], // 2, Green,   120°
    [  0, 255, 255 ], // 3, Cyan,    180°
    [  0,   0, 255 ], // 4, Blue,    240°
    [255,   0, 255 ], // 5, Magenta, 300°
    [255,   0,   0]], // 6, Red,     360°
    gradient,
    
     // blob objects
    red = new blob(128),
    green = new blob(128),
    blue = new blob(128);
	outline = new blob(32);
	deFEEST = new blob(2);
	meerFEEST = new blob(16);

// CANVAS SET UP
container = document.createElement( 'div' );
document.body.appendChild(container);

container.appendChild(canvas); 
canvas.width = SCREEN_WIDTH; 
canvas.height = SCREEN_HEIGHT;

// move origin into the centre of the screen
context.translate(HALF_WIDTH, HALF_HEIGHT);

// Create the linear gradient: sx, sy, dx, dy.
// That's the start (x,y) coordinates, followed by the destination (x,y).
gradient = context.createLinearGradient(-HALF_WIDTH+100, -HALF_HEIGHT+100, HALF_WIDTH+100, HALF_HEIGHT+100);
for (var i = 0; i <= 6; i++) {
  color = 'rgb(' + hue[i][0] + ', ' + hue[i][1] + ', ' + hue[i][2] + ')';
  gradient.addColorStop(i * 1/6, color);
}

// load the particle images
red.img.src = 'img/red.png'; 
green.img.src = 'img/green.png';
blue.img.src = 'img/blue.png';
outline.img.src = 'img/outline.png';
meerFEEST.img.src = deFEEST.img.src = 'img/deFEEST.png';

context.textBaseline = 'top';

// call the loop function at aprox 50fps (and hope we manage)
setInterval(loop, 20);

// change movement between 5 and 20 seconds 
setInterval(function(){alpha = randomRange(0.2, 0.8);}, randomRange(5000, 20000)); // blur factor
//setInterval(function(){red.fov = randomRange(90, 180);}, randomRange(5000, 20000));
//setInterval(function(){green.fov = randomRange(90, 180);}, randomRange(5000, 20000));
//setInterval(function(){blue.fov = randomRange(90, 180);}, randomRange(5000, 20000));
setInterval(function(){red.sX = randomRange(-5, 5);}, randomRange(5000, 20000));
setInterval(function(){red.sY = randomRange(-5, 5);}, randomRange(5000, 20000));
setInterval(function(){green.sX = randomRange(-5, 5);}, randomRange(5000, 20000)); 
setInterval(function(){green.sY = randomRange(-5, 5);}, randomRange(5000, 20000));
setInterval(function(){blue.sX = randomRange(-5, 5);}, randomRange(5000, 20000));
setInterval(function(){blue.sY = randomRange(-5, 5);}, randomRange(5000, 20000));

var audioElement = document.createElement('audio');
var sourceOgg = document.createElement('source'); 
sourceOgg.setAttribute('src', 'snd/instafail.ogg');
audioElement.appendChild(sourceOgg);
var sourceMp3 = document.createElement('source'); 
sourceMp3.setAttribute('src', 'snd/instafail.mp3');
audioElement.appendChild(sourceMp3);
audioElement.load()
audioElement.play()


// the main loop function 
function loop() {
	var time = audioElement.currentTime; 
	// clear the canvas
	context.globalCompositeOperation = 'source-over';
	context.fillStyle="rgb(0,0,0)";
	context.globalAlpha = alpha;
	context.fillRect(-HALF_WIDTH,-HALF_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT);

	// set "additive blending".             
	context.globalCompositeOperation = 'lighter';

	if (time > 1 && time < 101) {
		red.render(context);
	}
	if (time > 4.7 && time < 120) {
		green.render(context);
	}
	if (time > 6 && time < 135) {
		blue.render(context);
	}  
	if ((time > 56 && time < 90)||(time > 120 && time < 130)) {
		outline.render(context);
	}
	if ((time > 30 && time < 60)||(time > 95 && time < 125)) {
		
		deFEEST.render(context);
	}
	if (time>101 && time < 120) {
		meerFEEST.render(context);
	}

	context.globalCompositeOperation = 'source-over';
	// Big rainbow text
	context.fillStyle=gradient;
	context.font = 'bold 80px sans-serif';
	context.fillText('instaFAIL @ '+1/(time-lastTime), -200, HALF_HEIGHT-100, 0);

	// JinX
	context.font = 'bold 20px sans-serif';
	var txt = []; 
	if (time < 7) {
		txt[0] = 'deFEEST                                     instaFAIL';
		txt[1] = '                     outline 2011';
	} else if (time < 27) {
		txt[0] = 'deFEEST at Outline 2011';
		txt[1] = txt[2] = txt[3] = '';
		txt[4] = 'First ever deFEEST demo production.';
	} else if (time < 40) {
		//insert defeest logo
		txt[0] = 'Music: Cinder      Code: JinX';	
	} else if (time < 50) {
		txt[0] = 'We brought our own food, code and music . . ';
		txt[1] = 'Ableton, some JavaScript and a tiny bit of html.';
		txt[2] = 'I learned I suck at Javascript without internets.    (JinX)';
	} else if (time < 60) {
		txt[0] = 'Since I\'m no designer I\'ve left all the decision making up to random()';
		txt[1] = txt[2] = txt[3] = '';
		txt[4] = '      \\o/';
		offset = offset + 0.04;
		horizontal = -100;
	} else if (time < 70) {
		offset = horizontal = 0;
		txt[0] = 'Apologies:';
		txt[1] = '';
		txt[2] = 'Sorry about the exploding bbq';
		txt[3] = 'JinX for snoring in the non snoring area (only the first night though)';
		txt[4] = 'The thing with the children we are not supposed to talk about';
		txt[5] = 'Missing socks (how else am I supposed to brew Belgian beer?)';
		txt[6] = 'The hamster in the bathroom (tasted good on bbq)';
		txt[7] = 'Yes, that was that smell!';
		txt[8] = '';
		txt[9] = 'Apologies also for this production . .';  
	} else if (time < 80) {
		txt = ['WOB WOB W0B WOB WOB WoB WOB WOB WOB WOB WOB WOB W0B WOB WOB WOB WoB WOB WOB W0B WOB WOB WoB WOB WOB WOB WOB', '', '', '', '',
			'                                         greets to @brenno'];
		offset = offset + 0.1;
		horizontal = 100;
	} else if (time < 121) {
		horizontal = offset = 0;
		txt = ['yourMom = "cheap"; // oh wait I wasn\'t declaring variables here!','','','','','','','','','','',
			'                             Did you know the average Danish penis size is so small . . their pants fall off!'];
	} else {
		txt = ['Greets from deFEEST to all at outline 2011', '', 
			'Thx to: Ziphoid for encoding the audio.','Our moms for not using contraceptives.', 
			'GROLSCH', 'TMC (The Movie Collecting one, not the Canadian) for lending Photoshop', 
			'sirius)(black for use of GIMP (cause Photoshop sucks)', 
			'Chrome dev team for V8 JavaScript engine!', 'You for watching!'];
		offset = offset + 0.06;
		horizontal = -100;
	}
	
	for(i = 0; i < txt.length; i++) {
		context.fillText(txt[i], -HALF_WIDTH+20-(horizontal+(Math.sin(offset)*60)), -HALF_HEIGHT+(i*30)+60-(Math.cos(offset*0.7)*40), 0);
	}
	lastTime = time;
}

// The blob Object
function blob(c) {
  this.cnt = c;
  this.pts = createBlob(this.cnt);
  this.img = new Image();
  this.fov = randomRange(90, 180);
  this.sX = randomRange(-5, 5);
  this.sY = randomRange(-5, 5);
  
  this.render = function(c) {
    for (i=0; i<this.cnt; i++) {
      var point = this.pts[i]; 
      point.rotateXY(this.sX, this.sY);
      draw3Din2D(point, c, this.img, this.fov); 
    }
  }
  
  function createBlob(cnt) {
    // create 3D blob 
    var pts = [];
    for(var i = 0 ; i< cnt; i++) {
      pts.push(new Point3D(randomRange(-150,150),randomRange(-150,150),randomRange(-150,150)));
    }
    return pts;
  }
  
  // The 3D Point object. 
  // now with added method to rotate around the X and Y axis.
  function Point3D(x,y,z) {
    this.x = x; 
    this.y = y; 
    this.z = z; 
    // rotates the point around the origin by the specified 
    // number of degrees. Uses the trigonometry 
    // that you've probably forgotten from high school    
    this.rotateXY = function(angleX, angleY) {
      // might do with some more hard coding ;)
      var xy, xz, yz;

      sinRY = Math.sin(angleX * TO_RADIANS);
      cosRY = Math.cos(angleX * TO_RADIANS);
      sinRX = Math.sin(angleY * TO_RADIANS);
      cosRX = Math.cos(angleY * TO_RADIANS);

      xy = (cosRX*this.y)-(sinRX*this.z);
      xz = (sinRX*this.y)+(cosRX*this.z);
      yz = (cosRY*xz)-(sinRY*this.x);
	  
      this.x = (sinRY*xz)+(cosRY*this.x);
      this.y = xy;
      this.z = yz;
    }
  }
  
  function draw3Din2D(p3d, c, particleImage, fov) {  
    var scale = fov/(fov + p3d.z); 

    // if the particle is behind the camera, then don't draw it!
    if(scale<0) return; 

    // then multiply the 3D x and y by this scale
    // to get the 2D x and y. 
    var x2d = (p3d.x * scale);    
    var y2d = (p3d.y * scale);

    // save the state of the draw matrix
    c.save(); 

    // adjust the size dependent on the calculated scale factor
    // (1.5 is just an adjuster to make it a little bigger)
    c.scale(scale, scale); 
    // and offset so the image is centred on the position
    c.translate(particleImage.width * -0.5, particleImage.height * -0.5 );
    // and then draw it at x2d,y2d 
    // the particle position. 
    c.drawImage(particleImage, x2d,y2d); 

    // restore canvas to state before we started screwing with it :)
    c.restore();
  }
}

// returns a random number between the two limits provided 
function randomRange(min, max) {
  return ((Math.random()*(max-min)) + min); 
}
