function applyPrototype(obj, el) {
	for (f in obj.prototype) {
		if (typeof(el[f]) == 'undefined') {
			el[f] = obj.prototype[f];
		}
	}
}

var $ = function(id) {
	return document.getElementById(id);
};

function $new(eltype, attributes, content) {
    var newElement = document.createElement(eltype);

    if (typeof(attributes != 'undefined')) { 
        if (typeof(attributes) == 'object') {
            for (name in attributes) {
               if (typeof(attributes[name]) == 'string')
                   newElement.setAttribute(name, attributes[name]);
            }

            if (typeof(content) != 'undefined') 
               newElement.innerHTML = content;
        } else if (typeof(attributes) != 'undefined') {
            newElement.innerHTML = attributes;
        }
    } 
	
	applyPrototype(newElement, DomElement);
    return newElement;
}

function DomElement() {};

DomElement.prototype.addEvent = function(evtType, func) {
   if (this.addEventListener) { //gecko
      this.addEventListener(evtType, func, true);
   } else if (this.attachEvent) { //ie
      this.attachEvent('on' + evtType, func);
   } else { //all the others
      this['on' + evtType] = func;
   }
}

DomElement.prototype.hasClass = function(className) {
   var pattern = new RegExp('(^|\\s)' + className + '(\\s|$)'); //use this regexp
   return pattern.test(this.className); //to check for the class
}
 
DomElement.prototype.addClass = function(className) {
   if (!this.hasClass(className)) { //if the class isn't there already
      this.className += (' ' + className); //append it to the end of the class list
   }
}
 
DomElement.prototype.removeClass = function(className) {
   var pattern = new RegExp('(^|\\s)' + className + '(\\s|$)'); //use this regexp
   this.className = this.className.replace(pattern, ' '); //to make a search and replace by a blank space
}

DomElement.prototype.getElementsByClass = function (className, tag) {
   var returnArray = [];
   tag = tag || '*'; //if tag is defined, use that for a more specific search, otherwise search in all tags
 
   var els = this.getElementsByTagName(tag); //get the elements
 
   for (var i = 0; i < els.length; i++) { //run the elements
      if (els[i].hasClass(className)) { //if a element implements that class
         returnArray.push(els[i]); //append it to the return array
      }
   }
 
   return returnArray;
}

DomElement.prototype.appendAfter = function(newElement) {
   //call insertBefore method on parent node to insert the new element before the element next to this
   this.parentNode.insertBefore(newElement, this.nextSibling);
}
 
DomElement.prototype.appendBefore = function(newElement) {
   //call insertBefore method on parent node to insert the new element before this
   this.parentNode.insertBefore(newElement, this);
}

DomElement.prototype.removeElement = function(oldElement) {
   var childElements = oldElement.getElementsByTagName('*');
 
   for (var i = 0; i < childElements.length; i++) { //purge all elements contained in the element to remove
      purge(childElements[i]);
   }
 
   purge(oldElement); //purge the element to remove
   this.removeChild(oldElement); //remove it
 
   //function that came from Douglas Crockford site, that removes all the event handlers from de elements
   function purge(d) {
      var a = d.attributes, i, l, n;
      if (a) {
          l = a.length;
          for (i = 0; i < l; i += 1) {
              n = a[i].name;
              if (typeof d[n] === 'function') {
                  d[n] = null;
              }
          }
      }
      a = d.childNodes;
      if (a) {
          l = a.length;
          for (i = 0; i < l; i += 1) {
              purge(d.childNodes[i]);
          }
      }
   }
}

DomElement.prototype.getAbsolutePosition = function() {
	var curleft = curtop = 0;
	var el = this;
	
	if (el.offsetParent) {
		curleft = el.offsetLeft
		curtop = el.offsetTop
		
		while (el = el.offsetParent) {
			curleft += el.offsetLeft
			curtop += el.offsetTop
		}
	}
	
	return {x: curleft, y: curtop};
}

DomElement.prototype.getRelativePosition = function(node) {
	var pos = this.getAbsolutePosition();
	var nodePos = node.getAbsolutePosition();
	
	return {x: pos.x - nodePos.x, y: pos.y - nodePos.y};
}

Array.prototype.map = function(f) {
  for (i = 0; i < this.length; i++)
    f(this[i]);
}

window.addEvent = DomElement.prototype.addEvent;
window.loadEvents = [];
window.addEvent('load', function() {
	for (var i = 0; i < this.loadEvents.length; i++) {
		this.loadEvents[i]();
	}
});


window.addOnLoad = function(fnFunction) {
	window.loadEvents.push(fnFunction);
}
 
addOnLoad(function() {
	document.getElementsByClass = DomElement.prototype.getElementsByClass;
	document.body.getElementsByClass = DomElement.prototype.getElementsByClass;
	
	var allNodes = document.getElementsByTagName('*');
	
	for (var i = 0; i < allNodes.length; i++) {
		applyPrototype(DomElement, allNodes[i]);
	}
});