Magic = M = {};

$M = function(s){
	return document.getElementById(s);
}


// Coordinate functions
M.Coord = C = {};
C.screenScrollY = function(){
	var r = document.documentElement.scrollTop ? document.documentElement.scrollTop  : document.body.scrollTop;
	if(isNaN(r + 0)){ r = 0; }
	
	return r;
}

C.screenScrollX = function(){
	var r = document.documentElement.scrollLeft ? document.documentElement.scrollLeft  : document.body.scrollLeft;
	if(isNaN(r + 0)){ r = 0; }
	
	return r;
}

C.elementCoords = function(obj){
	// Courtesy of Quirksmode.org
	var curleft = curtop = 0;
	
	if (obj.offsetParent) {
		do {
			curleft += obj.offsetLeft;
			curtop += obj.offsetTop;
		} while (obj = obj.offsetParent);
	}
	return {x:curleft , y:curtop};

}

// Returns the element's coords minus the relative el's coords.  Useful for setting top properties.
C.elementCoordsRelative = function(el , relEl){
	elC = Magic.Coord.elementCoords(el);
	elR = Magic.Coord.elementCoords(relEl);
	
	return {x:elC.x - elR.x , y:elC.y - elR.y};
}


C.centerToScreen = function(el , x , y , xO , yO){
	if(!el){ return; }
	
	if(x !== false){ x = true;}
	if(x !== false){ y = true;}
	if(isNaN(xO + 0)){ xO = 0; }
	if(isNaN(yO + 0)){ yO = 0; }
	
	if(y){
		el.style.top = (((Magic.Coord.screenScrollY() + (Magic.Dimension.documentHeight() / 2)) - (el.offsetHeight / 2)) + xO) + "px";	
	}
	
	if(x){
		el.style.left = (((Magic.Coord.screenScrollX() + (Magic.Dimension.documentWidth() / 2)) - (el.offsetWidth / 2)) + xO) + "px";	
	}
}

C.mouseY = function(e){
	// Requires an event object
	if(!e){ return 0; }
	
	var y = e.pageY;
	var scroll = 0;
	
	if(typeof(y) == "undefined"){
		y = e.clientY;
		// scroll is for IE
		scroll = Magic.Coord.screenScrollY();
	}
	
	return y + scroll;
}

C.mouseX = function(e){
	if(!e){ return 0; }
	
	var y = e.pageX;
	var scroll = 0;
	
	if(typeof(y) == "undefined"){
		y = e.clientX;
		// scroll is for IE
		scroll = Magic.Coord.screenScrollX();
	}
	
	return y + scroll;
}

C.isMouseOverElement = function(e , el){
	var elCoords = Magic.Coord.elementCoords(el);
	var mX = Magic.Coord.mouseX(e);
	var mY = Magic.Coord.mouseY(e);
	
	return mX >= elCoords.x && mX <= elCoords.x + el.offsetWidth && mY >= elCoords.y && mY <= elCoords.x + el.offsetHeight; 
}


// Dimension
M.Dimension = C = {};

C.documentWidth = function(){
	return document.documentElement.clientWidth;
}

C.documentHeight = function(){
	return document.documentElement.clientHeight;
}


// Events Methods ***************
M.Event = C = {};
C.addEvent = function(obj , evt , fnc , useCapture){
	if (!useCapture){useCapture=false; }
	
	if (obj.addEventListener){
		obj.addEventListener(evt , fnc , useCapture);
		return true;
	}
	
	// IE
	if(obj.attachEvent){
		return obj.attachEvent("on" + evt , fnc);
	}

} 

C.removeEvent = function(obj , evt , fnc , useCapture){
	if(obj.removeEventListener){
		obj.removeEventListener(evt , fnc , useCapture);
		return true;
	}
	
	if(obj.detachEvent){
		obj.detachEvent("on" + evt , fnc);
	}
}

C.cancelEvent = function cancelEvent(e){
  e = e ? e : window.event;
  if(e.stopPropagation){
    e.stopPropagation();
  }
  
  if(e.preventDefault){
    e.preventDefault();
  }
  e.cancelBubble = true;
  e.cancel = true;
  e.returnValue = false;
  return false;
}

// Selector Methods ***************

M.Selector = C = {};
/* Developed by Robert Nyman, http://www.robertnyman.com
Code/licensing: http://code.google.com/p/getelementsbyclassname/ */
C.getElementsByClassName = function (className, tag, elm){
	if (document.getElementsByClassName) {
		getElementsByClassName = function (className, tag, elm) {
			elm = elm || document;
			var elements = elm.getElementsByClassName(className),
				nodeName = (tag)? new RegExp("\\b" + tag + "\\b", "i") : null,
				returnElements = [],
				current;
			for(var i=0, il=elements.length; i<il; i+=1){
				current = elements[i];
				if(!nodeName || nodeName.test(current.nodeName)) {
					returnElements.push(current);
				}
			}
			return returnElements;
		};
	}
	else if (document.evaluate) {
		getElementsByClassName = function (className, tag, elm) {
			tag = tag || "*";
			elm = elm || document;
			var classes = className.split(" "),
				classesToCheck = "",
				xhtmlNamespace = "http://www.w3.org/1999/xhtml",
				namespaceResolver = (document.documentElement.namespaceURI === xhtmlNamespace)? xhtmlNamespace : null,
				returnElements = [],
				elements,
				node;
			for(var j=0, jl=classes.length; j<jl; j+=1){
				classesToCheck += "[contains(concat(' ', @class, ' '), ' " + classes[j] + " ')]";
			}
			try	{
				elements = document.evaluate(".//" + tag + classesToCheck, elm, namespaceResolver, 0, null);
			}
			catch (e) {
				elements = document.evaluate(".//" + tag + classesToCheck, elm, null, 0, null);
			}
			while ((node = elements.iterateNext())) {
				returnElements.push(node);
			}
			return returnElements;
		};
	}
	else {
		getElementsByClassName = function (className, tag, elm) {
			tag = tag || "*";
			elm = elm || document;
			var classes = className.split(" "),
				classesToCheck = [],
				elements = (tag === "*" && elm.all)? elm.all : elm.getElementsByTagName(tag),
				current,
				returnElements = [],
				match;
			for(var k=0, kl=classes.length; k<kl; k+=1){
				classesToCheck.push(new RegExp("(^|\\s)" + classes[k] + "(\\s|$)"));
			}
			for(var l=0, ll=elements.length; l<ll; l+=1){
				current = elements[l];
				match = false;
				for(var m=0, ml=classesToCheck.length; m<ml; m+=1){
					match = classesToCheck[m].test(current.className);
					if (!match) {
						break;
					}
				}
				if (match) {
					returnElements.push(current);
				}
			}
			return returnElements;
		};
	}
	return getElementsByClassName(className, tag, elm);
};


// Element Methods *****************
M.Element = C = {};

C.insertAfter = function(newNode, refNode) {
	if(refNode.nextSibling) {
		return this.insertBefore(newNode, refNode.nextSibling);
	} else {
		return this.appendChild(newNode);
	}
}





