
//Line drwawings by rimina

//duration: part length in ms
//startTime: the absolute time when the part starts
//endTime: time that part need for end effect in ms
var Balls = function(){
  PartBase.call(this);
  this.initScene();
}

Balls.prototype = PartBase.prototype.inheritance();

//scene is initialized before demo starts
Balls.prototype.initScene = function(){
  
  this.scene = new THREE.Scene();
  this.camera = new THREE.PerspectiveCamera(TDEMO.fov, TDEMO.aspect, TDEMO.near, TDEMO.far);
  this.camera.position.z = 600;
  this.camera.position.y = 100;
  this.camera.rotation.x = -Math.PI/20;
  this.scene.add(this.camera);
  
  
  this.lsystem = new LSYSTEM();
  
  this.lsystem.interpret(12, 30, "F", "FFldFrFrFbdFtFtFubrdrFlFlFlFbdrFuFuFuFtb", 2);
  this.lsystem.moveToCenter();
  
  this.createHeightMap();
  this.scene.add(this.ground);
  
  this.container = new THREE.Object3D();
  this.createBalls();
  this.scene.add(this.container);
  
  this.startTime = 0;
  this.transformations = [];
  
  this.createSurroundings();
}

Balls.prototype.prepare = function(elapsedTime){
  this.startTime = elapsedTime;
  
  this.transformations = [
    {
      start : this.startTime,
      end : this.startTime + TDEMO.barLength*13.5,
      p : 600,
      v : (-600-400)/(TDEMO.barLength*13.5),
      r : (Math.PI*4)/(TDEMO.barLength*13.5),
      callback : function(transform, time){

        var t = time - transform.start;
        var s = transform.v * t;
        var sr = transform.r * t;
        
        this.camera.position.z = transform.p+s;
        
        for(var i = 0; i < this.right.children.length; ++i){
          this.right.children[i].rotation.y = sr+(0.1*i);
          this.left.children[i].rotation.y = -(sr+(0.1*i));
        }
        
      },
      done : false
    },
    {
      start : this.startTime + TDEMO.barLength*6,
      end : this.startTime + TDEMO.barLength*9,
      v : Math.PI/(TDEMO.barLength*3),
      callback: function(transform, time){
        var t = time - transform.start;
        var s = transform.v*t;
        
        this.camera.rotation.y = s;
      },
      done: false
    },
  ];
};

//Operations tahta takes place before rendering in every cycle
Balls.prototype.animate = function(elapsedTime){

  for(var i = 0; i < this.transformations.length; ++i){
    var transform = this.transformations[i];
    if(!transform.done && elapsedTime >= transform.start && elapsedTime <= transform.end){
      transform.callback.call(this, transform, elapsedTime);
    }
    else if(!transform.done && elapsedTime >= transform.end){
      transform.done = true;
    }
  }
}

Balls.prototype.createBalls = function(){

  var ballMaterial = new THREE.MeshPhongMaterial({
    color : 0x6A5ACD,
    ambient : 0x6A5ACD,
    emissive : 0x000000,//0x855285,
    specular : 0xFF55FF
  });
  var geometry = new THREE.SphereGeometry(6, 16, 16);
  
  this.left = new THREE.Object3D();
  this.right = new THREE.Object3D();
  
  var trees = 8;
  var z = 600;
  var step = -150;
  
  for(var k = 0; k < trees; ++k){
    var tree = new THREE.Object3D();
    var tree2 = new THREE.Object3D();
    
    for(var i = 0; i < this.lsystem.path.length; ++i){
      var point = this.lsystem.path[i];
      
      var ball = new THREE.Mesh(geometry, ballMaterial);
      ball.position.x = point.fromx;
      ball.position.y = point.fromy;
      ball.position.z = point.fromz;
      
      var ball2 = new THREE.Mesh(geometry, ballMaterial);

      ball2.position.x = point.tox;
      ball2.position.y = point.toy;
      ball2.position.z = point.toz;
      
      tree.add(ball);
      tree.add(ball2);
      
      tree2.add(ball.clone());
      tree2.add(ball2.clone());
      
    }
    tree.position.z = z;
    tree2.position.z = z;
    this.left.add(tree);
    this.right.add(tree2);
    
    z += step;
  }
  
  this.left.position.x = -110;
  this.right.position.x = 110;
  
  this.container.add(this.left);
  this.container.add(this.right);
}

Balls.prototype.createHeightMap = function(){
  var rtt = new THREE.WebGLRenderTarget(256, 256);
  
  var plane = new THREE.Mesh(new THREE.PlaneGeometry(256, 256), new THREE.ShaderMaterial({
    vertexShader : NoiseShader.vertexShader,
    fragmentShader : NoiseShader.fragmentShader
  }));
  var s = new THREE.Scene();
  var c = new THREE.OrthographicCamera(-256/2, 256/2, 256/2, -256/2);
  c.position.z = 1;
  s.add(c);
  s.add(plane);
  
  TDEMO.renderer.render(s, c, rtt, true);
  
  var gl = TDEMO.renderer.getContext();
  var pixels = new Uint8Array(4 * 256 * 256);
  gl.readPixels( 0, 0, 256, 256, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
  
  var geometry = new THREE.PlaneGeometry(1600,1600,40,40);
  geometry.dynamic = true;
  var material = new THREE.MeshBasicMaterial( { map: rtt, color : 0x40E0D0 } );
  this.ground = new THREE.Mesh( geometry, material );
  
  //set height of vertices
  for ( var i = 0; i<this.ground.geometry.vertices.length; i++ ){
    this.ground.geometry.vertices[i].z = pixels[i]/12;
  }
  geometry.verticesNeedUpdate = true;
  this.ground.rotation.x = -Math.PI/2;
}

Balls.prototype.createSurroundings = function(){

  var ambient = new THREE.AmbientLight(0xF8F8FF);
  this.scene.add(ambient);
  
  var pointLight = new THREE.PointLight(0xBF5FFF);
  pointLight.position.z = 100;
  this.scene.add(pointLight);
  
  this.scene.fog = new THREE.Fog(0xAAAAFF, 600, 1000 );
  
  var skyMaterial = new THREE.MeshBasicMaterial({color : 0x7171C6, side: THREE.BackSide});
  this.skySphere = new THREE.Mesh(new THREE.SphereGeometry(800, 16, 16), skyMaterial);
  this.scene.add(this.skySphere);
  
  this.rainbow = new Rainbow();
  this.rainbow.position.z = 60;
  this.scene.add(this.rainbow);
}

//rendering function
Balls.prototype.render = function(elapsedTime, rtt){
  TDEMO.renderer.render(this.scene, this.camera, rtt);
}