Fx.Rainbow = Fx.Style.extend({
	options: {
		transition: function(p, d) {
			p = (p + d) % .4;
			var m = 10, yint = 0;
			if(p > .2) {
				m = -10, yint = 3;
			}
			return (255*(m * p + yint)).limit(0,255);
		},
		duration: 40000
	},
	
	initialize: function(el, property, options) {
		this.parent(el, property, options);
		this.disp = 0;
		this.delta = [];
	},
	
	step: function() {
		var time = $time(), p;
		if (time < this.time + this.options.duration) {
			p = (time - this.time) / this.options.duration;
			this.delta[0] = this.options.transition(p, 0.1 + this.disp);
			this.delta[1] = this.options.transition(p, 0.0 + this.disp);
			this.delta[2] = this.options.transition(p, 0.3 + this.disp);
			this.setNow();
			this.increase();
		} else {
			this.stop(true);
			this.fireEvent('onComplete', this.element, 10);
			this.callChain();	
		}	
	},
	
	setNow: function() {
		var now = [];
		for (var i = 0, j = this.from.length; i < j; i++) {
			now[i] = Math.round(this.compute(i));
		}
		this.now = now;
	},
	
	compute: function(i) {
		return this.delta[i];
	},
	
	increase: function() {
		this.element.setStyle(this.property, Fx.CSS.Color.getValue(this.now));
	},
	
	stop: function(end) {
		this.parent(end);
	},
	
	start: function(from) {
		if(!this.options.wait) this.stop();
		else if (this.timer) return this;
		this.from = Fx.CSS.Color.parse(from || '#00f');
		this.time = $time();
		this.timer = this.step.periodical(Math.round(1000 / this.options.fps), this);
		this.fireEvent('onStart', this.element);
		return this;
	},
	
	set: function(to) {
		to = Fx.CSS.Color.parse(to);
		for(var i = 0, iter = 1 / this.options.duration; i < 1; i += iter) {
			if(
				to[0] == Math.round(this.options.transition(i, 0.1)) &&
				to[1] == Math.round(this.options.transition(i, 0.0)) &&
				to[2] == Math.round(this.options.transition(i, 0.3))
			) {
				this.disp = i;
				break;
			}
		}
		
		return this.parent(to);
	}
});