// -- misc functions --
var _systemID = 0;

function id(){
	return _systemID++;
}

function $(elem){
	return document.getElementById(elem);
}

function $$(elem, tag){
	var el = null;
	if($type(elem)=="string") el = $(elem);
	if($type(elem)=="element") el = elem;
	if(!el) return null;
	
	return el.getElementsByTagName(tag);
}

function $$$(className){
	var retnode = [];
	var myClass = new RegExp('\\b'+className+'\\b');
	var elem = document.getElementsByTagName('*');
	for (var i = 0; i < elem.length; i++) {
		var classes = elem[i].className;
		if (myClass.test(classes)) retnode.push(elem[i]);
	}
	return retnode;
}


function $A(parent, obj){
	if(parent.nodeName){
		if(obj instanceof Array){
			for(var i=0;i<obj.length;i++){
				$A(parent, obj[i]);
			}
		}else{
			var type = $type(obj);
			if(type=="element"||type=="textnode"){
				parent.appendChild(obj);
			}
			if(type=="string"){
				parent.appendChild($T(obj));
			}
		}
	}
	return parent;
}

function $T(text){
	return document.createTextNode(text);
}

function $E(obj){
	if($type(obj)=="string"){
		return document.createElement(obj);
	}
	if($type(obj)=="array"){
		var elem;
		for(var i=0;i<obj.length;i++){
			if(i==0&&$type(obj[0])=="string"){
				elem = document.createElement(obj[0]);
			} else if($type(obj[i])=="object") {
				for(attr in obj[i]){
					if($type(obj[i][attr])=="function"){
						elem[attr] = obj[i][attr];
					} else if(attr=="class") {
						elem.className = obj[i][attr];
					} else {
						elem.setAttribute(attr, obj[i][attr]);
					}
				}
			}
		}
		return elem;
	}
	return null;
}

// based on graft() function from Sean M. Burke - http://interglacial.com
function $G(oParent, oTree){
    var oElem;
    if(typeof(oTree)=="undefined"){
    	alert("$G ERROR: oTree undefined !");
    	return null;
    } else if(oTree.constructor==String) {
		oElem = $E("span");
		oElem.innerHTML = oTree;
    } else if(oTree.length==0) {
        oElem = $E("span");
    } else {
        for(var i=0;i<oTree.length;i++) {
            if((i==0)&&(oTree[i].constructor==String)) {
                var oRe;
                oRe = oTree[i].match(/^([a-z][a-z0-9]*)\.([^\s\.]+)$/i);
                if(oRe) {
                    oElem = $E(oRe[1]);
                    oElem.setAttribute('class', oRe[2]);
                    continue;
                }
                oRe = oTree[i].match(/^([a-z][a-z0-9]*)$/i);
                if(oRe) {
                    oElem = $E(oRe[1]);
                    continue;
                }
                oElem = $E("span");
            }

            if(oTree[i]==undefined) {
            	alert("$G ERROR: undefined element");
            	return null;
            }else if(oTree[i].constructor == String || oTree[i].constructor == Array){
                $G(oElem, oTree[i]);
            }else if(oTree[i].constructor == Number) {
                $G(oElem, oTree[i].toString());
            }else if(oTree[i].constructor == Object ) {
                for(var l in oTree[i]) {
                    if(typeof(oTree[i][l])=='function'){
                        oElem[l] = oTree[i][l];
                    }else if(l=="class"){
						oElem.className = oTree[i][l];
					}else{
                        oElem.setAttribute(l, oTree[i][l]);
                    }
                }
            }else if(typeof(oTree[i])=="object"){
            	oElem.appendChild(oTree[i]);
            }else{
            	alert("$G ERROR Object " + oTree[i] +" ");
            }
        }
    }

    oParent.appendChild(oElem);
    return oElem;
}

function $type(obj){
	if (!obj) return false;
	var type = false;
	if (obj instanceof Function) {
		type = 'function';
	}else if (obj.nodeName){
		if (obj.nodeType == 3) type = 'textnode';
		else if (obj.nodeType == 1) type = 'element';
	}else if (obj instanceof Array) {
		type = 'array';
	}else if (typeof obj == 'object') {
			type = 'object';
	}else if (typeof obj == 'string') {
		type = 'string';
	}else if (typeof obj == 'number' && isFinite(obj)) {
		type = 'number';
	}
	return type;
};

function $style(obj, style){
	var elem = obj;
	if($type(obj)=="string") elem = $(obj);
	if(document.defaultView && document.defaultView.getComputedStyle){
		var css = document.defaultView.getComputedStyle(elem, null);
		return css ? css.getPropertyValue(style) : null;
	}else if(elem.currentStyle){
		return elem.currentStyle[style];
	}
	return null;
}

function $styleClass(styleClass){
	for (var s=0; s<document.styleSheets.length; s++){
		if(document.styleSheets[s].rules){
			for (var r = 0; r <document.styleSheets[s].rules.length; r++){
				if (document.styleSheets[s].rules[r].selectorText == '.' + styleClass){
					return document.styleSheets[s].rules[r];
				}
			}
		}else if(document.styleSheets[s].cssRules){
			for (var r = 0; r < document.styleSheets[s].cssRules.length; r++){
				if (document.styleSheets[s].cssRules[r].selectorText == '.' + styleClass)
					return document.styleSheets[s].cssRules[r];
			}
		}
	}
	return null;
}

function $clear(elem){ // clear element content
	var e = null;
	if($type(elem)=="element"){
		e = elem;
	}else{
		if($(elem)) e = $(elem);
	}
	if(e){
		while(e.childNodes.length>0){
			e.removeChild(e.childNodes[0]);
		}
	}
}

function $cumulativeOffset(obj) {
	var _offsetX = _offsetY = 0;
	if (obj.offsetParent) {
		_offsetX = obj.offsetLeft;
		_offsetY = obj.offsetTop;
		while (obj = obj.offsetParent) {
			_offsetX += obj.offsetLeft;
			_offsetY += obj.offsetTop;
		}
	}
	return [_offsetX, _offsetY];
}

function $scrollOffset(obj){
	var _offsetX = _offsetY = 0;
	if (obj.parentNode) {
		_offsetX = obj.scrollLeft;
		_offsetY = obj.scrollTop;
		while (obj = obj.parentNode) {
			if(typeof(obj.scrollLeft)!="undefined") _offsetX += obj.scrollLeft;
			if(typeof(obj.scrollTop)!="undefined") _offsetY += obj.scrollTop;
		}
	}
	return [_offsetX, _offsetY];
}

// -- Function extensions --
// based on the functions included in Prototype JavaScript Framework - http://prototype.conio.net
Function.prototype.bind = function() {
	var __this = this;
	var _object = arguments[0];
	for(var i=0;i<arguments.length-1;i++){
		arguments[i] = arguments[i+1];
	}
	arguments.length--;
	var _args = arguments;
	return function() {
		return __this.apply(_object, _args);
	}
}

Function.prototype.bindAsEventListener = function(object){
	var __this = this;
	var _object = arguments[0];
	var _args = arguments;
	for(var i=0;i<_args.length-1;i++){
		_args[i] = _args[i+1];
	}
	return function(event) {
		var __args = new Array();
		__args.push(event||window.event);
		for(var j=0;j<_args.length;j++){
			__args.push(_args[j]);
		}
		return __this.apply(_object, __args);
	}
}

// -- Array extensions --
Array.prototype.clear = function(){
	this.length = 0;
	return this;
}

Array.prototype.indexOf = function(oObj){
	for(var i=0;i<this.length;i++){
		if(oObj==this[i]){
			return i;
		}
	}
	return -1;
}

Array.prototype.compact = function(){
	var aResult = new Array();
	for(var i=0;i<this.length;i++){
		if(typeof(this[i])!="undefined"&&this[i]!=null){
			aResult.push(this[i]);
		}
	}
	return aResult;
}

Array.prototype.shift = function(){
	var oResult = this[0];
	for(var i=0;i<this.length-1;i++){
		this[i] = this[i+1];
	}
	this.length--;
	return oResult;
}

