// Copyright (c) 2005 Thomas Fuchs (http://mir.aculo.us)
// 
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


Effect2 = {}

/* ------------- transitions ------------- */

Effect2.Transitions = {}
Effect2.Transitions.linear = function(pos) {
	return pos;
}
Effect2.Transitions.sinoidal = function(pos) {
	return (-Math.cos(pos*Math.PI)/2) + 0.5;
}
Effect2.Transitions.reverse  = function(pos) {
	return 1-pos;
}
Effect2.Transitions.flicker = function(pos) {
	return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random(0.25);
}
Effect2.Transitions.wobble = function(pos) {
	return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
}

/* ------------- core effects ------------- */

Effect2.Base = function() {};
Effect2.Base.prototype = {
  setOptions: function(options) {
	this.options = {
	  transition: Effect2.Transitions.sinoidal,
	  duration:   1.0,   // seconds
	  fps:        25.0,  // max. 100fps
	  sync:       false, // true for combining
	  from:       0.0,
	  to:         1.0
	}.extend(options || {});
  },
  start: function(options) {
	this.setOptions(options || {});
	this.currentFrame    = 0;
	  this.startOn  = new Date().getTime();
	  this.finishOn = this.startOn + (this.options.duration*1000);
	  if(this.options.beforeStart) this.options.beforeStart(this);
	if(!this.options.sync) this.loop();	
  },
  loop: function() {
	 timePos = new Date().getTime();
	 if(timePos >= this.finishOn) {
		this.render(this.options.to);
		if(this.finish) this.finish(); 
		if(this.options.afterFinish) this.options.afterFinish(this);
		return;	
	 }
	 pos   = (timePos - this.startOn) / (this.finishOn - this.startOn);
	 frame = Math.round(pos * this.options.fps * this.options.duration);
	 if(frame > this.currentFrame) {
		this.render(pos);
		this.currentFrame = frame;
	 }
	 this.timeout = setTimeout(this.loop.bind(this), 10);
  },
  render: function(pos) {
	 if(this.options.transition) pos = this.options.transition(pos);
	 pos  = pos * (this.options.to-this.options.from);
	 pos += this.options.from; 
	 if(this.options.beforeUpdate) this.options.beforeUpdate(this);
	 if(this.update) this.update(pos);
	 if(this.options.afterUpdate) this.options.afterUpdate(this);	
  },
  cancel: function() {
	 if(this.timeout) clearTimeout(this.timeout);
  }
}

Effect2.Opacity = Class.create();
Effect2.Opacity.prototype = (new Effect2.Base()).extend({
  initialize: function() {
	this.element = $(arguments[0] || document.rootElement);
	options = {
	  from: 0.0,
	  to:   1.0
	}.extend(arguments[1] || {});
	this.start(options);
  },
  update: function(position) {
	this.setOpacity(position);
  }, 
  setOpacity: function(opacity) {
	opacity = (opacity == 1) ? 0.99999 : opacity;
	this.element.style.opacity = opacity;
	this.element.style.filter = "alpha(opacity:"+opacity*100+")";
  }
});

/* ------------- prepackaged effects ------------- */

Effect2.Appear = function(element) {
	options = {
		from:     0.0,
		to:       1.0,
		duration: 0.3,
		beforeStart: function(effect) { 
			effect.setOpacity(0);
			Element.show(effect.element); 
		},
		afterUpdate: function(effect) { 
			Element.show(effect.element); 
		}
	}.extend(arguments[1] || {});
	new Effect2.Opacity(element,options);
}

