
//nimiavaruus
TDEMO = {
  audioStatus : false,
  
  inited : false,
  user : false,
  started : false,
  
  //ajastus ja parttien vaihto
  timeElapsed : 0,
  timeHelper : 0, // In case of no audio
  
  animationSpeed : 1/30,//animation speed
  maxSkip : 5,
  nextTick : 0,
  
  brightnessBlink : 3.0,
  brightnessDark : -3.0,
  brightnessDefault: 0.1,
  blinkOn : false,

  displayCredits : MUSIC.duration-(MUSIC.barLength*2),
  fadeCredits : MUSIC.duration-MUSIC.barLength,
  creditsVisible : false,
  creditsFaded : false,
  end : MUSIC.duration,
  
  width : 0,
  height : 0,
  minx : 0,
  maxx : 0,
  miny : 0,
  maxy : 0,
  
  //some camera parameters
  fov: 55,
  near : 0.2,
  far: 800,
  aspect : 1,
  
  mainloop : function(){
    
    if(!TDEMO.started){
      TDEMO.started = true;
      TDEMO.mainPart.prepare(0);
      if(TDEMO.audio !== undefined) {
        TDEMO.audio.play();
      }
      
      TDEMO.timeHelper = Date.now()/1000;
    }
    
    if(TDEMO.audio !== undefined) {
      TDEMO.timeElapsed = TDEMO.audio.currentTime;
    }
    else {
      TDEMO.timeElapsed = TDEMO.timeElapsed + (Date.now()/1000 - TDEMO.timeHelper);
      TDEMO.timeHelper = Date.now()/1000;
    }
    
    TDEMO.beat = MUSIC.onBeat(TDEMO.timeElapsed);
    //updating tic value for shader
    if(TDEMO.mainShader.uniforms.blend.value == 1 && TDEMO.beat.tic != TDEMO.mainShader.uniforms.beat.value){
      TDEMO.mainShader.uniforms.beat.value = TDEMO.beat.tic;
    }
    
    if(!TDEMO.beginning.ended){
      TDEMO.beginning.changeText(TDEMO.timeElapsed, TDEMO.beat.onTic);
    }
    
    //looping through state changes, transitions and blinks
    var limit = Math.max(Math.max(TDEMO.stateChanges.length, TDEMO.blinks.length), TDEMO.transitions.length);
    for(var b = 0; b < limit; ++b){
      if(b < TDEMO.blinks.length){
        var blink = TDEMO.blinks[b];
        if(!blink.done && TDEMO.timeElapsed >= blink.startTime && TDEMO.timeElapsed){

          if(TDEMO.beat.onTic && (blink.beats.indexOf(TDEMO.beat.beat) != -1 && blink.tics.indexOf(TDEMO.beat.tic) != -1)){
            TDEMO.brightnessPass.uniforms[ "brightness" ].value = TDEMO.brightnessBlink;
            TDEMO.blinkOn = true;
          }
          else if(TDEMO.blinkOn){
            TDEMO.brightnessPass.uniforms[ "brightness" ].value = TDEMO.brightnessDefault;
            TDEMO.blinkOn = false;
          }
        }
        if(!blink.done && TDEMO.timeElapsed >= blink.endTime){
          blink.done = true;
          TDEMO.brightnessPass.uniforms[ "brightness" ].value = TDEMO.brightnessDefault;
        }
      }
      if(b < TDEMO.stateChanges.length){
        var state = TDEMO.stateChanges[b];
        if(!state.done && TDEMO.timeElapsed >= state.startTime){
          state.uniform.value = state.endValue;
          state.done = true;
        }
      }
      if(b < TDEMO.transitions.length){
        var transition = TDEMO.transitions[b];
        //middle of transformation
        if(!transition.done && TDEMO.timeElapsed >= transition.startTime && TDEMO.timeElapsed < transition.endTime){
          var t = TDEMO.timeElapsed - transition.startTime;
          var s = transition.velocity * t;
          transition.uniform.value = transition.startValue + s;
        }
        else if(!transition.done && TDEMO.timeElapsed >= transition.endTime){
          transition.uniform.value = transition.endValue;
          transition.done = true;
        }
      }
    }
    
    var loops = 0;
    while( TDEMO.timeElapsed > TDEMO.nextTick && loops < TDEMO.maxSkip) {
      
      for(var i = 0; i < TDEMO.changeAnimation.length; ++i){
        if(i < TDEMO.changeAnimation.length){
          var animation = TDEMO.changeAnimation[i];
          if(!animation.done && TDEMO.timeElapsed >= animation.time){
            animation.done = true;
            TDEMO.mainPart.switchAnimation(animation.to);
          }
        }
      }
      
      
      TDEMO.mainPart.animate(TDEMO.animationSpeed, TDEMO.timeElapsed);
      TDEMO.mainShader.uniforms.time.value = TDEMO.timeElapsed;
      TDEMO.nextTick += TDEMO.animationSpeed;
      loops++;
    }
    
    var interpolation = (TDEMO.timeElapsed + TDEMO.animationSpeed - TDEMO.nextTick )/TDEMO.animationSpeed;
    TDEMO.mainPart.render(TDEMO.elapsedTime, interpolation, TDEMO.mainRTT);
    
    TDEMO.composer.render();
    
    if(TDEMO.timeElapsed >= TDEMO.displayCredits){
      var credits = document.getElementById("credits");
      if(!TDEMO.creditsVisible){
        credits.style.display = "block";
        credits.style.opacity = 0.8;
        TDEMO.creditsVisible = true;
      }
      if(!TDEMO.creditsFaded && TDEMO.timeElapsed >= TDEMO.fadeCredits){
        credits.style.opacity = parseFloat(credits.style.opacity)-0.1;
        if(parseFloat(credits.style.opacity) <= 0.0){
          TDEMO.creditsFaded = true;
        }
      }
    }
    
    if(TDEMO.timeElapsed > TDEMO.end && TDEMO.creditsFaded){
      cancelAnimationFrame(TDEMO.mainloop);
      console.log("The End");
    }
    else{
      requestAnimationFrame(TDEMO.mainloop);
    }
  }
  
};

//parttien luominen ja alustaminen.
var initParts= function(){
  
  TDEMO.mainPart = new Tunneli();
  TDEMO.beginning = Beginning();
  
  //TODO: SEPARATE STATE CHANGES FROM TRANSITIONS
  //TRANSITIONS NEED START AND END TIME STATE CHANGES ONLY TRIGGER TIME
  
  var getVelocity = function(startValue, endValue, startTime, endTime){
    var t = endTime-startTime;
    var s = endValue-startValue;
    var v = s/t;
    return v;
  }
  
  TDEMO.transitions = [
    {//Fade in after intro
      startTime : MUSIC.syncPoints.verse1+(MUSIC.barLength*4),
      endTime : MUSIC.syncPoints.verse1+(MUSIC.barLength*8),
      uniform : TDEMO.brightnessPass.uniforms[ "brightness" ],
      startValue : TDEMO.brightnessDark,
      endValue : TDEMO.brightnessDefault,
      done : false,
    },
    {//Transition to main scene
      startTime : MUSIC.syncPoints.fill1,
      endTime : MUSIC.syncPoints.verse2,
      uniform: TDEMO.mainShader.uniforms.phase,
      startValue : 2.0,
      endValue : -2.0,
      done : false,
    },
    {//transition to spherical scene
      startTime : MUSIC.syncPoints.bridge3,
      endTime : MUSIC.syncPoints.slow,
      uniform : TDEMO.mainShader.uniforms.phase,
      startValue : -2.0,
      endValue : 1.5,
      done : false,
    },
    {//transition back to normal scene
      startTime : MUSIC.syncPoints.slowBridge,
      endTime : MUSIC.syncPoints.verse4,
      uniform : TDEMO.mainShader.uniforms.phase,
      startValue : 1.5,
      endValue : -2.0,
      done : false,
    },
    {//Fade out
      startTime : MUSIC.syncPoints.lastBeat-(MUSIC.spb*2.0),
      endTime : MUSIC.syncPoints.lastBeat,
      uniform : TDEMO.brightnessPass.uniforms[ "brightness" ],
      startValue : TDEMO.brightnessDefault,
      endValue : TDEMO.brightnessDark,
      done : false,
    }
  ];

  for(var i = 0; i < TDEMO.transitions.length; ++i){
    var t = TDEMO.transitions[i];
    t.velocity = getVelocity(t.startValue, t.endValue, t.startTime, t.endTime);  
  }
  //console.log(TDEMO.transitions);

  TDEMO.stateChanges = [
    {//First scene to shader scene
      startTime : 0,
      uniform : TDEMO.mainShader.uniforms.phase,
      endValue : 2,
      done: false,
    },
    {//Blend used is from corner
      startTime : 0,
      uniform : TDEMO.mainShader.uniforms.blend,
      endValue : 3,
      done: false,
    },
    {//changing effect is tunnel
      startTime : 0,
      uniform : TDEMO.mainShader.uniforms.effect,
      endValue : 2,//tunnel effect
      done : false,
    },
    {//Blend used is from corner
      startTime : MUSIC.syncPoints.bridge3,
      uniform : TDEMO.mainShader.uniforms.blend,
      endValue : 2,
      done: false,
    },
    {//changing effect from tunnel to spherical
      startTime : MUSIC.syncPoints.bridge3,
      uniform : TDEMO.mainShader.uniforms.effect,
      endValue : 1,//spherical effect
      done : false,
    },
    {//Mixing tunnel and spherical
      startTime : MUSIC.syncPoints.slow + 16*MUSIC.barLength,
      uniform : TDEMO.mainShader.uniforms.effect,
      endValue : 3, //Mixed feelings
      done : false,
    },
    {//changing effect back to tunnel
      startTime : MUSIC.syncPoints.fill3+(MUSIC.spb*0.5),
      uniform : TDEMO.mainShader.uniforms.effect,
      endValue : 2,//tunnel effect
      done : false,
    },
    {//beat blengind to the last verse
      startTime : MUSIC.syncPoints.verse4,
      uniform : TDEMO.mainShader.uniforms.blend,
      endValue : 1,//beat blending
      done : false,
    },
    {//BREAK IT ALL
      startTime : 0,
      uniform : TDEMO.mainShader.uniforms.breakThings,
      endValue : 1,//YES DO THIS!!
      done : false,
    },
    {//FIX IT ALL
      startTime : MUSIC.syncPoints.verse4,
      uniform : TDEMO.mainShader.uniforms.breakThings,
      endValue : 0,
      done : false,
    }
  ];
  
  //console.log(TDEMO.stateChanges);
  
  TDEMO.blinks = [
    {
      startTime : MUSIC.syncPoints.fill1,
      beats : [0, 1, 2],
      tics : [0, 2],
      endTime : MUSIC.syncPoints.verse2,
      done : false
    },
    {
      startTime : MUSIC.syncPoints.fill1,
      beats : [3],
      tics : [0, 1, 2, 3],
      endTime : MUSIC.syncPoints.verse2,
      done : false
    },
    {
      startTime : MUSIC.syncPoints.verse3-MUSIC.barLength,
      beats : [0, 1, 2, 3],
      tics : [0, 2],
      endTime : MUSIC.syncPoints.verse3,
      done: false
    },
    {
      startTime : MUSIC.syncPoints.verse3,
      beats : [0, 3],
      tics : [0, 2],
      endTime : MUSIC.syncPoints.bridge3-(MUSIC.spb*2),
      done : false
    },
    {
      startTime : MUSIC.syncPoints.bridge3-(MUSIC.spb*2),
      beats : [0, 1, 2, 3],
      tics : [0, 2],
      endTime : MUSIC.syncPoints.bridge3+(MUSIC.spb*3),
      done : false
    },
    {
      startTime : MUSIC.syncPoints.fill2,
      beats : [0, 1, 2],
      tics : [0, 2],
      endTime : MUSIC.syncPoints.slow,
      done : false
    },
    {
      startTime : MUSIC.syncPoints.fill2,
      beats : [3],
      tics : [0, 1, 2, 3],
      endTime : MUSIC.syncPoints.slow,
      done : false
    },
    {
      startTime : MUSIC.syncPoints.slowBridge,
      beats : [0, 1, 2, 3],
      tics : [0, 2],
      endTime : MUSIC.syncPoints.fill3,
      done: false
    },
    {
      startTime : MUSIC.syncPoints.fill3,
      beats : [0, 1, 2],
      tics : [0, 2],
      endTime : MUSIC.syncPoints.verse4,
      done : false
    },
    {
      startTime : MUSIC.syncPoints.fill3,
      beats : [3],
      tics : [0, 1, 2, 3],
      endTime : MUSIC.syncPoints.verse4,
      done : false
    },
    {
      startTime : MUSIC.syncPoints.verse4,
      beats : [0, 3],
      tics : [0, 2],
      endTime : MUSIC.syncPoints.bridge4,
      done : false
    },
    {
      startTime : MUSIC.syncPoints.bridge4,
      beats : [0, 1, 2, 3],
      tics : [0, 1, 2, 3],
      endTime : MUSIC.syncPoints.lastBeat-(2*MUSIC.spb),
      done: false
    },
  ];
  
  //Animation function change
  TDEMO.changeAnimation = [
    {//Fading the ball out and cats in
      time : MUSIC.syncPoints.verse3,
      to : Tunneli.prototype.animate2,
      done : false
    }, 
    {//stopping the cats
      time : MUSIC.syncPoints.verse3+MUSIC.barLength*4,
      to : Tunneli.prototype.animate3,
      done : false
    },
    {//faiding the cats out
      time : MUSIC.syncPoints.bridge3,
      to : Tunneli.prototype.animate4,
      done : false
    }
  ];
};

//aloitetaan demo, kun kaikki alustustoimenpiteet
//on varmasti suoritettu
var allLoaded = function(){
  if(document.getElementById("audio") == null) {
    TDEMO.audioStatus = true;
  }
  if(TDEMO.audioStatus && TDEMO.inited && TDEMO.user){
    console.log("Let's start!");
    document.getElementById("loader").style.display = "none";
    TDEMO.mainloop();
  }
};

var audioReady = function(){
  TDEMO.audioStatus = true;
  TDEMO.audio = document.getElementById("audio");
  
  allLoaded();
};

var start = function(){
  
  window.addEventListener("resize", onResize);
  
  document.getElementById("start").style.display = "none";
  document.getElementById("demo").style.display = "block";
  document.getElementById("loader").style.display = "block";
  init();

  setTimeout(function(){
    TDEMO.user = true;
    allLoaded();
  }, 5000);
};

var fullScreen = function(){
  var demoEl = document.getElementById("demo");
  
  if(demoEl.requestFullscreen){
    demoEl.requestFullscreen();
  }
  else if(demoEl.mozRequestFullScreen){
    demoEl.mozRequestFullScreen();
  }
  else if (demoEl.webkitRequestFullscreen){
    demoEl.webkitRequestFullscreen();
  }
  else{
    console.log("Full screen failed defaulting to 1280x720");
    p720();
    return;
  }
  
  TDEMO.width = screen.width;
  TDEMO.height = screen.height;
  
  start();
}

var p720 = function(){
  TDEMO.width = 1280;
  TDEMO.height = 720;
  
  var demoEl = document.getElementById("demo");
  
  demoEl.width = TDEMO.width;
  demoEl.height = TDEMO.height;

  demoEl.style.position = "absolute";
  demoEl.style.top = ((window.innerHeight-TDEMO.height)/2).toString() + "px";
  demoEl.style.left = ((window.innerWidth-TDEMO.width)/2).toString() + "px";
  start();
}

var testReso = function(){
  TDEMO.width = 128;
  TDEMO.height = 128;
  
  var demoEl = document.getElementById("demo");
  
  demoEl.width = TDEMO.width;
  demoEl.height = TDEMO.height;

  demoEl.style.position = "absolute";
  demoEl.style.top = ((window.innerHeight-TDEMO.height)/2).toString() + "px";
  demoEl.style.left = ((window.innerWidth-TDEMO.width)/2).toString() + "px";
  start();
}

var onResize = function(){

  var demoEl = document.getElementById("demo");

  demoEl.style.position = "absolute";
  demoEl.style.top = ((window.innerHeight-TDEMO.height)/2).toString() + "px";
  demoEl.style.left = ((window.innerWidth-TDEMO.width)/2).toString() + "px";

}


//Alustaa three.js:n, partteihin ja renderöintiin liittyvät jutut
var init = function(){

  TDEMO.aspect = TDEMO.width/TDEMO.height;
  
  //some commonly used values
  TDEMO.minx = -TDEMO.width/2;
  TDEMO.maxx = TDEMO.width/2;
  TDEMO.miny = -TDEMO.height/2;
  TDEMO.maxy = TDEMO.height/2;
  
  //alustetaan renderer
  TDEMO.renderer = new THREE.WebGLRenderer();
  TDEMO.renderer.setSize(TDEMO.width, TDEMO.height);
  TDEMO.renderer.setClearColor(0xFFFFCC);
  
  TDEMO.renderer.domElement.style.width = TDEMO.width;
  TDEMO.renderer.domElement.style.height = TDEMO.height;
  document.getElementById("demo").appendChild(TDEMO.renderer.domElement);
  
  TDEMO.mainRTT = new THREE.WebGLRenderTarget(TDEMO.width, TDEMO.height, {
    minFilter: THREE.LinearFilter,
    magFilter: THREE.NearestFilter,
    format: THREE.RGBFormat
  });
  
  TDEMO.scene = new THREE.Scene();
	TDEMO.camera = new THREE.OrthographicCamera(TDEMO.minx, TDEMO.maxx, TDEMO.maxy, TDEMO.miny);
	TDEMO.camera.position.z = 1;
	TDEMO.scene.add(TDEMO.camera);
  
  TDEMO.mainShader = MainShader();
  TDEMO.mainShader.uniforms.mainScene.value = TDEMO.mainRTT;
  TDEMO.mainShader.uniforms.resolution.value = new THREE.Vector2(TDEMO.width, TDEMO.height);
  
  TDEMO.displayMaterial = new THREE.ShaderMaterial({
      uniforms: TDEMO.mainShader.uniforms,
      vertexShader: TDEMO.mainShader.vertexShader,
      fragmentShader: TDEMO.mainShader.fragmentShader,
  });
  
  TDEMO.display = new THREE.Mesh(new THREE.PlaneGeometry(TDEMO.width, TDEMO.height),
    TDEMO.displayMaterial);
	TDEMO.display.position.z = -1;
  TDEMO.scene.add(TDEMO.display);
  
  
  //POSTPROCESSING PIPELINE
  
  //COMPOSER
  TDEMO.composer = new THREE.EffectComposer(TDEMO.renderer);
  TDEMO.renderPass = new THREE.RenderPass(TDEMO.scene, TDEMO.camera);
  TDEMO.composer.addPass(TDEMO.renderPass);

  //THE VISUAL PIPELINE WHICH IS APPLIED TO ALL BY DEFAULT
  TDEMO.brightnessPass = new THREE.ShaderPass(THREE.BrightnessContrastShader);
  TDEMO.brightnessPass.uniforms[ "brightness" ].value = TDEMO.brightnessDark;
  TDEMO.brightnessPass.uniforms[ "contrast" ].value = 0.1;
  TDEMO.composer.addPass(TDEMO.brightnessPass);
  
  TDEMO.hblur = new THREE.ShaderPass( THREE.HorizontalBlurShader );
  TDEMO.hblur.uniforms[ "h" ].value =  1.0/TDEMO.width;
  TDEMO.composer.addPass(TDEMO.hblur);
  
  TDEMO.vblur = new THREE.ShaderPass( THREE.VerticalBlurShader );
  TDEMO.vblur.uniforms[ "v" ].value = 1.0/TDEMO.height;
  TDEMO.composer.addPass(TDEMO.vblur);
  
  //THE LAST THING TO COMBINE ALL
  TDEMO.copyPass = new THREE.ShaderPass(THREE.CopyShader);
  TDEMO.copyPass.renderToScreen = true;
  TDEMO.composer.addPass(TDEMO.copyPass);

  initParts();
  
  //alustus on tehty, kutsutaan tarkastusfunktiota
  TDEMO.inited = true;
  allLoaded();
};


