
function hasClass(ele,cls) {
	return ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)'));
}

function addClass(ele,cls) {
	if (!this.hasClass(ele,cls)) ele.className += " "+cls;
}

function removeClass(ele,cls) {
//	if (hasClass(ele,cls)) {
		var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)');
		ele.className=ele.className.replace(reg,' ');
//	}
}



function getElementPos(obj)
{
	return getOffsetToViewport(obj);
}
/*
The all-in-one function with indepth comments on specific browser quirks
and implementation details removed.
*/
function getOffsetToViewport(obj)
{
  // getBoundingClientRect is supported by IE5+, FF3+, OP9.50+, SF4+
  if (obj.getBoundingClientRect)
  {
    var bounds = obj.getBoundingClientRect();

    var xscroll = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft;
    var yscroll = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop;

    return { left: bounds.left + xscroll - document.documentElement.clientLeft - document.body.clientLeft
           , top:  bounds.top  + yscroll - document.documentElement.clientTop  - document.body.clientTop
           };
  }

  var elemx = obj.offsetLeft;
  var elemy = obj.offsetTop;
  var parent = obj.offsetParent;

  while (parent)
  {
    // add offset to content part of our offsetParent
    elemx += parent.offsetLeft;
    elemy += parent.offsetTop;

    // Quirks:
    // - Opera already adds clientTop/Left to offsetTop/Left
    // - Firefox <3 (Gecko <1.9) doesn't support clientTop/Left
    if (!toddClientTopIsAddedToOffsetTop && typeof parent.clientLeft != 'undefined')
    {
      // also add the edge size of the offsetParent
      elemx += parent.clientLeft;
      elemy += parent.clientTop;
    }

    // subtract the amount the offsetParent is scrolled, except if it's the scrollposition of the page
    if (parent != document.body && parent != document.documentElement)
    {
      elemx -= parent.scrollLeft;
      elemy -= parent.scrollTop;
    }

    parent = parent.offsetParent;
  }

  return { left: elemx
         , top:  elemy
         };
}


/** @short get the size of the visible area
*/
function getViewPortDimensions()
{
  // all except Explorer
  if (window.innerHeight)
    return { width:  window.innerWidth
           , height: window.innerHeight
           };

  // Explorer 6 Strict Mode
  if (document.documentElement && document.documentElement.clientHeight)
    return { width:  document.documentElement.clientWidth
           , height: document.documentElement.clientHeight
           };

  return { width:  document.body.clientWidth
         , height: document.body.clientHeight
         };
}

function getWindowInnerDimensions()
{
	// all except Explorer
    if (window.innerHeight) {
      window.method = 'window.inner...';
    }
    else // Explorer 6 Strict Mode
    if (document.documentElement && document.documentElement.clientHeight) {
      window.innerWidth = document.documentElement.clientWidth;
      window.innerHeight= document.documentElement.clientHeight;
      window.method = 'document.documentElement.client...';
    }
    else {
        window.innerWidth = document.body.clientWidth;
        window.innerHeight= document.body.clientHeight;
        window.method = 'document.body.client...';
    };
}



/** @short get the full size of the page
*/
function getPageDimensions()
{
  var htmlwidth = document.documentElement.scrollWidth;
  var htmlheight = document.documentElement.scrollHeight;

  // IE6-QuirksMode and SF (all versions? tested with 3.2.1) give page height in <BODY>
  // All other browsers give the size in documentElement (<HTML>)
  var bodywidth = document.body.scrollWidth;
  var bodyheight = document.body.scrollHeight;

  // return largest values
  return { width:  htmlwidth  > bodywidth  ? htmlwidth  : bodywidth
         , height: htmlheight > bodyheight ? htmlheight : bodyheight
         };
}



function loadStyle(src,callback) {

	var script;
	if (script = findInFilecache(src)) {

		// http://www.quirksmode.org/bugreports/archives/2006/01/IE_wont_allow_documentcreateElementstyle.html
		// http://forums.whirlpool.net.au/forum-replies-archive.cfm/426227.html
		// http://msdn.microsoft.com/en-us/library/ms531194.aspx
		try {

			var oStyle = document.createElement("style");
			oStyle.setAttribute("type", "text/css");

			if(oStyle.styleSheet){// IE
				// IE doesn't allow innerHTML, innerText and appendChild for <style>
				oStyle.styleSheet.cssText = script;
			} else {// w3c
				oStyle.appendChild(document.createTextNode(script));
			}

		} catch(err) {

			alert('experimental fallback mode for old browsers activated.');

			// This should allways work, but is a hack
			var htmlDiv = document.createElement('div');
			htmlDiv.innerHTML = '.<style type="text/css">'+script+'</style>';
			oStyle = htmlDiv.getElementsByTagName('style')[0];
		}
  
  		// we assume 'head' is available.
  		// in Safari it is not automaticly created in xhtml mode?
		document.getElementsByTagName('head')[0].appendChild(oStyle);
		if (callback) callback();
		return oStyle;
	}

	// generate a link to the stylesheet file
	var oStyle = document.createElement('link');
	oStyle.rel = 'stylesheet';
	oStyle.href = src;
	if (callback) oStyle.onload=callback;
	document.getElementsByTagName('head')[0].appendChild(oStyle);

	return oStyle;
}

// for the filecache to work, there may not be a newline between <div> and <!--
// and --> and </div>
function findInFilecache(src) {
	// iterate through the 'filecache'
	var filecache = document.getElementById('filecache');
	var cfile=filecache.firstChild;
	var cfilename;
	do {

		if (  cfile.nodeType==3 /* text node */
		    ||cfile.nodeType==8 /* comment node */ )
		   continue;

		if ( cfilename=cfile.getAttributeNode('filename').value) {
			if (cfilename==src) {
				console.log('Found file in filecache');
				return cfile.firstChild.nodeValue;
			}
		}
	} while(cfile=cfile.nextSibling);
	
	//console.log('Cannot find file '+src+' in browsercache.');
}

/*
  if (null == node.canHaveChildren || node.canHaveChildren) {
    node.appendChild(document.createTextNode(text));
  } else {
    node.text = text;
  } 
*/

function loadScript(src,callback) {
    if (window.console !== undefined)
    	console.log('Loading script '+src);

	var script;
	if (script = findInFilecache(src)) {

		//http://www.htmlcodetutorial.com/help/ftopic761.html
		var oScript = document.createElement('script');
		oScript.type = 'text/javascript';

//		oScript.innerHTML = script;								// works with FF3/Opera9/Safari3.1, but not IE
//		oScript.appendChild(document.createTextNode(oScript));
		oScript.text = script;									// works with FF3/Opera9/SF3.1 and IE6+

		document.getElementsByTagName('head')[0].appendChild(oScript);

		if (callback)
			callback();

		return;
	}

	var oScript = document.createElement('script');
	oScript.type = 'text/javascript';
	oScript.onerror = function() { console.error("File '"+src+"' could not be loaded."); };

	if (callback)
	{
		oScript.onload=callback;
	//	oScript.onload = function() { console.log("File '"+src+"' is loaded."); }

		// For IE (onload doesn't work on a script in IE?)
		oScript.onreadystatechange = function () {
			if (this.readyState == 'loaded' ||    /* finished loading for first time */
				this.readyState == 'complete') {  /* finished loading from cache */
				oScript.onload();
			}
		}
	}

	oScript.src = src;
//	document.body.appendChild(oScript);
	document.getElementsByTagName('head')[0].appendChild(oScript);
}


// getXMLvalue, getXMLattribute functions by Spellcoder (Mark de Jong)
function getXMLvalue(XMLobj)				{ return ((XMLobj && XMLobj.firstChild) ? XMLobj.firstChild.nodeValue : null) }
function getXMLattribute(XMLobj,attname)	{ return (XMLobj.getAttributeNode(attname) ? XMLobj.getAttributeNode(attname).value : null) }


// Name		- getURLprotocol
// Author	- Mark de Jong (Spellcoder)
// Date		- 16 juni 2006
function getURLprotocol() {
	var BASE = location+""
	uProtocol = BASE.substring(0,BASE.indexOf("://"))
	return uProtocol
}



var getElementsByClassName = function()
{
    // native
    if (document.getElementsByClassName)
    {
        return function(className, nodeName, parentElement)
        {
            var s = (parentElement || document).getElementsByClassName(className);

            if (nodeName && nodeName != '*')
            {
                nodeName = nodeName.toUpperCase();
                return Array.filter(s, function(el) { return el.nodeName == nodeName; });
            }
            else
                return [].slice.call(s, 0);
        }
    }

    // xpath
    if (document.evaluate)
    {
        return  function(className, nodeName, parentElement)
        {
            if (!nodeName) nodeName = '*';
            if (!parentElement) parentElement = document;

            var results = [], s, i = 0, element;

            s = document.evaluate(
                ".//" + nodeName + "[contains(concat(' ', @class, ' '), ' " + className + " ')]",
                parentElement,
                null,
                XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
                null
            );

            while ((element = s.snapshotItem(i++)))
                results.push(element);

            return results;
        }
    }

    // generic
    return function(className, nodeName, parentElement)
    {
        if (!nodeName) nodeName = '*';
        if (!parentElement) parentElement = document;

        var results = [], s, i = 0, element;
        var re = new RegExp('(^|\\s)' + className + '(\\s|$)'), elementClassName;

        s = parentElement.getElementsByTagName(nodeName);

        while ((element = s[i++]))
        {
            if (    (elementClassName = element.className) &&
                (elementClassName == className || re.test(elementClassName))
            )
                results.push(element);
        }

        return results;
    }
}();
