/*******************************************************************************
 *Copyright 2009, 2010 Innovation Gate GmbH. All Rights Reserved.
 *
 *This file is part of the OpenWGA server platform.
 *
 *OpenWGA is free software: you can redistribute it and/or modify
 *it under the terms of the GNU General Public License as published by
 *the Free Software Foundation, either version 3 of the License, or
 *(at your option) any later version.
 *
 *In addition, a special exception is granted by the copyright holders
 *of OpenWGA called "OpenWGA plugin exception". You should have received
 *a copy of this exception along with OpenWGA in file COPYING.
 *If not, see <http://www.openwga.com/gpl-plugin-exception>.
 *
 *OpenWGA is distributed in the hope that it will be useful,
 *but WITHOUT ANY WARRANTY; without even the implied warranty of
 *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *GNU General Public License for more details.
 *
 *You should have received a copy of the GNU General Public License
 *along with OpenWGA in file COPYING.
 *If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
// htmlhead.js

/**
 *  define Namespace for WGA
 */
WGA=function(){
	var ua = navigator.userAgent.toLowerCase();
	isSafari= ua.indexOf("safari") > -1;
	isWebKit= ua.indexOf("webkit") > -1;
	isIE= ua.indexOf("msie") > -1;
	isIE7= ua.indexOf("msie 7") > -1;
	isGecko= !isWebKit && ua.indexOf("gecko") > -1;
	isFirefox= ua.indexOf("firefox") > -1;
	isFirefox3= ua.indexOf("firefox/3")>0;
	return{
		isSafari: isSafari,
		isWebKit: isWebKit,
		isIE: isIE,
		isIE7: isIE7,
		isGecko: isGecko,
		isFirefox: isFirefox,
		isFirefox3: isFirefox3
	}
}();


WGA.util={
	showException: function(msg, e){
		msg += "\n"
		if(e.fileName)
			msg += "file: " + e.fileName + "\n";
		if(e.lineNumber)
			msg += "line: " + e.lineNumber + "\n";
		
		alert(msg + "\n" + e.message)
	}
};

WGA.util.getURLTypeFromClassName=function(classname){
	var classes=classname.split(" ");
	for(var i=0; i<classes.length; i++){
		var c=classes[i].split("-");
		if(c[0]=="wga" && c[1]=="urltype"){
			return c[2];
		}
	}
	return null;
}

WGA.util.getLinkInfo=function(atag){
	// old style:
	var linktype=atag.getAttribute("linktype");
	var wgakey=atag.getAttribute("wgakey");
	if(!linktype){
		// new style:
		// link has class="wga-urltype-<linktype>"
		linktype=WGA.util.getURLTypeFromClassName(atag.className)||"exturl";
		var path = WGA.util.decodeURI(atag.href).split("/");
		if(linktype=="file"){
			var filename=path.pop();
			var container=path.pop();
			wgakey=container+"/"+filename;
		}
		else if (linktype=="exturl")
			wgakey=atag.href;
		else wgakey=path.pop();		// last element in path						
	}
	if(wgakey){	
		wgakey = wgakey.split("?")[0];
		wgakey = wgakey.split("#")[0];
	}
	
	return {
		type: linktype,
		key: wgakey
	}
}

WGA.util.decodeURI=function(url){
	return decodeURI(url.replace(/\+/g, " ").replace(/%2B/g, "+"));
}

/**
 * convert given html code and create scriptlets for links and images
 * @param {String} htmltext
 * @param {Object} config (optional)
 */
WGA.util.makeScriptlets=function(htmltext, config){

	var config = config||{};
	var document=config.document||window.document;
	var contentinfo=config.contentinfo||WGA.contentinfo;	
	var contentkey = contentinfo?contentinfo.contentkey:myContentKey;	// old style BI3 way
	var dbkey = contentinfo?contentinfo.dbkey:myDbKey;	// old style BI3 way

	/* internal Helper function used to convert old imgage urls into old scriptlet code */
	function convertWGAKeysToScriptlets(htmltext){
		//console.log("convertWGAKeysToScriptlets", htmltext);
		var server_host = self.location.hostname;
		var server_port = self.location.port;
		var server_protocol = self.location.protocol;
	
		var result=htmltext;
		
		// Replace contentKey
		
		// var keyRegExp = new RegExp(editor.contentkey.replace( /\./g, "\\.") ,'gi');
		// B00004486: problems with notes-migrated RTF-s
		// changed the regExp to ignore version  
		var k = contentkey.split(".");
		k.pop();				// remove last part (version)
		k.push("\\d+");			// add wildcard (any number) for version
		
		var keyRegExp = new RegExp(k.join("\\.")+"/", 'gi');	
		result = result.replace(keyRegExp , "{%$key%}/");
		
		// Replace absolute URLs by relative URLs		
		var tmpPort = server_port;
		if( tmpPort && tmpPort != null && tmpPort!=''){
			tmpPort = ":" + tmpPort;
		}

		// replace absolute URL-s containing dbkey:
		keyRegExp = new RegExp(server_protocol + "\/\/" +server_host + tmpPort + WGA.contextpath + "/" + dbkey,'gi' );
		result = result.replace(keyRegExp , "../../../{%$db:dbkey%}"); 
		
		// replace nearly absolute URL-s (without protocoll:server:port) containing dbkey:
		keyRegExp = new RegExp(WGA.contextpath + "/" + dbkey, 'gi');
		result = result.replace(keyRegExp , "../../../{%$db:dbkey%}"); 
		
		// Replace dbKeys in relative URLs entered by user ( MUST be executed AFTER absolute URLs. )
		keyRegExp = new RegExp("/" + dbkey.replace( /\./g, "\\.") + "/" ,'gi');	
		result = result.replace(keyRegExp , "/{%$db:dbkey%}/");
		
		//console.log("result-end", result);
		return result; 
	}

	// use browsers dom as HTML parser:
	var el = document.createElement("div");
	el.innerHTML = htmltext;
	
	// convert link urls to scriptlets
	var links = el.getElementsByTagName("a");
	for(var i=0; i<links.length; i++){
		var link = links.item(i);
		var linktype=link.getAttribute("linktype");
		if(linktype){
			// old style:
			// convert to new style and remove old attributes:
			link.removeAttribute("linktype");
			link.removeAttribute("wgakey");
			var c = link.className;
			c = c.replace(/wga-urltype-\w+ */, "");
			link.className = c + (c?" ":"") + "wga-urltype-" + linktype;
		}
		else{
			// new style:
			// link has class="wga-urltype-<linktype>"
			linktype=WGA.util.getLinkInfo(link).type;
		}

		var path = WGA.util.decodeURI(link.href).split("/");
		switch(linktype){
			/*
			 * Don't directly write URL to link.href because FF3 will encode this URL in this case
			 * So we write the URL to an Attribute "wga:href" that will later be removed by a regexp
			 */
			case "int":
				// calc structkey
				var structkey=path.pop();
				link.setAttribute("wga:href", "{%!contenturl:"+structkey+"%}");
				link.removeAttribute("href");
				break;
			case "intname":
				var uname=path.pop();
				link.setAttribute("wga:href", "{%!namedcontenturl:"+uname+"%}");
				link.removeAttribute("href");
				break;
			case "file":
				// calc filename and container
				var filename=path.pop();
				var container = path.pop();
				link.setAttribute("wga:href", "{%!fileurl:"+container+","+filename+"%}");
				link.removeAttribute("href");
				break;
			case "intfile":
				// calc filename
				var filename=path.pop();
				link.setAttribute("wga:href", "{%!fileurl:"+filename+"%}");
				link.removeAttribute("href");
				break;
		}

	}

	// convert IMG urls to scriptlets
	var imgs = el.getElementsByTagName("img");
	for(var i=0; i<imgs.length; i++){
		var img = imgs.item(i);
		var urltype = WGA.util.getURLTypeFromClassName(img.className);
		var path = WGA.util.decodeURI(img.src).split("/");
		switch(urltype){
			case "file":
				// calc filename and container
				var filename=path.pop();
				var container = path.pop();
				img.setAttribute("wga:src", "{%!imgurl:"+container+","+filename+"%}");
				img.removeAttribute("src");
				break;
			case "intfile":
				// calc filename
				var filename=path.pop();
				img.setAttribute("wga:src", "{%!imgurl:"+filename+"%}");
				img.removeAttribute("src");
				break;
			case null:
				/*
				 * B00004D6A
				 * WGA 4.1.1: convert only old style images instead of global convertWGAKeysToScriptlets()
				 * old style img-tags from wga 4.0:
				 */
				img.setAttribute("wga:src", convertWGAKeysToScriptlets(img.src));
				img.removeAttribute("src");
				break;
		}
	}

	var htmltext = el.innerHTML;
	htmltext = htmltext.replace(/wga:href="([^"]*)"/g, 'href="$1"') 
	htmltext = htmltext.replace(/wga:src="([^"]*)"/g, 'src="$1"') 

	return htmltext;
}


WGA.util.maskElement = function(el)
{

	/**
	 * Helper function to stop events in gekko browser
	 */
	function __moz_stopPropagation(event){
		event.stopPropagation();
	}

   	try{
		if(document.all){
			// for IE and Opera:
			el.style.width=el.offsetWidth; // IE and Opera needs a "layout-attribute" like width
   	    	el.style.filter="alpha(opacity:20)";
			// capture all mouse events until div is reloaded.			   	
			if (!window.opera) {						   	
				el.setCapture(true);					// IE: capture all mouse events
			} else {
				// for opera
				el.style.opacity=0.2;
				el.addEventListener('click', __moz_stopPropagation, true );
				el.addEventListener('mouseover', __moz_stopPropagation, true );
			}
		}
		else {
			// for mozilla:
			el.style.opacity=0.2;
			if (el.addEventListener) {
				el.addEventListener("click", __moz_stopPropagation, true);
				el.addEventListener("mouseover", __moz_stopPropagation, true);
			}
		}
	} catch(e){
		WGA.util.showException("mask-element", e);
	}			
}
WGA.util.unmaskElement = function(el){}

/**
 * Generates content urls, for usage by other js functions
 * @param {String} key
 */ 
WGA.buildContentURL=function (key) {

	if (requestType == 'statictml' || requestType == 'null') {
		return "";
	}
	if (mediaKeyMode == 1) {
		if (key != null) {
			return WGPPath + "/" + myLayout + "/" + key + "." + myMedium;
		}
		else {
			return WGPPath + "/" + myLayout + "." + myMedium;
		}
	}
	else {
		if (key != null) {
			return WGPPath + "/" + myMedium + "/" + myLayout + "/" + key;
		}
		else {
			return WGPPath + "/" + myMedium + "/" + myLayout;
		}
	}
}

/**
 * Loads content of the given key
 * DEPRECATED
 * WS: not sure, who uses this function.
 * @param {String} key
 */
function loadContent(key) {
	location.href = WGA.buildContentURL(key);	
}

/**
 * Module to register onload functions in WGA.
 * onload-s are attached to the window.onload-event and are called after Ajax calls
 */
WGA.onload=function(){
	
	var callbacks=[];	
	
	return{
	
		register: function(f){
			callbacks.push(f);
			return f;		
		},
		
		reset: function(){
			callbacks=[];
		},
		
		/**
		 * call all registered onload-s and deregister functions
		 */		
		execute:function(){			
			while(callbacks.length>0)
				callbacks.shift()();					
		}
	}
}()

// attach to window.onload:
if(window.addEventListener)
	window.addEventListener("load", WGA.onload.execute, true);
else if (window.attachEvent)
	window.attachEvent("onload", WGA.onload.execute);			


/**
 * Form submit function register. Registered functions are called in callAction before submitting the form
 * The form will only be submitted if the function returns true;
 */
WGA.b4submit=function(){
	var callbacks={};
	
	return{
	
		register: function(formid, f){
			if(!callbacks[formid])
				callbacks[formid]=[]
			callbacks[formid].push(f);
			return f;		
		},
		
		onsubmit: function(form){
			if(!form || form.id=="" || !callbacks[form.id])
				return true;

			for(var i=0; i<callbacks[form.id].length; i++){
				var f = callbacks[form.id][i];
				if(!f(form))
					return false;	// onsubmit-function returned false				
			}
			
			return true;				
		},
		
		reset: function(formid){
			callbacks[formid]=[];
		}
	}
}()

/**
 * Parses a JavaScript action link and divides it up into it's parts
 */
WGA.parseActionLink = function(actionLink) {

	var elements = actionLink.split("/");
	for (var i=0; i < elements.length; i++) {
		if (elements[i] == WGA.emptyActionParam) {
			elements[i] = null;
		}
	}
	
	switch (elements.length) {
	
		case 1:
			return {
				formID: null,
				portletKey: null,
				actionLink: elements[0]
			}
	
		case 2:
			return {
				formID: elements[0],
				portletKey: null,
				actionLink: elements[1]
			}
	
		case 3:
			return {
				formID: elements[0],
				portletKey: elements[1],
				actionLink: elements[2]
			}
			
		default: {
			alert("Error calling Action. Invalid number of action link parts:  "+ elements.length);
		}
	
	}
	
	

}

/**
 * generate action URL and open page
 * or submit the form if action comes from a form
 * @param {String} actionLink
 */
WGA.callAction=function(actionLink) {

	var link = WGA.parseActionLink(actionLink);

	if (link.formID == null) {
		location.replace(location.pathname + "?$action=" + link.actionLink);
	}
	else {
		var form = document.forms[link.formID];
		if( !form || !form.$formaction){
			alert("Error while calling action. TMLForm \"" + link.formID + "\" not found.");
			return false;
		}
		form.$formaction.value = link.actionLink;
	    if(WGA.b4submit.onsubmit(form))
			form.submit();
	}
	return true;
}


/****************************
 * AJAX handling
 */

/**
 * Namespace for AJAX methods
 */
WGA.ajax={
		
	portletFormCallbacks: {},		
	runningPortlets: {},
	
	hasRunningPortlets: function(){
		var now = (new Date()).getTime();
		for(var p in this.runningPortlets){
			var portlet_time=this.runningPortlets[p].getTime();
			if(now - portlet_time > 10000){
				delete this.runningPortlets[p];
				continue;
			}
			return true;
		}
		return false;
	}
};

/**
 * Object to register function to be called before ajax calls
 */
WGA.ajax.b4post=function(){

	var callbacks={};
	
	return{
		register: function(id, f){
			if(!callbacks[id])
				callbacks[id]=[];
			callbacks[id].push(f);
			return f;		
		},

		execute: function(id){
			while(callbacks[id] && callbacks[id].length>0)
				callbacks[id].shift()();	// call listener and shift it from array
		},
				
		reset: function(){
			callbacks={}
		}
	}
}()

/**
/* Call ajax action
/* @param {Object} actionDef - see de.innovationgate.wgpublisher.webtml.utils.AjaxActionDefinition
/*	      .action - actionlink
/*        .id     - portletId
/*        .graydiv - grayout portlet (true/false)
/*        .callback - custom callback function only executed outside an tmlform
/*        .mode 	- valid values "norefresh"
/*		  .tmlformSessionKey - sessionkey of server side tmlform (used during formcallback)
/**/
WGA.ajax.action=function (actionDef) {

	var link = WGA.parseActionLink(actionDef.action);
	if ((actionDef.id == undefined || actionDef.id == null) && link.portletKey != null) {
		actionDef.id = link.portletKey;
	}

	WGA.ajax.runningPortlets[actionDef.id] = new Date();

	if (link.formID == null) {
		// do post
		WGA.ajax.post(actionDef);
	}
	else {
		WGA.ajax.portletFormCallbacks[actionDef.id] = actionDef.callback;
		var form = document.forms[link.formID];
		if( !form || !form.$formaction){
			alert("Error while calling action. TMLForm \"" + link.formID + "\" not found.");
			return false;
		}
		form.$formaction.value = link.actionLink;
		form.$ajaxcallid.value = actionDef.id;
		
		if (actionDef.graydiv != undefined) {		
			form.$ajaxgraydiv.value = actionDef.graydiv;		
		} else {
			form.$ajaxgraydiv.value = '#null#';
		}
		
		if (actionDef.mode) {
			form.$ajaxmode.value = actionDef.mode;
		} else {
			form.$ajaxmode.value = '#null';
		}
		
		var iframename="$wga_ajaxIFrame_" + actionDef.id;
		var frame = document.getElementById(iframename);
		if(!frame) {
			frame = document.createElement('iframe');
	        frame.id = iframename;
	        frame.name = iframename;
	        
	        document.body.appendChild(frame);
	        if(WGA.isIE)
	        	document.frames[iframename].name = iframename;
		}
        frame.style.position="absolute";
        frame.style.visibility="hidden"	        
        frame.style.left = -10000;
        frame.style.top = -10000;	        
		
		form.target = iframename;
		form.action = WGA.contextpath + "/ajaxform";	
		
	    if(WGA.b4submit.onsubmit(form))
	    	form.submit();
	}
}

/**
 * Function called from iframe after a form is sumbittes via ajax
 * @param {Object} actionDef
 */
WGA.ajax.formCallback=function(actionDef) {
	actionDef.callback = WGA.ajax.portletFormCallbacks[actionDef.id];
	delete WGA.ajax.portletFormCallbacks[actionDef.id];
	WGA.ajax.post(actionDef);
}

/**
 * Old version of call ajax action
 * DEPRECATED
 * generate actionDef object and calls new ajax.action()
 * @param {Object} action
 * @param {Object} id
 * @param {Object} graydiv
 * @param {Object} callback
 */
WGA.ajax.callAction=function (action, id, graydiv, callback) {
	WGA.ajax.action({action:action, id:id, graydiv:graydiv, callback:callback});
}

/**
 * Send ajax request
 *
 * @param {String} method		
 * @param {string} uri			the uri to post the request to
 * @param {String} data			the data to post
 * @param {Function} callback	the function to be called on sucessfull answer from the server
 * @param {Object} header		optional: request headers
 */
WGA.ajax.request=function(method, uri, data, callback, header){

   	var xmlHttpReq = false;
    // Mozilla/Safari
    if (window.XMLHttpRequest) {
        xmlHttpReq = new XMLHttpRequest();
    }
    // IE
    else if (window.ActiveXObject) {
        xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
    }

	if(!xmlHttpReq)
		return alert("unable to get xmlHttpRqeuest Object");

    xmlHttpReq.onreadystatechange = function() {
		if (xmlHttpReq.readyState == 4) {
        	if(typeof(WGA)=="undefined")
        		return;		// page may be reloaded before callback was reached.

			callback(xmlHttpReq)

			// cleanup: so IE doesn't leak memory
			delete xmlHttpReq['onreadystatechange'];
			xmlHttpReq=null;
        }
    }
    
    var method = method.toUpperCase();
    xmlHttpReq.open(method, uri, true);
    if(header){
    	for(h in header)
    		xmlHttpReq.setRequestHeader(h, header[h]);
    }
    else if(method=="POST")
    	xmlHttpReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    
    xmlHttpReq.send(data);
}

/**
 * Do the ajax call 
 * @param {Object} actionDef
 */
WGA.ajax.post=function(actionDef) {

	var link = WGA.parseActionLink(actionDef.action);
	if ((actionDef.id == undefined || actionDef.id == null) && link.portletKey != null) {
		actionDef.id = link.portletKey;
	}
		
	// retrieve ajaxInfo object
	var ajaxInfo = eval("$ajaxInfo_" + actionDef.id);

	// build url
	var strURL = location.pathname + "?$action=" + link.actionLink;
	
	/** event maintenance **/
	if(actionDef.mode!="norefresh"){	
		// unregister all eventlistener of this portlet
		WGA.event.removeListeners(actionDef.id);
	}	
		
	/** portlet registration maintenance **/ 	
	//WGA.portlet.unregister(actionDef.id);
	
	// call registered b4post-listeners
	WGA.ajax.b4post.execute(actionDef.id);
	
    var divTag = document.getElementById("$ajaxContentDiv_" + actionDef.id);
    if(divTag!=null){
    	if(actionDef.graydiv==undefined || actionDef.graydiv){
    		WGA.util.maskElement(divTag)
    	}
    }
    else return; 
    
    // build absolute URL for post - HTMLUnit tests do not support referencial URLs
	var host = location.host;
	var protocol = location.protocol;
	var absoluteURL = protocol + "//" + host + strURL
	
	// do the request now:
	WGA.ajax.request("POST", absoluteURL,
		"$ajaxInfo=" + ajaxInfo + (actionDef.tmlformSessionKey?"&$ajaxformkey=" + actionDef.tmlformSessionKey:""),
		function (xmlHttpReq){
			// callback after request 
			delete WGA.ajax.runningPortlets[actionDef.id];
			//console.log(WGA.ajax.runningPortlets, WGA.ajax.hasRunningPortlets());
			
			if (actionDef.mode == 'norefresh') {
				WGA.ajax.callbackNoRefresh(xmlHttpReq);
			} else if (actionDef.callback==undefined) {
				WGA.ajax.replaceHTML(xmlHttpReq.responseText, actionDef.id);	// default action if no userdefined callback is given
			} else {
				actionDef.callback(xmlHttpReq);
				WGA.portlet.onload.execute(actionDef.id);
				WGA.event.fireEvents();
			}
			// if robottests enabled - setFinishedFlag
			if (WGA.robotTest) {
				WGA.robotTest.idle();
			}
		}
	)
	
}

/**
 * Replace div.innerHTML by string and ensure, that scripts are getting executed
 * @param {Object} str
 * @param {Object} id - id of the element to be replaced
 */
WGA.ajax.replaceHTML=function(str, id){	
    var divTag = document.getElementById("$ajaxDiv_" + id);
    if (divTag==null)
    	return;
    // IE does not recognize the first script tag by getElementsByTagName
    // if there is no html:tag with content in front
    // so add a none displayed span-tag in front of the pasted code
	divTag.innerHTML = "<div id='$ajaxContentDiv_" + id + "'><span style=\"display:none\">ajax</span>" + str + "</div>";
	
    // evaluate pasted javascript
    var scripts = divTag.getElementsByTagName("script");
	if(WGA.isIE){
	    for (var i = 0; i < scripts.length; i++) {
	    	var script = scripts[i].text;
			WGA.ajax.executeScriptElement(script);
		}
		WGA.portlet.onload.execute(id);
		WGA.event.fireEvents();
	}
	else{
		var totalscripts="";
	    for (var i = 0; i < scripts.length; i++) {
			var script = scripts[i].innerHTML;
			totalscripts += "\n"+script;
		}
		totalscripts += "\nWGA.portlet.onload.execute('"+id+"');";
		totalscripts += "\nWGA.event.fireEvents();";
		window.setTimeout(totalscripts, 10);
	}
}

/**
 * The following function is used when we are in IE only
 * @param {Object} script
 */
WGA.ajax.executeScriptElement=function(script) {
	var script_element = document.createElement("script");
	// first append as child of head
	// Opera execute scripts twice if the next to lines are changed in order
	//script_element.text = script;
	document.getElementsByTagName("head")[0].appendChild(script_element);	    	    				
	script_element.text = script;
	document.getElementsByTagName("head")[0].removeChild(script_element);
}

/**
 * execute a ajax response as script
 * The response should only contain one single javascript text (like in JSON responds)
 * @param {Object} xmlHttpReq
 */
WGA.ajax.callbackNoRefresh=function(xmlHttpReq) {
	var script = xmlHttpReq.responseText;
	script += "\nWGA.event.fireEvents();";
	if(WGA.isIE)
		WGA.ajax.executeScriptElement(script);
	else window.setTimeout(script, 10);
}
/*	--- end AJAX Handling ---


/*************************
   event handling		
*/
WGA.event = function(){

	var eventStack = [];
	var listeners = {};
	var timer;
	
	return{
	
		/**
		 * dispacht an event (put it on event stack)
		 * the event is not fired.
		 * use this function to dispacht multiple events and then call fireEvents() 
		 * @param {Object} event
		 */
		dispatch: function(event){
			eventStack.push(event);
		}
		
		/**
		 * dispacht an event (put it on event stack) and fires the event.
		 * @param {Object} event
		 */
		,fireEvent: function(eventname, source, params){
			WGA.event.dispatch({
				name: eventname,
				source: source||"WGA",
				params: params||{}
			});
			WGA.event.fireEvents()
		}

		/**
		 * register an eventlistener for a portlet and event
		 * @param {Object} pKey - portlet key
		 * @param {Object} eventName
		 * @param {Object} f - function to be called back when event fires
		 */
		,addListener: function(pKey, eventName, f) {
			if (!listeners[pKey]) {
				listeners[pKey] = {}
			}
			listeners[pKey][eventName] = f;
		}
		
		/**
		 * unregister all eventlistener of this portlet and all its child portlets
		 * @param {Object} pKey - portlet key
		 */
		,removeListeners: function(pkey){
			delete listeners[pkey]; 		
			// unregister all eventlistener of child portlets
			WGA.portlet.forEachChild(pkey, WGA.event.removeListeners);
		}

		/**
		 * fire all events (call event listeners) on event stack end delete event from stack
		 */
		,fireEvents: function() {
			if(WGA.ajax.hasRunningPortlets()){
				if(timer)
					window.clearTimeout(timer)
				timer = window.setTimeout(WGA.event.fireEvents, 1000);
				return;
			}
			while (eventStack.length > 0) {
				var event = eventStack.shift();
				for (var i in listeners) {
					if (listeners[i][event.name]) {
						try{
							listeners[i][event.name](event);
						}
						catch(e){
							// catch JS-error in event listeners to ensure ALL listeners will be called.
							WGA.util.showException("Error in WGA event listener for event '" + event.name+"'", e);							
						}
					}
				}
			}
		}

				
	}
	
}();

/**
 * If the page is laoded, call WGA.event.fireEvents() 
 */
WGA.onload.register(WGA.event.fireEvents);
/*   end event handling		*/


/**
 * portlet registry	   
 */
WGA.portlet = function(){

	// local variables:
	var childRegistry = {};
	var parentRegistry = {};
	var objectReg = {};

	function destroyObjects(portletkey){
		var objects = objectReg[portletkey];
		if(objects){
			for(var i=0; i<objects.length; i++){
				var o = objects[i];
				if(o.destroy)
					o.destroy(portletkey)
				delete o;
			}
		}
		delete objectReg[portletkey]
	}	
	
	return{
		/**
		 * WGA.portlet.onload registers function to be called when a portlet is refreshed by an ajax call
		 * Callbacks are not called on page loads like WGA.onload (why not ???)
		 * Because WGA.onload may have problems when many portlets are refreshed at the same time, WGA.portlet.onload
		 * is the better way to register callbacks
		 */
		onload: function(){
			
			var reg={};		// local var to srore callbacks
			
			return{
				
				/*
				 * register a function to be called when the portlet is loaded via ajax or a page refresh
				 * @param {Object} pkey - portlet key
				 */
				register: function(pkey, f){
					if(pkey=="")
						return WGA.onload.register(f);
					if(!reg[pkey])
						reg[pkey]=[];
					reg[pkey].push(f);
					return f;		
				},
								
				/**
				 * execute all registered onload-s for one portlet and delete it from registry
				 * will be called automaticaly on ajax-loads and should not be called directly
				 * the registered function will be called with the portlet key as parameter
				 * @param {Object} pkey - portlet key
				 */
				execute: function(pkey){
					try{
						var fns=reg[pkey];
						while(fns && fns.length>0)
							fns.shift()(pkey);
						// execute onload-s for all childportlets:
						WGA.portlet.forEachChild(pkey, WGA.portlet.onload.execute);
					}catch(e){
						WGA.util.showException("portlet.onload exception", e);
					}
				},
				
				/**
				 * execute all registered onload-s for ALL portlets (and delete them from registry)
				 * will be called automaticaly on window.onload and should not be called directly
				 */
				executeAll: function(){
					for(pkey in reg){
						WGA.portlet.onload.execute(pkey);
					}
				}
			}
		}()	// end onload
		
		/*
		 * register portlet.
		 * @param {Object} pkey - portlet key		 
		 */		
		,register: function(pKey, parentKeys){
			// check if we have child portlets and destroy all registered objects
			this.forEachChild(pKey, destroyObjects)
			destroyObjects(pKey);
			
			// add portlet as parent to child registry
			childRegistry[pKey] = {};	
			for (var i=0; i<parentKeys.length; i++) {
				var key = parentKeys[i];
				childRegistry[key][pKey] = pKey;
			}			
			// add portlet to parent registry
			parentRegistry[pKey] = parentKeys;
		}

		/*
		 * unregister portlet. remove is from all parents and delete it from registries
		 * @param {Object} pkey - portlet key		 
		 */		
		,unregister: function(pkey){
			// remove this portlet as child from each parent
			var parentKeys = parentRegistry[pkey];
			for (var i=0; parentKeys && i<parentKeys.length; i++) {
				var parentKey = parentKeys[i];
				if(childRegistry[parentKey] && childRegistry[parentKey][pkey])
					delete childRegistry[parentKey][pkey];
			}
			delete childRegistry[pkey];
			delete parentRegistry[pkey];
		}
		
		/*
		 * utility function to call a user provided function for all childportlets
		 * the provided function will be called with the childrens portletkey as parameter
		 * @param {Object} pkey - portlet key		 
		 * @param {Object} f - the function to be called for each child portlet		 
		 */		
		,forEachChild: function(pkey, f){
			var childportlets = childRegistry[pkey];
			for(var i in childportlets)
				f(childportlets[i])
		}
		
		,registerObject: function(portletkey, obj){
			if(!objectReg[portletkey])
				objectReg[portletkey] = [];
			objectReg[portletkey].push(obj);
			return obj;
		}
		
	}
}();

// ensure portlet.onload-s will be called on window.onload as well:
WGA.onload.register(WGA.portlet.onload.executeAll);

/*   end portlet registry	*/

/*****************************************************************************
	Stay compatible with older WGA versions:
*/
callAction=WGA.callAction;
callAjaxAction=WGA.ajax.callAction;
ajaxFormCallback=WGA.ajax.formCallback;

// deprecated:
WGA.event.register=WGA.event.addListener;
