//(c) 2006 Valerio Proietti (http://mad4milk.net). MIT-style license.
//moo.fx.js - depends on prototype.js OR prototype.lite.js
//version 2.0

var Fx = fx = {};

Fx.Base = function(){};
Fx.Base.prototype = {
	
	log:		[],
	
	inputType: 'px',

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

	step: function(){
		//alert('step: '+this.inputType);
		var time = new Date().getTime();
		//this.log.push(this.inputType);
		if (time < this.time + this.options.duration){
			this.cTime = time - this.time;
			this.log.push(this.inputType);
			if (this.inputType == 'hex'){this.log.push('calling setNow');}
			this.setNow();
			
			
		} else {
			setTimeout(this.options.onComplete.bind(this.options.context, this.element), 10);
			this.clearTimer();
			if (this.inputType == 'hex'){
				var value =  {};
				for (p in this.to){
					//alert('step2: '+this.inputType);
					value[p] = Utils.dec2hex(this.to[p]);
					//alert ('value (hex): '+value[p]);
					this.now[p] = value[p].substr(0,7);
					//alert('this.now (hex): '+this.now[p]);
				}
			}else{
				this.now = this.to;
				//alert('this.now (px): '+this.now);
			}
		}
		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);
	},
	
	computeHex: function(from,to){		
		var fromChannels = {r:from.substr(1,2),g:from.substr(3,4),b:from.substr(5,6)};
		var toChannels ={r:to.substr(1,2),g:to.substr(3,4),b:to.substr(5,6)};
		var nowChannels = {r:'',g:'',b:''};
		var hexValue = null;
		for (p in fromChannels){
			//this.log.push('toChannels.r: '+toChannels.r+' ');
			from = Utils.hex2dec(fromChannels[p]);
			//this.log.push('from: '+from+' ');
			to = Utils.hex2dec(toChannels[p]);
			//this.log.push('to: '+to+' ');
			nowChannels[p] = Utils.dec2hex(this.compute(from, to));
			nowChannels[p] = nowChannels[p].substr(0,1);
			//this.log.push('nowChannels[p]: '+nowChannels[p]+' ');
		}

			hexValue = '#'+nowChannels.r+nowChannels.g+nowChannels.b;
			//this.log.push('hexValue: '+hexValue+' ');
			//this.log.push('nowChannels.r: '+nowChannels.r+' ');
			return hexValue;
	},

	clearTimer: function(){
		clearInterval(this.timer);
		this.timer = null;
		return this;
	},
	
	detectFormat: function(from,to){
		var hex = /#/;
		var px = /px/;
		
		for (p in from){
			var inputString = String(from[p]);
			if (inputString.search(hex) != -1) {this.inputType = 'hex';this.options.unit='';}
			if (inputString.search(px) != -1) {this.inputType = 'px';}
		}
	},

	_start: function(from, to){
		if (!this.options.wait) this.clearTimer();
		if (this.timer) return;
		setTimeout(this.options.onStart.bind(this.options.context, this.element), 10);
		
		this.detectFormat(from,to);
		//alert(this.inputType);
		this.from = from;
		this.to = to;
		
		this.time = new Date().getTime();
		this.timer = setInterval(this.step.bind(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) e.style.filter = "alpha(opacity=" + v*100 + ")";
			e.style.opacity = v;
		} else {e.style[p] = v+this.options.unit;}
		//alert(e.style.backgroundColor);
		
	}

};

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

	initialize: function(el, property, options){
		this.element = $(el);
		this.setOptions(options);
		this.property = property.camelize();
	},

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

});

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

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

	setNow: function(){ //overrides base class
		if (this.inputType == 'px') {
			for (p in this.from) {this.now[p] = this.compute(this.from[p], this.to[p]);}
		} else if (this.inputType == 'hex') {
			//this.log.push('setNow: '+this.inputType);
			for (p in this.from) {this.now[p] = this.computeHex(this.from[p], this.to[p]);}
		}
	},

	custom: function(obj){//overrides base class
		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];
			//alert("custom:: from[p] = "+from[p]+" to[p] = "+to[p]);
		}
		return this._start(from, to);
	},

	increase: function(){ //overrides base class
		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) {
		//alert ('transition b = '+b);
		return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b; }
};

/*
custom()
._start() sets this.timer = setInterval(step)

step() calls setNow()

setNow() sets this.now = compute(from, to) --(#)

setNow() calls increase()

increase() calls setStyle()

*/
