var TRANSITION = {

    // t = time
    // b = beginn
    // c = change
    // d = duration
    
    Sine: {
        'easeIn': function(t, b, c, d){
            return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;
        },
        'easeOut': function(t, b, c, d){
            return c * Math.sin(t / d * (Math.PI / 2)) + b;
        },
        'easeInOut': function(t, b, c, d){
            return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;
        }
    },
    Quint: {
        'easeIn': function(t, b, c, d){
            return c * (t /= d) * t * t * t * t + b;
        },
        'easeOut': function(t, b, c, d){
            return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
        },
        'easeInOut': function(t, b, c, d){
        
            if ((t /= d / 2) < 1) 
                return c / 2 * t * t * t * t * t + b;
            return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
            
        }
    },
    Quart: {
        'easeIn': function(t, b, c, d){
            return c * (t /= d) * t * t * t + b;
        },
        'easeOut': function(t, b, c, d){
            return -c * ((t = t / d - 1) * t * t * t - 1) + b;
        },
        'easeInOut': function(t, b, c, d){
        
            if ((t /= d / 2) < 1) 
                return c / 2 * t * t * t * t + b;
            return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
            
        }
    },
    Quad: {
        '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;
        }
    },
    Linear: {
        'easeIn': function(t, b, c, d){
            return c * t / d + b;
        },
        'easeOut': function(t, b, c, d){
            return c * t / d + b;
        },
        'easeInOut': function(t, b, c, d){
            return c * t / d + b;
        }
    },
    Expo: {
        'easeIn': function(t, b, c, d){
            return (t == 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b;
        },
        'easeOut': function(t, b, c, d){
            return (t == d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b;
        },
        'easeInOut': function(t, b, c, d){
            if (t == 0) 
                return b;
            if (t == d) 
                return b + c;
            if ((t /= d / 2) < 1) 
                return c / 2 * Math.pow(2, 10 * (t - 1)) + b;
            return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b;
        }
    },
    Elastic: {
        'easeIn': 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;
        },
        'easeOut': 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);
        },
        'easeInOut': function(t, b, c, d, a, p){
            if (t == 0) 
                return b;
            if ((t /= d / 2) == 2) 
                return b + c;
            if (!p) 
                p = d * (.3 * 1.5);
            if (!a || a < Math.abs(c)) {
                a = c;
                var s = p / 4;
            }
            else 
                var s = p / (2 * Math.PI) * Math.asin(c / a);
            if (t < 1) 
                return -.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
            return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
        }
    },
    Cubic: {
        'easeIn': function(t, b, c, d){
            return c * (t /= d) * t * t + b;
        },
        'easeOut': function(t, b, c, d){
            return c * ((t = t / d - 1) * t * t + 1) + b;
        },
        'easeInOut': function(t, b, c, d){
            if ((t /= d / 2) < 1) 
                return c / 2 * t * t * t + b;
            return c / 2 * ((t -= 2) * t * t + 2) + b;
        }
    },
    Circ: {
        'easeIn': function(t, b, c, d){
            return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b;
        },
        'easeOut': function(t, b, c, d){
            return c * Math.sqrt(1 - (t = t / d - 1) * t) + b;
        },
        'easeInOut': function(t, b, c, d){
            if ((t /= d / 2) < 1) 
                return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b;
            return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b;
        }
    },
    Bounce: {
        'easeOut': function(t, b, c, d){
            if ((t /= d) < (1 / 2.75)) {
                return c * (7.5625 * t * t) + b;
            }
            else 
                if (t < (2 / 2.75)) {
                    return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
                }
                else 
                    if (t < (2.5 / 2.75)) {
                        return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
                    }
                    else {
                        return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
                    }
        },
        'easeIn': function(t, b, c, d){
            return c - Bounce.easeOut(d - t, 0, c, d) + b;
        },
        'easeInOut': function(t, b, c, d){
            if (t < d / 2) 
                return Bounce.easeIn(t * 2, 0, c, d) * .5 + b;
            else 
                return Bounce.easeOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
            
        }
    },
    Back: {
        'easeIn': function(t, b, c, d, s){
            if (s == undefined) 
                s = 1.70158;
            return c * (t /= d) * t * ((s + 1) * t - s) + b;
        },
        'easeOut': function(t, b, c, d, s){
            if (s == undefined) 
                s = 1.70158;
            return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
        },
        'easeInOut': function(t, b, c, d, s){
            if (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;
        }
    }
};

function Animation (o) {
	
	var obj = o.obj,
		type = o.type,
		duration = o.duration || 2000,
		transition = o.transition || TRANSITION.Quart.easeOut,
		callback = o.callback || function(){},
		startTime = null,
		animate = false,
		r,
		r1,
		g1,
		b1,
		r2,
		g2,
		b2;
	
	switch (type) {
			case 'move':
				var startTop = o.startTop || obj.offsetTop,
					startLeft = o.startLeft || obj.offsetLeft,
					targetTop = typeof o.targetTop != 'undefined' ? o.targetTop : null;
					targetLeft = typeof o.targetLeft != 'undefined' ? o.targetLeft : null;		
				break;
			case 'resize':
				var startWidth = o.startWidth || getObjSize(obj).width,
					startHeight = o.startHeight || getObjSize(obj).height,
					targetWidth = o.targetWidth || null,
					targetHeight = o.targetHeight || null;
				break;
			case 'opacity':
				var startOpacity = o.startOpacity || getObjOpacity(obj),
					targetOpacity = o.targetOpacity || 0;
				break;
			case 'color':
				var colorAttribute = o.colorAttribute || 'backgroundColor',
					startColor = o.startColor || getStyle(obj,colorAttribute),
					targetColor = o.targetColor || null;
				break;
	}
	
	if (startColor != null) startColor = startColor.replace(/#/,'').toUpperCase();
	if (targetColor != null) targetColor = targetColor.replace(/#/,'').toUpperCase();
	
	this.start = function () {
		animate = true;
		startTime = getTime();
		try {
			left = startLeft;
			top = startTop;
		}catch(err){}
		switch (type) {
			case 'move':
				move();
				break;
			case 'resize':
				resize();
				break;
			case 'opacity':
				opacity();
				break;
			case 'color':
				r1 = hex2dec(startColor.slice(0,2));
			    g1 = hex2dec(startColor.slice(2,4));
			    b1 = hex2dec(startColor.slice(4,6));
			    r2 = hex2dec(targetColor.slice(0,2));
			    g2 = hex2dec(targetColor.slice(2,4));
			    b2 = hex2dec(targetColor.slice(4,6));
				color();
				break;
		}
	}
	function move () {
		
		var time = getTime(),
			delta = 0;
			
		if (!animate) return;
		
		if ((time - startTime) <= duration) {
			r = (time - startTime);
			if (targetLeft != null) {
				delta = transition(r, startLeft, (targetLeft-startLeft), duration);
				obj.style.left=delta+'px';
			}
			if (targetTop != null) {
				delta = transition(r, startTop, (targetTop-startTop), duration);
				obj.style.top=delta+'px';
			}
			setTimeout(move, 0);
		} else {
			if (targetLeft != null)obj.style.left=targetLeft+'px';
			if (targetTop != null)obj.style.top=targetTop+'px';
			animate = false;
			callback();
		}
	}
	function resize () {
		
		var time = getTime(),
			delta = 0;
			
		if (!animate) return;
		
		if ((time - startTime) <= duration) {
			r = (time - startTime);
			if (targetWidth != null) {
				delta = transition(r, startWidth, (targetWidth-startWidth), duration);
				obj.style.width=delta+'px';
			}
			if (targetHeight != null) {
				delta = transition(r, startHeight, (targetHeight-startHeight), duration);
				obj.style.height=delta+'px';
			}
			setTimeout(resize, 0);
		} else {
			if (targetWidth != null) obj.style.width = targetWidth+'px';
			if (targetHeight != null) obj.style.height = targetHeight+'px';
			animate = false;
			callback();
		}
	}
	function opacity () {
		
		var time = getTime(),
			delta = 0;
			
		if ((time - startTime) <= duration) {
			r = (time - startTime);
			delta = transition(r, startOpacity, (targetOpacity-startOpacity), duration);
			obj.style['opacity'] = delta / 100;
			obj.style['-moz-opacity'] = delta / 100;
			obj.style.filter = 'alpha(opacity=' + delta + ')';
			setTimeout(opacity, 0);
		} else {
			obj.style['opacity'] = targetOpacity/100;
			obj.style['-moz-opacity'] = targetOpacity/100;
			obj.style.filter = 'alpha(opacity=' + targetOpacity + ')';
			animate = false;
			callback();
		}
	}
	function color () {
		
		var time = getTime(),
			delta = 0,
			pc;
			
		if ((time - startTime) <= duration) {
			r = (time - startTime);
			delta = transition(r, 0, 100, duration);
			
		    pc = delta/100;
		
		    r = Math.floor(r1+(pc*(r2-r1)) + .5);
		    g = Math.floor(g1+(pc*(g2-g1)) + .5);
		    b = Math.floor(b1+(pc*(b2-b1)) + .5);
			
			obj.style[colorAttribute] = '#' + dec2hex(r) + dec2hex(g) + dec2hex(b);
			setTimeout(color, 0);
		} else {
			obj.style[colorAttribute] = '#' + targetColor;
			animate = false;
			callback();
		}
	}
	
	function getTime () {
		return new Date().getTime();
	}
	function getObjPos  (o) {
		if (!o || o == null) return;
		var elem=o,tagname='',t=0,l=0;
	  	try {
			while ((typeof(elem)=='object')&&(typeof(elem.tagName)!='undefined')) {
				t+=elem.offsetTop;
				l+=elem.offsetLeft;
				tagname=elem.tagName.toUpperCase();
				if (tagname=='BODY') elem=0;
				if (typeof(elem)=='object')
					if (typeof(elem.offsetParent)=='object')
						elem=elem.offsetParent;
			}
		} catch (err) {}
		return {'top':t,'left':l};
	}
	function getObjSize (o) {
		return(o)?{'width':parseInt(o.offsetWidth),'height':parseInt(o.offsetHeight)}:0;
	}
	function getObjOpacity (o) {
		try {
			if (o.style.opacity) op = o.style.opacity*100;
			if (o.style.MozOpacity) op = o.style.MozOpacity*100;
			if (o.filters) op = o.filters.alpha.opacity;
		} catch (err) {
			op=100;
		}
		if (typeof op=='undefined')op=100;
		return op;
	}
	function dec2hex (dec){
		var hexDigit = ["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"];
		return(hexDigit[dec>>4]+hexDigit[dec&15]);
	}
	function hex2dec (hex){
		return parseInt(hex,16);
	}
	function getStyle (o,s) {
		if (o.currentStyle)
			return o.currentStyle[s];
		else if (window.getComputedStyle)
			return document.defaultView.getComputedStyle(o,null).getPropertyValue(s);
		else return null;
    }
}
