/*
* @project AvriBubble & AvriContainer - Mootools 1.2.1> Drag Class
* @author : Quentin Ambard
* @version : 0.1.2
* @url http://www.avricot.com/blog
* @license MIT Style License
*
* @contributions
* :bounce algorithm
* :Olivier Desmaisons 
*/

var AvriContainer = new Class({
	  Implements: [Options, Events],
	  options: {
		  top: 0,
		  left: 50,
		  height: 670,
		  width: 1280,
		  speed: 20,
		  randomChange: 1,
		  detectColision: true,
		  gravity: 1,
		  friction: 0.9,
		  displayBorder: true
	  },
	  listBulle: [],
	  periodical: null,
	  wall: {el: {id: 'wall'}},
	  initialize: function(_options){
		  this.setOptions(_options);
		  this.top = this.options.top ;
		  this.left =  this.options.left ;
		  this.right =  this.options.left+this.options.width ;
		  this.bottom =  this.options.top+this.options.height ;
		  
		  if (this.options.displayBorder === true) {
			  var divBorder = new Element('div', { 'class': 'container', styles: { width: this.options.width, height: this.options.height, top: this.options.top, left: this.options.left} }).inject(document.body) ;
		  }
	  },
	  add: function (_bubble) {
		  if(_bubble.options.isDraggable === true) {
			  var that = this ;
			  var drag = _bubble.el.makeDraggable ({
				  snap: 0,
				  limit: {x:[that.left+1,that.right-_bubble.radius*2-1], y:[that.top+1,that.bottom-_bubble.radius*2-1]},
				  //beforeStart
				  onSnap: function (b) { this.isDragged = true ;}.bind(_bubble),
				  onDrag: function(b){
					  this.speed.x = b.getTop()+this.radius-this.center.x ; 
					  this.speed.y = b.getLeft()+this.radius-this.center.y;
					  this.center.x = b.getTop()+this.radius;
					  this.center.y = b.getLeft()+this.radius;
				  }.bind(_bubble),
  				  onDrop: function (b) {this.isDragged = false ;}.bind(_bubble)
			  }) ; 
			  _bubble.el.addEvents({mousedown: function () { _bubble.isDragged = true; },
									mouseup: function () { _bubble.isDragged = false; }});
		  }
		  _bubble.start();
		  this.listBulle[this.listBulle.length] = _bubble ;
	  },
	  start: function() {
		  if(this.periodical === null)
			  this.periodical = this.move.periodical(this.options.speed, this) ;
	  },
	  stop: function() {
		  this.periodical = $clear(this.periodical) ;
	  },
	  move: function () {
		  var i, size, b1 ;
		  size = this.listBulle.length;
		  for(i=0;i<size;i++) {
			  b1 = this.listBulle[i] ;
			  b1.speed.x += this.options.gravity/10;
			  //make a random change of the direction...
			  if(this.options.randomChange<1) {
				  if (Math.random()>this.options.randomChange) {
					  b1.speed.y = b1.getRandomSpeed();
				  }
				  if (Math.random()>this.options.randomChange) {
					  b1.speed.x = b1.getRandomSpeed();
				  }
			  }			  
			  b1.move();
			  //detection of the colision with another bubbles
			  if (this.options.detectColision) {
				  var b2, theta, v1Tang, v2Tang, v1Norm, v2Norm, v1NormBis, v2NormBis;
				  for(j=0;j<size;j++) {
					  b2 = this.listBulle[j] ;
					  //if there is a colision
					  if(i!=j && this.colisionbubble(b1, b2)) {
						  //angle of the contact surface
						  theta = Math.abs(Math.atan((b1.center.x-b2.center.x)/(b1.center.y-b2.center.y)));
						  if ((b1.center.x-b2.center.x)*(b1.center.y-b2.center.y)>0)
								theta *= -1 ;
						  //we work in the speed reference
						  v1Tang=Math.cos(theta)*b1.speed.x+Math.sin(theta)*b1.speed.y;
						  v1Norm=-Math.sin(theta)*b1.speed.x+Math.cos(theta)*b1.speed.y;
						  v2Tang=Math.cos(theta)*b2.speed.x+Math.sin(theta)*b2.speed.y;
						  v2Norm=-Math.sin(theta)*b2.speed.x+Math.cos(theta)*b2.speed.y;
						  //News speeds (Tan is unchanged)
						  v1NormBis=((b1.mass-b2.mass)*v1Norm+2*b2.mass*v2Norm)/(b1.mass+b2.mass);
						  v2NormBis=((b2.mass-b1.mass)*v2Norm+2*b1.mass*v1Norm)/(b1.mass+b2.mass);
						  b1.unMove();
						  //%nouveau changement de rep鑽e
						  b1.speed.x=Math.cos(theta)*v1Tang-Math.sin(theta)*v1NormBis;
						  b1.speed.y=Math.sin(theta)*v1Tang+Math.cos(theta)*v1NormBis;
						  b2.speed.x=Math.cos(theta)*v2Tang-Math.sin(theta)*v2NormBis;
						  b2.speed.y=Math.sin(theta)*v2Tang+Math.cos(theta)*v2NormBis;
						  //frottements
						  b1.friction(this.options.friction) ;
						  b2.friction(this.options.friction) ;
						  while(this.colisionbubble(b1, b2)) {
							b2.move();
							b1.move();
						  }
					  }
				  }
			  }
			  //detection of the colision with the border of the container
			  if(this.colisionX(b1)) {
				  b1.friction(this.options.friction);
				  b1.unMove();
				  b1.inverseX();
				  if(this.colisionX(b1)) {
				  	  b1.move();
				  }
			  }
			  if(this.colisionY(b1)) {
				  b1.friction(this.options.friction);
				  b1.unMove();
				  b1.inverseY();
				  if(this.colisionY(b1)) {
				  	  b1.move();
				  }
			  }
			  b1.displayMove();
		  }
	  },
	  colisionX: function(b) {
		  if(!b.isDragged && (b.center.x-b.radius<=this.top || b.center.x+b.radius>=this.bottom)) {
		  	  this.fireEvent('colision', [b, this.wall]) ;
			  return true ;
		  } else {
		      return false ;  
		  }
	  },
	  colisionY: function(b) {
		  if(!b.isDragged && (b.center.y-b.radius<=this.left || b.center.y+b.radius>=this.right)) {
		  	  this.fireEvent('colision', [b, this.wall]) ;
			  return true ;
		  } else {
		      return false ;  
		  }
	  },
	  colisionbubble: function (b1, b2) {
		 if (Math.sqrt(Math.pow(b1.center.x - b2.center.x,2)+Math.pow(b1.center.y - b2.center.y,2))<=b1.radius+b2.radius) {
		  	  this.fireEvent('colision', [b1, b2]) ;
			  return true ;
		  } else {
		      return false ;  
		  }
	  }
});

var AvriBubbule = new Class({
	  Implements: [Options, Events],
	  options: {
		  step: 5,
		  mass: 'prop',
		  isDraggable: true
	  },
	  isDragged: false,
	  speed: {x: 0, y: 0},
	  center: {x: 0, y: 0},
	  initialize: function(_element , _options){
		  this.el = $(_element);
		  this.radius = this.el.getStyle('height').toInt()/2 ;
		  this.center.x = this.el.getStyle('top').toInt() + this.radius;
		  this.center.y = this.el.getStyle('left').toInt() + this.radius;
		  this.setOptions(_options);
		  this.step = this.options.step ;
		  if (this.options.mass === 'prop') {
			  this.mass = Math.pow(this.radius,2) ;
		  } else {
		  	this.mass = this.options.mass ;
		  }
	  },
	  getRandomSpeed: function() {
		  return this.step/2-Math.random()*this.step;
	  },
	  move: function () {
		  if(!this.isDragged) {
			  this.center.x += this.speed.x ;
			  this.center.y += this.speed.y ;
		  }
	  },
	  unMove: function () {
		  if(!this.isDragged) {
			  this.center.x -= this.speed.x ;
			  this.center.y -= this.speed.y ;
		  }
	  },
	  start: function () {
		  this.speed.y = this.getRandomSpeed()
		  this.speed.x = this.getRandomSpeed();
	  },
	  inverseX: function () {
		  if(!this.isDragged) {
			 this.speed.x *= -1; 
		  }
	  },
	  inverseY: function () {
		  if(!this.isDragged) {
			 this.speed.y *= -1; 
		  }
	  },
	  displayMove: function () {
		  if(!this.isDragged) {
			  this.el.setStyle('top', this.center.x-this.radius); 
			  this.el.setStyle('left', this.center.y-this.radius); 
		  }
	  },
	  friction: function (_friction) {
		  this.speed.x *= _friction ;
		  this.speed.y *= _friction ;
	  }
});
