var getBrowser = function() {
	var userAgent = navigator.userAgent.toLowerCase();
	if (/webkit/.test( userAgent )) {
		return "safari";
	}
	if (/opera/.test( userAgent )) {
		return "opera";
	}
	if (/msie/.test( userAgent ) && !/opera/.test( userAgent )) {
		return "msie";
	}
	if (/mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent )) {
		return "mozilla";
	}
};

var getBrowserVersion = function() {
	var userAgent = navigator.userAgent.toLowerCase();
	return (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1];
};

//borrowed from jQuery (jQuery.com)
// A helper method for determining if an element's values are broken
function color( elem ) {
	if (getBrowser() != "safari")
		return false;

	var defaultView = document.defaultView || {};
	// defaultView is cached
	var ret = defaultView.getComputedStyle( elem, null );
	return !ret || ret.getPropertyValue("color") == "";
}

var hasClass = function(element, className) {
	var array = (element.className || element).toString().split(/\s+/);
	
	var j=-1;
	for (var i=0;i<array.length;i++) {
		if (array[i] === className) {
			j=i;
		}
	}
	return (j > -1);
}

var removeClass = function(element, className) {
	var arr = (element.className || element).toString().split(/\s+/);
	
	var newArr = new Array();
	var j = 0;
	for (var i=0;i<arr.length;i++) {
		if (arr[i] != className) {
			newArr[j] = arr[i];
			j++;
		}
	}
	element.className = newArr.join(" ");
}

var addClass = function(element, className) {
	if (!hasClass(element,className)) {
		element.className += (element.className ? " " : "") + className;
	}
}

var searchChilds = function(element, childClassName, level, maxLevel) {
	maxLevel = maxLevel || 0;
	level = level || 0;
	
	var childs = new Array();
	for(var i=0;i<element.childNodes.length;i++) {
		if (hasClass(element.childNodes[i],childClassName)) {
			childs.push(element.childNodes[i]);
		}
		if (element.childNodes[i].childNodes.length > 0 && (maxLevel == 0 || level < maxLevel)) {
			childs = childs.concat(searchChilds(element.childNodes[i],childClassName,level+1,maxLevel));
		}
	}
	return childs;
}

var searchChildsByTagName = function(element, childTagName, level, maxLevel) {
	maxLevel = maxLevel || 0;
	level = level || 0;
	
	var childs = new Array();
	for(var i=0;i<element.childNodes.length;i++) {
		if (element.childNodes[i].tagName == childTagName) {
			childs.push(element.childNodes[i]);
		}
		if (element.childNodes[i].childNodes.length > 0 && (maxLevel == 0 || level < maxLevel)) {
			childs = childs.concat(searchChildsByTagName(element.childNodes[i],childTagName,level+1,maxLevel));
		}
	}
	return childs;
}

function getStyleValue(elem, prop, force) {
	var ret, style = elem.style;
	
	
	if (prop == "opacity" && getBrowser() == "msie") {
		return style.filter && style.filter.indexOf("opacity=") >= 0 ?
			(parseFloat( style.filter.match(/opacity=([^)]*)/)[1] ) / 100) + '':
			"";
	} else {
		
		var defaultView = document.defaultView || {};
		
		if ( !force && style && style[ prop ] ) {
			ret = style[ prop ];
		
		} else if ( defaultView.getComputedStyle ) {
			var computedStyle = defaultView.getComputedStyle( elem, null );

			
			if ( computedStyle && !color( prop ) ) {
				
				ret = computedStyle.getPropertyValue( prop );
				
			} else {
				
				var swap = [], stack = [], a = elem, i = 0;
				
				// Locate all of the parent display: none elements
				for ( ; a && color(a); a = a.parentNode )
					stack.unshift(a);

					
				// Go through and make them visible, but in reverse
				// (It would be better if we knew the exact display type that they had)
				for ( ; i < stack.length; i++ )
					if ( color( stack[ i ] ) ) {
						swap[ i ] = stack[ i ].style.display;
						stack[ i ].style.display = "block";
					}

				// Since we flip the display style, we have to handle that
				// one special, otherwise get the value
				ret = prop == "display" && swap[ stack.length - 1 ] != null ?
					"none" :
					( computedStyle && computedStyle.getPropertyValue( prop ) ) || "";

				// Finally, revert the display styles back
				for ( i = 0; i < swap.length; i++ )
					if ( swap[ i ] != null )
						stack[ i ].style.display = swap[ i ];
			}
		} else if ( elem.currentStyle ) {
			ret = elem.currentStyle[ prop ];
		}
		
		return ret;
	}
}

function setStyleValue(elem, prop, value) {	
	if (prop == "opacity" && getBrowser() == "msie") {
		elem.style.zoom=1;
		elem.style.filter = (elem.style.filter || "").replace( /alpha\([^)]*\)/, "" ) +
			(parseInt( value ) + '' == "NaN" ? "" : "alpha(opacity=" + value * 100 + ")");
		
	} else {
		elem.style[prop]=value;
	}
}

function getWidth(elem, p, b, m) {
	var props = { position: "absolute", visibility: "hidden", display:"block" };
	var old = {};
	var display;
	
	display = getStyleValue(elem,'display');
	
	if (getBrowser() != "safari") {
		w = elem.offsetWidth;
	} else if (display != 'none' && display != null) {
		w = elem.offsetWidth;
	} else {
		for ( var n in props ) {
			old[ n ] = elem.style[ n ];
			elem.style[ n ] = props[ n ];
		}
		
		w = elem.offsetWidth;
		
		// Revert the old values
		for ( var n in props )
			elem.style[ n ] = old[ n ];
		
		
		alert(w);
	}
	
	p = p || true;
	b = b || true;
	m = m || false;
	
	padding = 0;
	border = 0;
	margin = 0;
	
	if (p) {
		padding = parseFloat(getStyleValue(elem, "paddingLeft"),true) || 0;
		padding += parseFloat(getStyleValue(elem, "paddingRight"),true) || 0;
	}
		
	if (b) {
		border = parseFloat(getStyleValue(elem, "borderLeftWidth"),true) || 0;
		border += parseFloat(getStyleValue(elem, "borderRightWidth"),true) || 0;
	}
		
	if (m)  {
		margin = parseFloat(getStyleValue(elem, "marginLeft"),true) || 0;
		margin += parseFloat(getStyleValue(elem, "marginRight"),true) || 0;
	}
		
	return Math.round(w + padding + border + margin);
}

function now() {
	return +new Date;
}

var Animation = function(duration,step,complete,cancel) {
	var startTime = now();
	var dur = duration;
	var self=this;
	
	var timerId = window.setInterval(function() {
		var n  = now() - startTime;
		var state = n / dur;
		if (state > 1) {
			state = 1;
		}
		if (step != undefined && typeof(step) == "function") {
			
			var r = step.call(self,state,n,dur) || true;
			if (!r || state >= 1) {
				window.clearInterval(timerId);
				if (!r && cancel != undefined && typeof(cancel) == "function") {
					cancel.call(state);
				}
				if (r && complete != undefined && typeof(complete) == "function") {
					complete.call(state);
				}
			}
		}
	},13);
	
}