/**
  * Crossbrowser event handling functions.
  *
  * A set of functions to easily attach and detach event handlers to HTML elements.
  * These functions work around the shortcomings of the traditional method ( element.onevent = function; )
  * where only 1 handler could be attached for a certain event on the object, and mimic the DOM level 2
  * event methods addEventListener and removeEventListener for browsers that do not support these
  * methods (e.g. Internet Explorer) without resorting to propriety methods such as attachEvent and detachEvent
  * that have a whole set of their own shortcomings.
  * Created as an entry for the 'contest' at quirksmode.org: http://www.quirksmode.org/blog/archives/2005/09/addevent_recodi.html
  *
  * @author Tino Zijdel ( crisp@xs4all.nl )
  * @version 1.2
  * @date 2005-10-21
  */
/**
  * addEvent
  *
  * Generic function to attach event listeners to HTML elements.
  * This function does NOT use attachEvent but creates an own stack of function references
  * in the DOM space of the element. This prevents closures and therefor possible memory leaks.
  * Also because of the way the function references are stored they will get executed in the
  * same order as they where attached - matching the behavior of addEventListener.
  *
  * @param obj The object to which the event should be attached.
  * @param evType The eventtype, eg. 'click', 'mousemove' etcetera.
  * @param fn The function to be executed when the event fires.
  * @param useCapture (optional) Whether to use event capturing, or event bubbling (default).
  */
function addEvent(obj, evType, fn)
{
	var evTypeRef = '__' + evType;

	if (obj[evTypeRef])
	{
		if (array_search(fn, obj[evTypeRef]) > -1) return;
	}
	else
	{
		obj[evTypeRef] = [];
		if (obj['on'+evType]) obj[evTypeRef][0] = obj['on'+evType];
		obj['on'+evType] = handleEvent;
	}

	obj[evTypeRef][obj[evTypeRef].length] = fn;
}

function removeEvent(obj, evType, fn)
{
	var evTypeRef = '__' + evType;

	if (obj[evTypeRef])
	{
		var i = array_search(fn, obj[evTypeRef]);
		if (i > -1) delete obj[evTypeRef][i];
	}
}

function handleEvent(e)
{
	e = e || window.event;
	var evTypeRef = '__' + e.type, retValue = true;

	for (var i = 0, j = this[evTypeRef].length; i < j; i++)
	{
		if (this[evTypeRef][i])
		{
			this.__fn = this[evTypeRef][i];
			retValue = this.__fn(e) && retValue;
		}
	}

	if (this.__fn) try { delete this.__fn; } catch(e) { this.__fn = null; }

	return retValue;
}
/**
  * array_search
  * 
  * Searches the array for a given value and returns the (highest) corresponding key if successful, -1 if not found.
  *
  * @param val The value to search for.
  * @param arr The array to search in.
  */
function array_search(val, arr)
{
	var i = arr.length;

	while (i--)
		if (arr[i] && arr[i] === val) break;

	return i;
}

// Optional cancelEvent() function you can call within your event handlers to
// stop them performing the normal browser action or kill the event entirely.
// Pass an event object, and the second "c" parameter cancels event bubbling.
function cancelEvent(e, c)
{
 e.returnValue = false;
 if (e.preventDefault) e.preventDefault();
 if (c)
 {
  e.cancelBubble = true;
  if (e.stopPropagation) e.stopPropagation();
 }
}



// event helpers
function getNode(id){return document.getElementById(id);}

function killNode(id){
	var el = getNode(id);
	if(el==null || typeof el=="undefined"){return;}
	var parent = el.parentElement;
	if(typeof parent != "undefined"){
		parent.removeChild(el);
	}else{
		el.style.display="none";
	}
}

function removeChildNodes(el){
	while(el.hasChildNodes()){
		el.removeChild(el.firstChild);
	}
}

// to be tested
function replaceChildNodes(el, newchild){
	removeChildNodes(el);
	el.appendChild(newchild);
}
function getEventTarget(evt){
	evt = evt || window.event;
	var tgt = evt.srcElement;
	if(!tgt){
		tgt = evt.target;
	}
	return tgt;
}
function cleanWhitespace(element) {
  //element = $(element);
  for (var i = 0; i < element.childNodes.length; i++) {
    var node = element.childNodes[i];
    if (node.nodeType == 3 && !/S/.test(node.nodeValue))
      element.removeChild(node);
  }
}

// removes whitespace-only text node children
/*cleanWhitespace: function(element) {
  element = $(element);
  for (var i = 0; i < element.childNodes.length; i++) {
    var node = element.childNodes[i];
    if (node.nodeType == 3 && !/S/.test(node.nodeValue))
      Element.remove(node);
  }
}*/
/*
function getStyleBySelector(selector)
{
	var sheetList = document.styleSheets;
	var ruleList;
	var i, j;
	
	//look through stylesheets in reverse order that
	// they appear in the document
	for (i=sheetList.length-1; i >= 0; i--)
	{
	  ruleList = sheetList[i].cssRules;
	  for (j=0; j<ruleList.length; j++)
	  {
			if (ruleList[j].type == CSSRule.STYLE_RULE && 
				 ruleList[j].selectorText == selector)
			{
				 return ruleList[j].style;
			}   
	  }
	}
	return null;
}
*/
/*
http://onlinetools.org/articles/unobtrusivejavascript/cssjsseparation.html
a: defines the action you want the function to perform.
o: the object in question.
c1: the name of the first class
c2: the name of the second class
*/
function jscss(a,o,c1,c2)
{
  switch (a){
    case 'swap':
      o.className=!jscss('check',o,c1)?o.className.replace(c2,c1): o.className.replace(c1,c2);
    break;
    case 'add':
      if(!jscss('check',o,c1)){o.className+=o.className?' '+c1:c1;}
    break;
    case 'remove':
      var rep=o.className.match(' '+c1)?' '+c1:c1;
      o.className=o.className.replace(rep,'');
    break;
    case 'check':
      return new RegExp('\\b'+c1+'\\b').test(o.className);
    break;
  }
}
function addCssClass(element, classname) {jscss('add', element, classname);}
function removeCssClass(element, classname) {jscss('remove', element, classname);}
function swapCssClass(element, classname1, classname2){jscss('swap', element, classname1, classname2); }
function replaceCssClass(element, oldclassname, newclassname){
	if(hasCssClass(element, oldclassname)){swapCssClass(element, oldclassname, newclassname);}
}
function hasCssClass(element, classname){ return jscss('check', element, classname);}
