function PrezentDomApi() {
    this.version = '0.2';
    this.eventCache = new PrezentDomApi.EventCache();
    this.actionAttacher = null;
};

// Static domloader variables
PrezentDomApi.domLoad = [];
PrezentDomApi.domLoaderSet = false;

/**
 * TagEvent class.
 * @version 1.0
 */
PrezentDomApi.TagEvent = function (tagName, className, act, func) {
    this.tagName = tagName.toLowerCase();
    this.className = className;
    this.act = act;
    this.func = func;
}
PrezentDomApi.TagEvent.prototype.matches = function(tagName, className) {
    if (tagName.toLowerCase() != this.tagName) {
        return false;
    }
    return (this.className == null || new RegExp(this.className+"([\\W\\s]|$)").test(className));
};

/**
 * ActionAttacher class.
 * attaches events to tags by their tagName / classname.
 * Use actionAttacher.addTagEvent to add an event to a tag / className combination.
 */
PrezentDomApi.ActionAttacher = function() {
    this.tagEvents = [];
    this.counter = 0;
}

/* Runs onload to attach all TagEvents */
PrezentDomApi.ActionAttacher.prototype.attach = function(rootElem) {
    var tagEvents = this.tagEvents;
    var tags = {}, elems, len, j;
	var rootElem = rootElem || document.body;

    // Loop trough all tagEvents to retreive tag
    for (var k=0; k < tagEvents.length; k++) {
        if (typeof tags[tagEvents[k].tagName] != 'undefined') {
            continue;
        }
        // add HTMLCollection to tags array
        tags[tagEvents[k].tagName] = rootElem.getElementsByTagName(tagEvents[k].tagName);
    }

    // Loop trough all tags where events should be attached to
    for (j in tags) {
        elems = tags[j];
        len = elems.length;

        for (var i=0; i < len; i++) {

            // Loop trough events
            for (k=0; k < tagEvents.length; k++) {
                // check if we have a tag- and classname match
                if (tagEvents[k].matches(elems[i].tagName, elems[i].className)) {
                    // Check if action is 'attach', this means we execute the method on attach
                	if (tagEvents[k].act == 'attach') {
                    	tagEvents[k].func(elems[i]);
                    } else {
                    	// Add event on match
                    	pDomApi.addEvent(elems[i], tagEvents[k].act, tagEvents[k].func);
                    }
                }
            }
        }
    }

};
/* Add tag event to action attacher */
PrezentDomApi.ActionAttacher.prototype.addTagEvent = function (tEvent) {
    this.tagEvents.push(tEvent);
    return this.counter++;
};

PrezentDomApi.prototype.getActionAttacher = function () {
	if (this.actionAttacher) {
		return this.actionAttacher;
	}
	var me = this;
	this.actionAttacher = new PrezentDomApi.ActionAttacher();
	this.addEvent(window, 'domload', function() { me.actionAttacher.attach();});
	return this.actionAttacher;
};

PrezentDomApi.EventCache =  function() {

	var listEvents = [];

	return {
		listEvents : listEvents,
		add : function(node, sEventName, fHandler){
			listEvents.push(arguments);
		},
		flush : function() {
			var i, item;
			for(i = listEvents.length - 1; i >= 0; i = i - 1){
				item = listEvents[i];
				if(item[0].removeEventListener){
					item[0].removeEventListener(item[1], item[2], item[3]);
				};
				if(item[1].substring(0, 2) != "on"){
					item[1] = "on" + item[1];
				};
				if(item[0].detachEvent){
					item[0].detachEvent(item[1], item[2]);
				}
				item[0][item[1]] = null;
			}
		}
	};

}

/* Runs on dom load if needed */
PrezentDomApi.domLoaded = function() {

    if (arguments.callee.done) { return; }
    arguments.callee.done = true;

    for (var i = 0;i < PrezentDomApi.domLoad.length;i++) {
        PrezentDomApi.domLoad[i]();
    }
};


/**
 * Sets a classname for element elem, eventually replacing other classname(s)
 * @param   HTMLElement     elem
 * @param   String          className
 * @param   String/Array    replace
 * @since   0.1
 */
PrezentDomApi.prototype.setClassName = function(elem, className, replace) {
	var replaceArr = [className];
    var newClassName = elem.className;


    // determine replace parameter type (note that it can also be undefined, that case is not handled)
    switch ((typeof replace).toLowerCase()) {
        case 'string':
            replaceArr.push(replace);
            break;
        case 'object':
            replaceArr = replaceArr.concat(replace);
            break;
    }

    // replace all classNames in the replaceArray with a space
    for (var i = 0; i < replaceArr.length; i++) {
        newClassName = newClassName.replace(new RegExp("(^|\\s)" + replaceArr[i] + "(\\s|$)", "g"), ' ');
    }
    // set the new classname
    elem.className = newClassName.trim() + (newClassName.length > 0 ? ' ' : '') + className;
};

/**
 * Sets a classname for element elem, eventually replacing other classname(s)
 * @param   Array           elems       Array of HTMLElements
 * @param   String          className
 * @param   String/Array    replace
 * @since   0.1
 */
PrezentDomApi.prototype.setClassNames = function(elems, className, replace) {
    for (var i in elems) {
        this.setClassName(elems[i]);
    }
};

// elem: (string || object) string of elements id, or a reference to the element itself
// act:  (string) eventname without the 'on' prefix. (load, click, mouseover, etc.)
// func: (unquoted string) functionname of the function to execute on event fire.
PrezentDomApi.prototype.addEvent = function(elem, act, func) {

    if(typeof elem == 'string') {
        elem = document.getElementById(elem);
    }

    if(!elem) return false;

    if (act == 'domload' && elem == window) {
        this.addDomLoadEvent(func);
    }

    if (window.addEventListener) {
       elem.addEventListener(act, func, false);
       this.eventCache.add(elem, act, func);
    }
    else if (window.attachEvent) {
    	elem["e"+act+func] = func;
    	elem[act+func] = function() { elem["e"+act+func](window.event); };
        elem.attachEvent('on'+act, elem[act+func]);
        this.eventCache.add(elem, act, func);
    }
    else { return false; }
    return true;
};

PrezentDomApi.prototype.addDomLoadEvent = function(func) {

    PrezentDomApi.domLoad.push(func);
    if (PrezentDomApi.domLoaderSet) {
        return false;
    }

	if (document.addEventListener) {
		document.addEventListener("DOMContentLoaded", PrezentDomApi.domLoaded, null);
    }
	if (/KHTML|WebKit/i.test(navigator.userAgent)) {
		var _timer = setInterval(function()	{
			if (/loaded|complete/.test(document.readyState)) {
				clearInterval(_timer);
				delete _timer;
				PrezentDomApi.domLoaded();
			}
		}, 25);
	}
	/*@cc_on @*/
	/*@if (@_win32)
	var proto = "src='javascript:void(0)'";
	if (location.protocol == "https:") proto = "src=//0";
	document.write("<scr"+"ipt id=__ie_onload defer " + proto + "><\/scr"+"ipt>");
	var script = document.getElementById("__ie_onload");
	script.onreadystatechange = function() {
	    if (this.readyState == "complete") {
	        PrezentDomApi.domLoaded();
	    }
	};
	/*@end @*/
   this.addEvent(window, 'load', PrezentDomApi.domLoaded);
   PrezentDomApi.domLoaderSet = true;
};

// Call this function with the same arguments as you did with AddEvent
// to remove the eventlistener.
PrezentDomApi.prototype.removeEvent = function(elem, act, func) {
    if(typeof elem == 'string') {
        elem = document.getElementById(elem);
    }

    if(!elem) return false;

    if(window.removeEventListener) {
       elem.removeEventListener(act, func, false);
    }
    else if(window.detachEvent) {
        elem.detachEvent('on'+act, func);
    }
};

/*
    Written by Jonathan Snook, http://www.snook.ca/jonathan
    Add-ons by Robert Nyman, http://www.robertnyman.com
    Added support for native getElementsByTagName implementation (supported in Firefox 3)
    http://ejohn.org/blog/getelementsbyclassname-in-firefox-3/
*/
PrezentDomApi.prototype.getElementsByClassName = function(className, tagName, elm){
    var arrReturnElements = [];
    var tagName = tagName || "*";
	var elm = elm || document;

    // Check for native getElementsByClassName implementation (FF3, Safari 3.1, Opera 9.5)
    if (elm.getElementsByClassName) {
        var arrElements = elm.getElementsByClassName(className);
        var nodeName = (tagName != '*')? new RegExp("\\b" + tagName + "\\b", "i") : null;

        for (var i=0; i < arrElements.length; i++){
        	if(! nodeName || nodeName.test(arrElements[i].nodeName)) {
        		arrReturnElements.push(arrElements[i]);
			}
        }
        return arrReturnElements;
    }

    var arrElements = (tagName == "*" && elm.all) ? elm.all : elm.getElementsByTagName(tagName);

    className = className.replace(/\-/g, "\\-");
    var oRegExp = new RegExp("(^|\\s)" + className + "(\\s|$)");
    var oElement;
    for (var i=0; i<arrElements.length; i++){
        oElement = arrElements[i];
        if(oRegExp.test(oElement.className)){
            arrReturnElements.push(oElement);
        }
    }
    return arrReturnElements;
};

PrezentDomApi.prototype.hasClassName = function(oElm, strClassName) {
    var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
    return oRegExp.test(oElm.className);
};

PrezentDomApi.prototype.showHide = function(elem, hide, show) {
    var hide = hide == undefined ? 'hide' : hide;
    var show = show == undefined ? 'show' : show;

    elem.className = new RegExp(hide).test(elem.className) ?
        elem.className.replace(new RegExp(hide), show) :
        elem.className.replace(new RegExp('\\s?'+ show), '') + ' ' + hide;

};

PrezentDomApi.prototype.preventDefault = function(event) {
    if (event.preventDefault) {
        event.preventDefault();
    } else {
        event.returnValue = false;
    }
};

var pDomApi = new PrezentDomApi();
// flush events
pDomApi.addEvent(window, 'unload', pDomApi.eventCache.flush);


/* Extra helper functions */
if (typeof window.eId != 'function') {
    function eId() {
        var elements = new Array();

        for (var i = 0; i < arguments.length; i++) {
            var element = arguments[i];
            if (typeof element == 'string') { element = document.getElementById(element); }

            if (arguments.length == 1) { return element; }

            elements.push(element);
        }

        return elements;
    };
}

String.prototype.trim = function() {
    var str = this.replace(/^\s\s*/, ''),
        ws = /\s/,
        i = str.length;
    while (ws.test(str.charAt(--i)));
    return str.slice(0, i + 1);
};
/*
 * $Id: common.js,v 1.1 2006-05-18 15:48:37 sven Exp $
 */
function newWindow(mypage,myname,w,h,features) {

	if(screen.width){
		var winl = (screen.width-w)/2;
		var wint = (screen.height-h)/2;
	}
	else{winl = 0;wint =0;}
	if (winl < 0) winl = 0;
	if (wint < 0) wint = 0;

	var settings = 'height=' + h + ',';
	settings += 'width=' + w + ',';
	settings += 'top=' + wint + ',';
	settings += 'left=' + winl + ',';
	settings += features;

	win = window.open(mypage,myname,settings);
	win.name = 'opener';
	win.window.focus();
}

var getElemsByRel = function(rel){

    aElements = document.getElementsByTagName("a");
    relElems = new Array();
    for (i = 0; i < aElements.length; i++) {
        if (aElements[i].getAttribute("rel") && aElements[i].rel == rel) {
            relElems.push(aElements[i]);
        }
    }
	return relElems;
}

function showHideSubMenu() {
	var submenu = this.nextSibling;

	while (submenu.nodeType != 1 || submenu.tagName.toLowerCase() != 'ul') {
		submenu = submenu.nextSibling;
	}

	pDomApi.showHide(submenu, 'show', 'hide');
}

function formAction(e) {
	if (e.stopEvents) {
		return false;
	}
	var inputs = this.getElementsByTagName('input');
	var form = eId('itemListForm');
	if (! form) {
		return false;
	}
	form.innerHTML = '';
	if (this.getAttribute('href') != '') {
		form.setAttribute('action', this.getAttribute('href'));
	}

	for (var i =0; i < inputs.length; i++) {
		form.appendChild(inputs[0]);
	}
	pDomApi.preventDefault(e);
	form.submit();
	return true;
}

pDomApi.getActionAttacher().addTagEvent(new PrezentDomApi.TagEvent('a', 'popup', 'click', function(e) {
	var targ = e.target ? e.target : e.srcElement;

    while (targ.nodeType != 1 || targ.tagName.toLowerCase() != 'a') {
    	targ = targ.parentNode;
    }

    newWindow(targ.href,'TNO_Workshop',600,500,"");
    pDomApi.preventDefault(e);
}));

pDomApi.getActionAttacher().addTagEvent(new PrezentDomApi.TagEvent('a', 'selectAllButton', 'click', function(e) {
	var form = document.getElementById('linkTopics');
	// First check wether the elements are all checked or all unchecked or partly checked
	var check = 0;
	var uncheck = 0;
	for (i = 0; i < form.elements.length; i++) {
		if (form.elements[i].type == "checkbox") {
			if(form.elements[i].checked == true) {
				check++;
			} else {
				uncheck++;
			}
		}
	}
	if (uncheck == 0) {
		value = false;
	} else {
		value = true;
	}
	for (i = 0; i < form.elements.length; i++) {
		if (form.elements[i].type == "checkbox") {
			form.elements[i].checked = value;
		}
	}
	return false;

}));

pDomApi.getActionAttacher().addTagEvent(new PrezentDomApi.TagEvent('span', 'parentItem', 'click', showHideSubMenu));

pDomApi.getActionAttacher().addTagEvent(
		new PrezentDomApi.TagEvent('a', 'formAction', 'click', formAction));
function _hs_findOptions(ary, keys) {
    var key = keys.shift();
    if (typeof ary == 'undefined' || !key in ary) {
        return {};
    } else if (0 == keys.length) {
        return ary[key];
    } else {
        return _hs_findOptions(ary[key], keys);
    }
}

function _hs_findSelect(form, groupName, selectIndex) {
    if (groupName+'['+ selectIndex +']' in form) {
        return form[groupName+'['+ selectIndex +']'];
    } else {
        return form[groupName+'['+ selectIndex +'][]'];
    }
}

function _hs_unescapeEntities(str) {
    var div = document.createElement('div');
    div.innerHTML = str;
    return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
}

function _hs_replaceOptions(ctl, optionList) {
    var j = 0;
    ctl.options.length = 0;


    pDomApi.setClassName(ctl, 'show', 'hide');

    for (var i in optionList) {
        var optionText = (-1 == String(optionList[i]).indexOf('&'))? optionList[i]: _hs_unescapeEntities(optionList[i]);
        ctl.options[j++] = new Option(optionText, i, false, false);
    }
    if (! i) {
        pDomApi.setClassName(ctl, 'hide', 'show');
    }

}

function _hs_setValue(ctl, value) {
    var testValue = {};
    if (value instanceof Array) {
        for (var i = 0; i < value.length; i++) {
            testValue[value[i]] = true;
        }
    } else {
        testValue[value] = true;
    }
    for (var i = 0; i < ctl.options.length; i++) {
        if (ctl.options[i].value in testValue) {
            ctl.options[i].selected = true;
        }
    }
}

function _hs_swapOptions(form, groupName, selectIndex) {
    var hsValue = [];
    for (var i = 0; i <= selectIndex; i++) {
        hsValue[i] = _hs_findSelect(form, groupName, i).value;
    }

    _hs_replaceOptions(_hs_findSelect(form, groupName, selectIndex + 1),
                       _hs_findOptions(_hs_options[groupName][selectIndex], hsValue));
    if (selectIndex + 1 < _hs_options[groupName].length) {
        _hs_swapOptions(form, groupName, selectIndex + 1);
    }

    // Fucking IE7 needs this to redraw the map
    if (eId('map')) {
    	eId('map').className = eId('map').className
    }
}

function _hs_onReset(form, groupNames) {
    for (var i = 0; i < groupNames.length; i++) {
        try {
            for (var j = 0; j <= _hs_options[groupNames[i]].length; j++) {
                _hs_setValue(_hs_findSelect(form, groupNames[i], j), _hs_defaults[groupNames[i]][j]);
                if (j < _hs_options[groupNames[i]].length) {
                    _hs_replaceOptions(_hs_findSelect(form, groupNames[i], j + 1),
                                       _hs_findOptions(_hs_options[groupNames[i]][j], _hs_defaults[groupNames[i]].slice(0, j + 1)));
                }
            }
        } catch (e) {
            if (!(e instanceof TypeError)) {
                throw e;
            }
        }
    }
}

function _hs_setupOnReset(form, groupNames) {
    setTimeout(function() { _hs_onReset(form, groupNames); }, 25);
}

function _hs_onReload() {
    var ctl;
    for (var i = 0; i < document.forms.length; i++) {
        for (var j in _hs_defaults) {
            if (ctl = _hs_findSelect(document.forms[i], j, 0)) {
                for (var k = 0; k < _hs_defaults[j].length; k++) {
                    _hs_setValue(_hs_findSelect(document.forms[i], j, k), _hs_defaults[j][k]);
                }
            }
        }
    }

}

pDomApi.addEvent(window, 'load', _hs_onReload);

var _hs_options = {};
var _hs_defaults = {};
