// ***************
//   DOM
// ***************
//
// navigation
// ----------
//
// document.documentElement points to the root <html> node
//
// native DOM functions:
// - node.getElementById( idValue )
// - node.getElementsByTagName( tagName )
// - node.getElementsByName( name )
// native DOM objecten:
// - node.previousSibling
// - node.nextSibling
// - node.firstChild
// - node.lastChild
// - node.parentNode

function prevSiblingOf( elem ) {
	do {
		elem = elem.previousSibling;
	} while ( elem && elem.nodeType != 1 );
	return elem;
}

function nextSiblingOf( elem ) {
	do {
		elem = elem.nextSibling;
	} while ( elem && elem.nodeType != 1 );
	return elem;
}

function firstChildOf( elem ) {
	elem = elem.firstChild;
	return elem && elem.nodeType != 1 ? nextSiblingOf ( elem ) : elem;
}

function lastChildOf( elem ) {
	elem = elem.lastChild;
	return elem && elem.nodeType != 1 ? prevSiblingOf ( elem ) : elem;
}

function parentOf( elem, num ) {
	num = num || 1;
	for ( var i = 0; i < num; i++ ) {
		if ( elem != null ) elem = elem.parentNode;
	}	
	return elem;
}

//
// finding elements
// ----------------
//
// also check cssQuery: library for finding elements based on css selector syntax
//

function getElementsByClassName(strClassName, strTagName, startElement) {
  var startNode = startElement?startElement:document;
  var arrNodes  = startNode.getElementsByTagName(strTagName?strTagName:'*');
  var arrFound  = new Array();
  for (var i=0; i< arrNodes.length; i++) {
    var node = arrNodes[i];
    if (!node.className || node.className=="") continue;
    var arrClasses = node.className.split(' ');
    for (var j=0; j<arrClasses.length; j++) {
      if (arrClasses[j]==strClassName) arrFound[arrFound.length] = node;
    }
  }
  return arrFound;
}

//
// modifying
// ---------
//
// native DOM functions:
// - nodeParent.insertBefore( nodeToInsert, beforeNode )
// - nodeParent.appendChild( nodeToInsert );
// - nodeParent.removeChild( nodeToRemove );
// 
// you may also consider just using the innerHTML property of elements
//

function remove( elem ) {
	if ( elem ) elem.parentNode.removeChild( elem );
}

function empty( elem ) {
	while ( elem.firstChild ) {
		remove( elem.firstChild );
	}	
}

//
// attributes
// ---------
//
// native DOM functions:
// - node.getAttribute( attrName )
// - node.setAttribute( attrName, attrValue )
// 
// you may also use getters and setters, i.e. node.attrName = ...
//

// ***************
//   EVENTS
// ***************
//
function stopBubble(e) {
	// If an event object is provided, then this is a non-IE browser
	if ( e && e.stopPropagation ) {
		// and therefore it supports the W3C stopPropagation() method
		e.stopPropagation();
	}	else {
		// Otherwise, we need to use the Internet Explorer way of cancelling event bubbling
		window.event.cancelBubble = true;
	}	
}

//
// addEvent/removeEvent written by Dean Edwards, 2005
// with input from Tino Zijdel
// http://dean.edwards.name/weblog/2005/10/add-event/
// ----------------------------------------------------
//
// usage example:
//
// 
// 
// function keyStrokeHandler(e){
//   // If the user hits the Spacebar + Ctrl key
//   if ( e.keyCode == 32 && e.ctrlKey ) {
//     // Display our special form
//     this.getElementsByTagName("form")[0].style.display = 'block';
//     // Prevent browser default action for this keystroke
//     e.preventDefault();
//   }
// }
// 
// function loadEvents(){
//   addEvent( document.body, "keypress", keyStrokeHandler);
//   // add more event handlers if you like
// }
// 
// addEvent( window, "load", loadEvents ); // this should happen once per script page included

function addEvent(element, type, handler) {
  // assign each event handler a unique ID
  if (!handler.$$guid) handler.$$guid = addEvent.guid++;
  // create a hash table of event types for the element
  if (!element.events) element.events = {};
  // create a hash table of event handlers for each element/event pair
  var handlers = element.events[type];
  if (!handlers) {
    handlers = element.events[type] = {};
    // store the existing event handler (if there is one)
    if (element["on" + type]) {
      handlers[0] = element["on" + type];
    }
  }
  // store the event handler in the hash table
  handlers[handler.$$guid] = handler;
  // assign a global event handler to do all the work
  element["on" + type] = handleEvent;
};

// a counter used to create unique IDs
addEvent.guid = 1;
    
function removeEvent(element, type, handler) {
  // delete the event handler from the hash table
  if (element.events && element.events[type]) {
    delete element.events[type][handler.$$guid];
  }
};

function handleEvent(event) {
  var returnValue = true;
  // grab the event object (IE uses a global event object)
  event = event || fixEvent(window.event);
  // get a reference to the hash table of event handlers
  var handlers = this.events[event.type];
  // execute each event handler
  for (var i in handlers) {
    this.$$handleEvent = handlers[i];
    if (this.$$handleEvent(event) === false) {
      returnValue = false;
    }
  }
  return returnValue;
};

// Add some "missing" methods to IE's event object
function fixEvent(event) {
  // add W3C standard event methods
  event.preventDefault = fixEvent.preventDefault;
  event.stopPropagation = fixEvent.stopPropagation;
  return event;
};

fixEvent.preventDefault = function() {
  this.returnValue = false;
};

fixEvent.stopPropagation = function() {
  this.cancelBubble = true;
};  


// *******************
//   CSS en animaties
// *******************
//
function getStyle( elem, name ) {
	if (elem.style[name]) return elem.style[name]; // property exists in style[]
	if (elem.currentStyle) return elem.currentStyle[name]; // try IE
	if (document.defaultView && document.defaultView.getComputedStyle) { // try W3C
		name = name.replace(/([A-Z])/g,"-$1");
		name = name.toLowerCase();
		var s = document.defaultView.getComputedStyle(elem,"");
		return s && s.getPropertyValue(name);
	} 
	return null;
}

// find x position of an element relative to the entire document
function pageX(elem) {
	return elem.offsetParent ? elem.offsetLeft + pageX( elem.offsetParent ) : elem.offsetLeft;
}

// find y position of an element relative to the entire document
function pageY(elem) {
	return elem.offsetParent ? elem.offsetTop + pageY( elem.offsetParent ) : elem.offsetTop;
}

// find x position of an element relative to its parent
function parentX(elem) {
	return elem.parentNode == elem.offsetParent ? elem.offsetLeft : pageX( elem ) - pageX( elem.parentNode );
}

// find y position of an element relative to its parent
function parentY(elem) {
	return elem.parentNode == elem.offsetParent ? elem.offsetTop : pageY( elem ) - pageY( elem.parentNode );
}

// find the css left position of an element
function posX(elem) {
	return parseInt( getStyle( elem, "left" ) );
}

// find the css top position of an element
function posY(elem) {
	return parseInt( getStyle( elem, "top" ) );
}

// set the css left position of an element
function setX(elem, pos) {
	elem.style.left = pos + "px";
}

// set the css top position of an element
function setY(elem, pos) {
	elem.style.top = pos + "px";
}

// increment the css left position of an element
function addX(elem,pos) {
	setX( posX(elem) + pos );
}

// increment the css top position of an element
function addY(elem,pos) {
	setY( posY(elem) + pos );
}

// find the current width of an element
function getWidth( elem ) {
	return parseInt( getStyle( elem, 'width' ) );
}

// find the current height of an element
function getHeight( elem ) {
	return parseInt( getStyle( elem, 'height' ) );
}

// find the normal width of an element
function fullWidth( elem ) {
	if ( getStyle( elem, 'display' ) != 'none' ) return elem.offsetWidth || getWidth( elem );
	var old = resetCSS( elem, {
		display: '',
		visibility: 'hidden',
		position: 'absolute'
	});
	var w = elem.clientWidth || getWidth( elem );
	restoreCSS( elem, old );
	return w;
}

// find the normal height of an element
function fullHeight( elem ) {
	if ( getStyle( elem, 'display' ) != 'none' ) return elem.offsetHeight || getHeight( elem );
	var old = resetCSS( elem, {
		display: '',
		visibility: 'hidden',
		position: 'absolute'
	});
	var h = elem.clientHeight || getHeight( elem );
	restoreCSS( elem, old );
	return h;
}

// helper function
function resetCSS( elem, prop ) {
	var old = {};
	for ( var i in prop ) {
		old[ i ] = elem.style[ i ];
		elem.style[ i ] = prop[i];
	}
	return old;
}

// helper function
function restoreCSS( elem, prop ) {
	for ( var i in prop ) {
		elem.style[ i ] = prop[ i ];
	}
}

// hide an element
function hide( elem ) {
	var curDisplay = getStyle( elem, 'display' );
	if ( curDisplay != 'none' ) elem.$oldDisplay = curDisplay;
	elem.style.display = 'none';
}

// show an element
function show( elem ) {
	elem.style.display = elem.$oldDisplay || '';
}

// set the opacity of an element
function setOpacity( elem, level ) {
	if ( elem.filters ) {
		elem.style.filters = 'alpha(opacity=' + level + ')';
	}	else {
		elem.style.opacity = level / 100;
	}
}


// expand height from 0 to 100% over one second
function slideDown( elem ) {
	elem.style.height = '0px';
	show( elem );
	var h = fullHeight( elem );
	for ( var i = 0; i <= 100; i += 5 ) {
		(function(){
			var pos = i;
			setTimeout(function(){
				elem.style.height = ( pos / 100 ) * h  + "px";
			}, ( pos + 1 ) * 10 );
		})();
	}
}

// set alpha from 0 to 100% over one second
function fadeIn( elem ) {
	setOpacity( elem, 0 );
	show( elem );
	for ( var i = 0; i <= 100; i += 5 ) {
		(function(){
			var pos = i;
			setTimeout(function(){
				setOpacity( elem, pos );
			}, ( pos + 1 ) * 10 );
		})();
	}
}

// ***** CSS, mouse section *****

// find x position of the cursor relative to the entire document
function getX(e) {
	e = e || window.event;
	return e.pageX || e.clientX + document.body.scrollLeft;
}

// find y position of the cursor relative to the entire document
function getY(e) {
	e = e || window.event;
	return e.pageY || e.clientY + document.body.scrollTop;
}

// find x position of the cursor relative to the current element
function getElementX( e ) {
	return ( e && e.layerX ) || window.event.offsetX;
}

// find y position of the cursor relative to the current element
function getElementY( e ) {
	return ( e && e.layerY ) || window.event.offsetY;
}

// ***** CSS, page section *****
//
// native functions:
// - window.scrollTo(newX, newY);

// find the height of the whole web page
function pageHeight() {
	return document.body.scrollHeight;
}

// find the width of the whole web page
function pageWidth() {
	return document.body.scrollWidth;
}

// find how far horizontally the browser is scrolled
function scrollX() {
	var de = document.documentElement;
	return self.pageXOffset || ( de && de.scrollLeft ) || document.body.scrollLeft;
}

// find how far vertically the browser is scrolled
function scrollY() {
	var de = document.documentElement;
	return self.pageYOffset || ( de && de.scrollTop ) || document.body.scrollTop;
}

// find the height of the viewport
function windowHeight() {
	var de = document.documentElement;
	return self.innerHeight || ( de && de.clientHeight ) || document.body.clientHeight;
}

// find the width of the viewport
function windowWidth() {
	var de = document.documentElement;
	return self.innerWidth || ( de && de.clientWidth ) || document.body.clientWidth;
}


