//(c) 2006 Valerio Proietti (http://mad4milk.net). MIT-style license.
//Modified to be prototype free (and without name conflicts) by Tom Giordano
//moo.fx-prototypefree.js renamed fx.js
//version 2.0

// Prototype-Lite Function.prototype.bind => Function.prototype.FxBind
Function.prototype.FxBind = function(object) {
	var __method = this;
	return function() {
		return __method.apply(object, arguments);
	}
};

var Fx = fx = {};

// Prototype-Lite Object.extend => Fx.Extend
Fx.Extend = function(destination, source) {
	for (var property in source) destination[property] = source[property];
	return destination;
};

// Prototype-Lite: String.prototype.camelize => Fx.Camelize (note this works differently -- Fx.Camelize(str) vs str.camelize())
Fx.Camelize = function(str) {
	return str.replace(/-\D/gi, function(match){
		return match.charAt(match.length - 1).toUpperCase();
	});
};

// Prototype-Lite: $c => Fx.CreateArray
Fx.CreateArray = function(array){
	var nArray = [];
	for (var i=0;i<array.length;i++) nArray.push(array[i]);
	return nArray;
}

// Prototype-Lite: $ => Fx.GetElement
Fx.GetElement = function() {
	if (arguments.length == 1) return get$(arguments[0]);
	var elements = [];
	Fx.CreateArray(arguments).each(function(el){
		elements.push(get$(el));
	});
	return elements;

	function get$(el){
		if (typeof el == 'string') el = document.getElementById(el);
		return el;
	}
};

Fx.Base = function(){};
Fx.Base.prototype = {

	setOptions: function(options){
		this.options = Fx.Extend({
			onStart: function(){},
			onComplete: function(){},
			transition: Fx.Transitions.sineInOut,
			duration: 500,
			unit: 'px',
			wait: true,
			fps: 50
		}, options || {});
	},

	step: function(){
		var time = new Date().getTime();
		if (time < this.time + this.options.duration){
			this.cTime = time - this.time;
			this.setNow();
		} else {
			setTimeout(this.options.onComplete.FxBind(this, this.element), 10);
			this.clearTimer();
			this.now = this.to;
		}
		this.increase();
	},

	setNow: function(){
		this.now = this.compute(this.from, this.to);
	},

	compute: function(from, to){
		var change = to - from;
		return this.options.transition(this.cTime, from, change, this.options.duration);
	},

	clearTimer: function(){
		clearInterval(this.timer);
		this.timer = null;
		return this;
	},

	_start: function(from, to){
		if (!this.options.wait) this.clearTimer();
		if (this.timer) return;
		setTimeout(this.options.onStart.FxBind(this, this.element), 10);
		this.from = from;
		this.to = to;
		this.time = new Date().getTime();
		this.timer = setInterval(this.step.FxBind(this), Math.round(1000/this.options.fps));
		return this;
	},

	custom: function(from, to){
		return this._start(from, to);
	},

	set: function(to){
		this.now = to;
		this.increase();
		return this;
	},

	hide: function(){
		return this.set(0);
	},

	setStyle: function(e, p, v){
		if (p == 'opacity'){
			if (v == 0 && e.style.visibility != "hidden") e.style.visibility = "hidden";
			else if (e.style.visibility != "visible") e.style.visibility = "visible";
			if (window.ActiveXObject){
				if (!e.currentStyle.hasLayout)
					e.style.zoom = "1"; // Give it layout
				e.style.filter = "alpha(opacity=" + v*100 + ")";
			}
			e.style.opacity = v;
		} else e.style[p] = v+this.options.unit;
	}

};

// TJG: Prototype-Lite: Class => Fx.Class
Fx.Class = {
	create: function() {
		return function() {
			this.initialize.apply(this, arguments);
		}
	}
};

Fx.Style = Fx.Class.create();
Fx.Style.prototype = Fx.Extend(new Fx.Base(), {

	initialize: function(el, property, options){
		this.element = Fx.GetElement(el);
		this.setOptions(options);
		this.property = Fx.Camelize(property);
	},

	increase: function(){
		this.setStyle(this.element, this.property, this.now);
	}

});

Fx.Styles = Fx.Class.create();
Fx.Styles.prototype = Fx.Extend(new Fx.Base(), {

	initialize: function(el, options){
		this.element = Fx.GetElement(el);
		this.setOptions(options);
		this.now = {};
	},

	setNow: function(){
		for (p in this.from) this.now[p] = this.compute(this.from[p], this.to[p]);
	},

	custom: function(obj){
		if (this.timer && this.options.wait) return;
		var from = {};
		var to = {};
		for (p in obj){
			from[p] = obj[p][0];
			to[p] = obj[p][1];
		}
		return this._start(from, to);
	},

	increase: function(){
		for (var p in this.now) this.setStyle(this.element, p, this.now[p]);
	}

});

//Transitions (c) 2003 Robert Penner (http://www.robertpenner.com/easing/), BSD License.

Fx.Transitions = {
	linear: function(t, b, c, d) { return c*t/d + b; },
	sineInOut: function(t, b, c, d) { return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; }
};


