/*

unbad object library Copyright © 2006-2010 - Sean Claflin

unbad object library is licensed under the MIT License
http://www.opensource.org/licenses/mit-license.php

*/

(ub.fx = {
	init: function() {
		ub.e.attach(ub, 'unload', function(e) {
			this.destruct();
		}, false, this);
	},
	destruct: function() {
		//clear out our fx stack in reverse order
		ub.a.each(this.stack, function(fx) {
			fx.destruct();
		}, this, true);
	},
	easing: {
		//Open source under the BSD License.
		//Copyright © 2001 Robert Penner All rights reserved.
		//http://www.robertpenner.com/
		//t Time elapsed
		//b Beginning position
		//c Change in position
		//d Duration
		easeNone: function (t, b, c, d) {
			return c*t/d + b;
		},
		easeIn: function (t, b, c, d) {
			return c*(t/=d)*t + b;
		},
		easeOut: function (t, b, c, d) {
			return -c *(t/=d)*(t-2) + b;
		},
		easeInOut: function (t, b, c, d) {
			if ((t/=d/2) < 1) return c/2*t*t + b;
			return -c/2 * ((--t)*(t-2) - 1) + b;
		},
		elasticIn: function (t, b, c, d, a, p) {
			if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
			if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
			else var s = p/(2*Math.PI) * Math.asin (c/a);
			return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
		},
		elasticOut: function (t, b, c, d, a, p) {
			if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
			if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
			else var s = p/(2*Math.PI) * Math.asin (c/a);
			return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
		},
		backIn: function (t, b, c, d, s) {
			if (typeof s == 'undefined') s = 1.70158;
			return c*(t/=d)*t*((s+1)*t - s) + b;
		},
		backOut: function (t, b, c, d, s) {
			if (typeof s == 'undefined') s = 1.70158;
			return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
		},
		backBoth: function (t, b, c, d, s) {
			if (typeof s == 'undefined') s = 1.70158; 
			if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
			return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
		}
	},
	stack: [],
	start: function(block, from, to) {
		if(block.timer) return;
		block.start = new Date().getTime();
		block.from = from;
		block.to = to;
		block.onstart(new ub.e.event('start'));
		block.timer = setInterval(function() {
			ub.fx.step(block);
		}, 10);
	},
	step: function(block) {
		block.now = new Date().getTime();
		if(block.now - block.start >= block.options.duration) {
			block.now = block.start + block.options.duration;
			block.update();
			clearInterval(block.timer);
			block.timer = null;
			block.onupdate(new ub.e.event('update'));
			block.onfinish(new ub.e.event('finish'));
		}
		else {
			block.update();
			block.onupdate(new ub.e.event('update'));
		}
	},
	opacity: function() {
		var opacity = function(node, options) {
			ub.a.append(ub.fx.stack, this);
			this.node = node;
			this.options = ub.u.extend({
				duration: 250,
				minOpacity: 0,
				maxOpacity: 1,
				easing: ub.fx.easing.easeNone
			}, options);
			if(!this.node.style['opacity'])
				ub.n.setOpacity(this.node, this.options.maxOpacity);
		};
		opacity.prototype.destruct = function() {
			ub.a.remove(ub.fx.stack, this);
			this.node = null;
			this.destruct = function() {};
		};
		opacity.prototype.update = function() {
			ub.n.setOpacity(this.node, this.options.easing(
				this.now - this.start,
				this.from,
				this.to - this.from,
				this.options.duration
			));
		};
		opacity.prototype.exposed = function() {
			return ((parseFloat(this.node.style['opacity']) || this.options.minOpacity) > this.options.minOpacity);
		};
		opacity.prototype.expose = function() {
			this.state = 'expose';
			this.onexpose(new ub.e.event('expose'));
			ub.fx.start(this, parseFloat(this.node.style['opacity']) || this.options.minOpacity, this.options.maxOpacity);
		};
		opacity.prototype.conceal = function() {
			this.state = 'conceal';
			this.onconceal(new ub.e.event('conceal'));
			if(this.exposed())
				ub.fx.start(this, parseFloat(this.node.style['opacity']) || this.options.maxOpacity, this.options.minOpacity);
		};
		opacity.prototype.toggle = function() {
			this.ontoggle(new ub.e.event('toggle'));
			if(this.exposed()) this.conceal();
			else this.expose();
		};
		opacity.prototype.hide = function() {
			this.state = 'hide';
			this.onhide(new ub.e.event('hide'));
			ub.n.setOpacity(this.node, this.options.minOpacity);
		};
		opacity.prototype.show = function() {
			this.state = 'show';
			this.onshow(new ub.e.event('show'));
			ub.n.setOpacity(this.node, this.options.maxOpacity);
		};
		opacity.prototype.halt = function() {
			clearInterval(this.timer);
			this.timer = null;
			this.onhalt(new ub.e.event('halt'));
		}
		opacity.prototype.onstart = function(e) {};
		opacity.prototype.onfinish = function(e) {};
		opacity.prototype.onupdate = function(e) {};
		opacity.prototype.onexpose = function(e) {};
		opacity.prototype.onhalt = function(e) {};
		opacity.prototype.onconceal = function(e) {};
		opacity.prototype.ontoggle = function(e) {};
		opacity.prototype.onhide = function(e) {};
		opacity.prototype.onshow = function(e) {};
		return opacity;
	}(),
	height: function() {
		var height = function(node, options) {
			ub.a.append(ub.fx.stack, this);
			this.node = node;
			this.node.style['overflow'] = 'hidden';
			this.options = ub.u.extend({
				duration: 250,
				easing: ub.fx.easing.easeOut
			}, options);
		};
		height.prototype.destruct = function() {
			ub.a.remove(ub.fx.stack, this);
			this.node = null;
			this.destruct = function() {};
		};
		height.prototype.update = function() {
			this.node.style['height'] = this.options.easing(
				(this.now - this.start),
				this.from,
				(this.to - this.from),
				this.options.duration
			) + 'px';
			//this.node.style['height']  = ((this.to - this.from) * percent + this.from) + 'px';;
		};
		height.prototype.exposed = function() {
			return (this.node.offsetHeight > 0);
		};
		height.prototype.expose = function() {
			this.state = 'expose';
			this.onexpose(new ub.e.event('expose'));
			if(this.node.offsetHeight < this.node.scrollHeight) ub.fx.start(this, this.node.offsetHeight, this.node.scrollHeight);
		};
		height.prototype.conceal = function() {
			this.state = 'conceal';
			this.onconceal(new ub.e.event('conceal'));
			if(this.exposed()) ub.fx.start(this, this.node.offsetHeight, 0);
		};
		height.prototype.toggle = function() {
			this.ontoggle(new ub.e.event('toggle'));
			if(this.exposed()) this.conceal();
			else this.expose();
		};
		height.prototype.hide = function() {
			this.state = 'hide';
			this.onhide(new ub.e.event('hide'));
			this.node.style['height'] = '0px';
		};
		height.prototype.show = function() {
			this.state = 'show';
			this.onshow(new ub.e.event('show'));
			this.node.style['height'] = this.node.scrollHeight +'px';
		};
		height.prototype.halt = function() {
			clearInterval(this.timer);
			this.timer = null;
			this.onhalt(new ub.e.event('halt'));
		}
		height.prototype.onstart = function(e) {};
		height.prototype.onfinish = function(e) {};
		height.prototype.onupdate = function(e) {};
		height.prototype.onhalt = function(e) {};
		height.prototype.onexpose = function(e) {};
		height.prototype.onconceal = function(e) {};
		height.prototype.ontoggle = function(e) {};
		height.prototype.onhide = function(e) {};
		height.prototype.onshow = function(e) {};
		return height;
	}(),
	width: function() {
		var width = function(node, options) {
			ub.a.append(ub.fx.stack, this);
			this.node = node;
			this.node.style['overflow'] = 'hidden';
			this.options = ub.u.extend({
				duration: 250,
				easing: ub.fx.easing.easeOut
			}, options);
		};
		width.prototype.destruct = function() {
			ub.a.remove(ub.fx.stack, this);
			this.node = null;
			this.destruct = function() {};
		};
		width.prototype.update = function() {
			this.node.style['width'] = this.options.easing(
				(this.now - this.start),
				this.from,
				(this.to - this.from),
				this.options.duration
			) + 'px';
			//this.node.style['width']  = ((this.to - this.from) * percent + this.from) + 'px';;
		};
		width.prototype.exposed = function() {
			return (this.node.offsetWidth > 0);
		};
		width.prototype.expose = function() {
			this.state = 'expose';
			this.onexpose(new ub.e.event('expose'));
			if(!this.exposed()) ub.fx.start(this, 0, this.node.scrollWidth);
		};
		width.prototype.conceal = function() {
			this.state = 'conceal';
			this.onconceal(new ub.e.event('conceal'));
			if(this.exposed()) ub.fx.start(this, this.node.offsetWidth, 0);
		};
		width.prototype.toggle = function() {
			this.ontoggle(new ub.e.event('toggle'));
			if(this.exposed()) this.conceal();
			else this.expose();
		};
		width.prototype.hide = function() {
			this.state = 'hide';
			this.onhide(new ub.e.event('hide'));
			this.node.style['width'] = '0px';
		};
		width.prototype.show = function() {
			this.state = 'show';
			this.onshow(new ub.e.event('show'));
			this.node.style['width'] = this.node.scrollWidth +'px';
		};
		width.prototype.halt = function() {
			clearInterval(this.timer);
			this.timer = null;
			this.onhalt(new ub.e.event('halt'));
		}
		width.prototype.onstart = function(e) {};
		width.prototype.onfinish = function(e) {};
		width.prototype.onupdate = function(e) {};
		width.prototype.onhalt = function(e) {};
		width.prototype.onexpose = function(e) {};
		width.prototype.onconceal = function(e) {};
		width.prototype.ontoggle = function(e) {};
		width.prototype.onhide = function(e) {};
		width.prototype.onshow = function(e) {};
		return width;
	}(),
	size: function() {
		var size = function(node, options) {
			ub.a.append(ub.fx.stack, this);
			this.node = node;
			this.options = ub.u.extend({
				duration: 250,
				minHeight: 0,
				maxHeight: this.node.clientHeight,
				minWidth: 0,
				maxWidth: this.node.clientWidth,
				easing: ub.fx.easing.easeOut
			}, options);
		};
		size.prototype.destruct = function() {
			ub.a.remove(ub.fx.stack, this);
			this.halt();
			this.node = null;
			this.destruct = function()  {};
		};
		size.prototype.update = function() {
			this.node.style['width'] = this.options.easing(
				(this.now - this.start),
				this.from[0],
				(this.to[0] - this.from[0]),
				this.options.duration
			) + 'px';
			this.node.style['height'] = this.options.easing(
				(this.now - this.start),
				this.from[1],
				(this.to[1] - this.from[1]),
				this.options.duration
			) + 'px';
		};
		size.prototype.exposed = function() {
			return (
				parseInt(this.node.style['height']) > minHeight ||
				parseInt(this.node.style['width']) > minWidth
			);
		};
		size.prototype.expose = function() {
			this.state = 'expose';
			this.onexpose(new ub.e.event('expose'));
			var from = [
				parseInt(this.node.style['width']) || 0,
				parseInt(this.node.style['height']) || 0
			];
			var to = [
				this.options.maxWidth,
				this.options.maxHeight
			];
			ub.fx.start(this, from, to);
		};
		size.prototype.conceal = function() {
			this.state = 'conceal';
			this.onconceal(new ub.e.event('conceal'));
			var from = [
				parseInt(this.node.style['width']) || 0,
				parseInt(this.node.style['height']) || 0
			];
			var to = [
				this.options.minWidth,
				this.options.minHeight
			];
			ub.fx.start(this, from, to);
		};
		size.prototype.hide = function() {
			this.state = 'hide';
			this.onhide(new ub.e.event('hide'));
			this.node.style['width'] = this.options.minWidth +'px';
			this.node.style['height'] = this.options.minHeight +'px';
		};
		size.prototype.show = function() {
			this.state = 'show';
			this.onshow(new ub.e.event('show'));
			this.node.style['width'] = this.options.maxWidth +'px';
			this.node.style['height'] = this.options.maxHeight +'px';
		};
		size.prototype.halt = function() {
			clearInterval(this.time);
			this.timer = null;
			this.onhalt(new ub.e.event('halt'));
		};
		size.prototype.onstart = function(e) {};
		size.prototype.onupdate = function(e) {};
		size.prototype.onfinish = function(e) {};
		size.prototype.onhalt = function(e) {};
		size.prototype.onexpose = function(e) {};
		size.prototype.onconceal = function(e) {};
		size.prototype.onhide = function(e) {};
		size.prototype.onshow = function(e) {};
		return size;
	}(),
	position: function(node, options) {
		var position = function(node, options) {
			ub.a.append(ub.fx.stack, this);
			this.node = node;
			if(!this.node.style['position'])
				this.node.style['position'] = 'absolute';
			this.options = ub.u.extend({
				duration: 250,
				easing: ub.fx.easing.backBoth,
				x_style: 'left',
				y_style: 'top'
			}, options);
		};
		position.prototype.destruct = function() {
			ub.a.remove(ub.fx.stack, this);
			this.halt();
			this.node = null;
			this.destruct = function() {};
		};
		position.prototype.update = function() {
			this.node.style[this.options.x_style] = this.options.easing(
				(this.now - this.start),
				this.from[0],
				(this.to[0] - this.from[0]),
				this.options.duration
			) + 'px';
			this.node.style[this.options.y_style] = this.options.easing(
				(this.now - this.start),
				this.from[1],
				(this.to[1] - this.from[1]),
				this.options.duration
			) + 'px';
		};
		position.prototype.move = function(to, from) {
			this.state = 'move';
			if(!from) from = [
				parseInt(this.node.style[this.options.x_style]),
				parseInt(this.node.style[this.options.y_style])
			];
			ub.fx.start(this, from, to);
		};
		position.prototype.jump = function(to) {
			this.state = 'jump';
			this.node.style[this.options.x_style] = to[0] +'px';
			this.node.style[this.options.y_style] = to[1] +'px';
			this.onjump(new ub.e.event('jump'));
		}
		position.prototype.halt = function() {
			clearInterval(this.timer);
			this.timer = null;
			this.onhalt(new ub.e.event('halt'));
		}
		position.prototype.onstart = function(e) {};
		position.prototype.onfinish = function(e) {};
		position.prototype.onhalt = function(e) {};
		position.prototype.onupdate = function(e) {};
		position.prototype.onjump = function(e) {};
		return position;
	}(),
	scroll: function(node, options) {
		var scroll = function(node, options) {
			ub.a.append(ub.fx.stack, this);
			this.node = node;
			this.options = ub.u.extend({
				duration: 500,
				easing: ub.fx.easing.easeOut
			}, options);
		};
		scroll.prototype.destruct = function() {
			ub.a.remove(ub.fx.stack, this);
			this.halt();
			this.node = null;
			this.destruct = function() {};
		};
		scroll.prototype.update = function() {
			this.node.scrollLeft = this.options.easing(
				(this.now - this.start),
				this.from[0],
				(this.to[0] - this.from[0]),
				this.options.duration
			);
			this.node.scrollTop = this.options.easing(
				(this.now - this.start),
				this.from[1],
				(this.to[1] - this.from[1]),
				this.options.duration
			);
		};
		scroll.prototype.move = function(to, from) {
			this.state = 'move';
			if(!from) from = [
				parseInt(this.node.scrollLeft),
				parseInt(this.node.scrollTop)
			];
			ub.fx.start(this, from, to);
		};
		scroll.prototype.halt = function() {
			clearInterval(this.timer);
			this.timer = null;
			this.onhalt(new ub.e.event('halt'));
		}
		scroll.prototype.onstart = function(e) {};
		scroll.prototype.onfinish = function(e) {};
		scroll.prototype.onhalt = function(e) {};
		scroll.prototype.onupdate = function(e) {};
		return scroll;
	}(),
	slide: function(node, options) {
		var slide = function(node, options) {
			ub.a.append(ub.fx.stack, this);
			this.node = node;
			//clone our node
			this.container = this.node.cloneNode(false);
			
			//force some styles
			this.container.style['border'] = 'none';
			this.container.style['overflow'] = 'hidden';
			this.container.style['padding'] = '0px';
			this.container.style['background'] = 'transparent';
			ub.n.setDims(this.container, ub.n.getDims(this.node));
			this.node.style['position'] = 'relative';
			this.node.style['margin'] = '0px';
			this.node.style['top'] = '0px';
			this.node.style['left'] = '0px';
			
			//insert the container just before our node
			this.node.parentNode.insertBefore(this.container, this.node);
			
			//stuff the node inside the container
			this.container.appendChild(this.node);
			this.options = ub.u.extend({
				duration: 500,
				easing: ub.fx.easing.easeOut
			}, options);
		};
		slide.prototype.destruct = function() {
			ub.a.remove(ub.fx.stack, this);
			this.node = null;
			this.container = null;
			this.destruct = function() {};
		};
		slide.prototype.update = function(percent) {
			this.node.style['left'] = this.options.easing(
				(this.now - this.start),
				this.from[0],
				(this.to[0] - this.from[0]),
				this.options.duration
			) + 'px';
			this.node.style['top'] = this.options.easing(
				(this.now - this.start),
				this.from[1],
				(this.to[1] - this.from[1]),
				this.options.duration
			) + 'px';
			ub.n.setDims(this.container, ub.n.getDims(this.node));
		};
		slide.prototype.exposed = function() {
			var coords = ub.n.getCoords(this.node);
			var dims = ub.n.getDims(this.node);
			return (
				coords[0] > -dims[0] &&
				coords[0] < dims[0] &&
				coords[1] > -dims[1] &&
				coords[1] < dims[1]
			);
		};
		slide.prototype.inLeft = function() {
			this.oninleft(new ub.e.event('inleft'));
			var dims = ub.n.getDims(this.node);
			ub.fx.start(this, [-dims[0], 0], [0,0]);
			this.state = 'in';
			this.dir = 'left';
		};
		slide.prototype.outLeft = function() {
			this.onoutleft(new ub.e.event('outleft'));
			var coords = ub.n.getCoords(this.node);
			var dims = ub.n.getDims(this.node);
			ub.fx.start(this, coords, [-dims[0], 0]);
			this.state = 'out';
			this.dir = 'left';
		};
		slide.prototype.toggleLeft = function() {
			this.ontoggleleft(new ub.e.event('toggleleft'));
			if(this.exposed()) this.outLeft();
			else this.inLeft();
		};
		slide.prototype.inRight = function() {
			this.oninright(new ub.e.event('inright'));
			var dims = ub.n.getDims(this.node);
			ub.fx.start(this, [dims[0], 0], [0,0]);
			this.state = 'in';
			this.dir = 'right';
		};
		slide.prototype.outRight = function() {
			this.onoutright(new ub.e.event('outright'));
			var coords = ub.n.getCoords(this.node);
			var dims = ub.n.getDims(this.node);
			ub.fx.start(this, coords, [dims[0], 0]);
			this.state = 'out';
			this.dir = 'right';
		};
		slide.prototype.toggleRight = function() {
			this.ontoggleright(new ub.e.event('toggleright'));
			if(this.exposed()) this.outRight();
			else this.inRight();
		};
		slide.prototype.inTop = function() {
			this.onintop(new ub.e.event('intop'));
			var dims = ub.n.getDims(this.node);
			ub.fx.start(this, [0, -dims[1]], [0,0]);
			this.state = 'in';
			this.dir = 'top';
		};
		slide.prototype.outTop = function() {
			this.onouttop(new ub.e.event('outtop'));
			var coords = ub.n.getCoords(this.node);
			var dims = ub.n.getDims(this.node);
			ub.fx.start(this, coords, [0,-dims[1]]);
			this.state = 'out';
			this.dir = 'top';
		};
		slide.prototype.toggleTop = function() {
			this.ontoggletop(new ub.e.event('toggletop'));
			if(this.exposed()) this.outTop();
			else this.inTop();
		};
		slide.prototype.inBottom = function() {
			this.oninbottom(new ub.e.event('inbottom'));
			var dims = ub.n.getDims(this.node);
			ub.fx.start(this, [0, dims[1]], [0,0]);
			this.state = 'in';
			this.dir = 'bottom';
		};
		slide.prototype.outBottom = function() {
			this.onoutbottom(new ub.e.event('outbottom'));
			var coords = ub.n.getCoords(this.node);
			var dims = ub.n.getDims(this.node);
			ub.fx.start(this, coords, [0,dims[1]]);
			this.state = 'out';
			this.dir = 'bottom';
		};
		slide.prototype.toggleBottom = function() {
			this.ontogglebottom(new ub.e.event('togglebottom'));
			if(this.exposed()) this.outBottom();
			else this.inBottom();
		};
		slide.prototype.halt = function() {
			clearInterval(this.timer);
			this.timer = null;
			this.onhalt(new ub.e.event('halt'));
		}
		slide.prototype.oninleft = function(e) {};
		slide.prototype.onoutleft = function(e) {};
		slide.prototype.ontoggleleft = function(e) {};
		slide.prototype.oninright = function(e) {};
		slide.prototype.onoutright = function(e) {};
		slide.prototype.ontoggleright = function(e) {};
		slide.prototype.onintop = function(e) {};
		slide.prototype.onouttop = function(e) {};
		slide.prototype.ontoggletop = function(e) {};
		slide.prototype.oninbottom = function(e) {};
		slide.prototype.onoutbottom = function(e) {};
		slide.prototype.ontogglebottom = function(e) {};
		slide.prototype.onhalt = function(e) {};
		slide.prototype.onstart = function(e) {};
		slide.prototype.onfinish = function(e) {};
		slide.prototype.onupdate = function(e) {};
		return slide;
	}(),
	count: function(node, options) {
		var count = function(node, options) {
			ub.a.append(ub.fx.stack, this);
			this.node = node;
			this.options = ub.u.extend({
				currentValue: 0,
				duration: 1000,
				easing: ub.fx.easing.easeOut,
				decimals: 2,
				thousandsSeparator: ','
			}, options);
		};
		count.prototype.destruct = function() {
			ub.a.remove(ub.fx.stack, this);
			this.node = null;
			this.destruct = function() {};
		};
		count.prototype.update = function() {
			this.options.currentValue = this.options.easing(
				(this.now - this.start),
				this.from,
				(this.to - this.from),
				this.options.duration
			);
			this.node.innerHTML = ub.u.formatNumber(
				this.options.currentValue,
				this.options.decimals,
				this.options.thousandsSeparator
			);
		};
		count.prototype.tick = function(to, from) {
			to = parseFloat(to) || 0;
			from = parseFloat(from);
			this.state = 'tick';
			this.ontick(new ub.e.event('tick'));
			ub.fx.start(this, 
				(from || from == 0) ? from : this.options.currentValue,
				to
			);
		};
		count.prototype.halt = function() {
			clearInterval(this.timer);
			this.timer = null;
			this.onhalt(new ub.e.event('halt'));
		};
		count.prototype.onstart = function(e) {};
		count.prototype.ontick = function(e) {};
		count.prototype.onupdate = function(e) {};
		count.prototype.onfinish = function(e) {};
		count.prototype.onhalt = function(e) {};
		return count;
	}()
}).init();

