//used to mark form dirty and warn user to save first.
var o2c=0;
var o3c=new Array();//array holds flexi.form id's
o_info.guibusy = false;


// Each flexible.form item with an javascript 'on...' configured calls this fn.
// It is called at least if a flexible.form is submitted.
// It submits the component id as hidden parameters. This specifies which 
// form item should be dispatched by the flexible.form container. A second
// parameter submitted is the action value triggering the submit.
// A 'submit' is not the same as 'submit and validate'. if the form should validate
// is defined by the triggered component.
function o_ffEvent (formNam, dispIdField, dispId, eventIdField, eventInt){
	//set hidden fields and submit form
	var elem = document.getElementById(dispIdField);
	elem.value=dispId;
	elem = document.getElementById(eventIdField);
	elem.value=eventInt;
	document.forms[formNam].submit();
}


function o_init() {
	try {
		// all init-on-new-page calls here
		//return opener window
		o_getOpenWin().o_afterserver();	
	} catch(e) {}	
}

function o_getOpenWin() {
	var w = top;
	try {
		if (w.opener && w.opener.o_info) {
			w = w.opener;
		}
	} catch (e) {}
	return w;
}

o_info.linkbusy = false;

function o2cl() {
	// alert("busy:"+o_info.linkbusy);
	if (window.frames['oaa'] && o_info.linkbusy) {
		return false;
	} else {
		var doreq = (o2c==0 || confirm(o_info.dirty_form));
		if (doreq) {
			o_beforeserver();
			if (window.olatonunload) olatonunload();
		}
		return doreq;
	}
}

function o3cl(formId) {
	if (o_info.linkbusy) {
		return false;
	} else {
		if (window.olatonunload) olatonunload();
		
		//detect if another flexi form on the screen is dirty too
		var isRegistered = o3c1.indexOf(formId) > -1;
		var flexiformdirty = (isRegistered && o3c1.length > 1) || o3c1.length > 0;
		
		//check if no other flexi form is dirty
		//otherwise ask if changes should be discarded.
		var doreq = ( !flexiformdirty || confirm(o_info.dirty_form));
		if (doreq) o_beforeserver();
		return doreq;
	}
}

function o_ajaxwins() {
	for (var key in o_info.wins) {
    	var curwin = o_info.wins[key];
    	if (curwin.closed) {
    		delete o_info.wins[key];
    		//todo: notify server that window has been closed
    	} 
    }
    window.setTimeout("o_ajaxwins()", 1280);
}
// on ajax poll complete
function o_onc(response) {
	var te = response.responseText;
	var r;
	eval("r="+te+";");
	o_ainvoke(r);
}

function o_winmgrinit() {
	o_mainregister(o_info.o_winid, this.window);
	o_ajaxwins();
	setTimeout(function() { o_cajax(); }, pollperiod);
}


function o_beforeserver() {
	o_info.linkbusy = true;
	o_info.busyon = true;
	setTimeout("showAjaxBusy()",1000);
	//to prevent sending a second request while the response of the first one is one the way
	//we disable following requests for 1,5s
	setTimeout("o_allowNextClick()",1500);
}

function o_allowNextClick() {
	o_info.linkbusy = false;
	removeBusy();
}

function o_afterserver() {
	o_allowNextClick();
	removeAjaxBusy();
}

function showerror(e) {
	var r = "";
    for (var p in e)
      r += p + ": " + e[p] + "\n";
    return "error detail:\n"+r;
}


function o_mainregister(winid, win) {
	o_info.wins[winid] = win;
}
//remove busy after clicking a download link in non-ajax mode
//use LinkFactory.markDownloadLink(Link) to make a link call this method.
function removeBusyAfterDownload(e,target,options){
	o2c = 0;
	o_afterserver();
}

function o_ainvoke(r) {
	// commands
	var cmdcnt = r["cmdcnt"];
	if (cmdcnt > 0) {
		var cs = r["cmds"];
		for (var i=0; i<cmdcnt; i++) {
			var acmd = cs[i];
			var co = acmd["cmd"];
			var cda = acmd["cda"];
			var wid = acmd["w"];
			var wi = o_info.wins[wid]; 
			var out;
			if (wi) {
				switch (co) {
					case 1: // specific command
						var f = cda["f"];
						var jso = cda["jso"];
						var cdata = cda["data"];
						var e1;
						try {
							eval("e1 = wi."+jso);
							if (e1) {
								eval("e1."+f+"(cdata)");
							} else {
								// if a component function was not found
								if (isdebug) alert ("function f = '"+f+"' not found");
							}
							
						} catch (e) {
							if (isdebug) alert("eval error: jso='"+jso+"', exception:"+e);
						}
						
						break;
					case 2:  // redraw components command
						//hide info/error message before
						var om = wi.$("o_messages"); if (om) Element.hide(om);						
						//now paint waiter
						var cnt = cda["cc"];
						var ca = cda["cps"];
						for (var j=0;  j<cnt; j++) {
							var c1 = ca[j];
							var ciid = c1["cid"]; // component id
							var civis = c1["cidvis"];// component visibility
							var hfrag = c1["hfrag"]; // html fragment of component
							var jsol = c1["jsol"]; // javascript on load
							var hdr = c1["hdr"]; // header
							var con = hfrag.stripScripts();
							var hdrco = hdr+"\n\n"+con;
							var inscripts = hfrag.extractScripts();
							var newc = wi.document.getElementById("o_c"+ciid);
							if (newc == null) {
								if (isdebug) alert("could not find comp with id: o_c"+ciid+",\nname: "+c1["cname"]+",\nlistener(s): "+c1["clisteners"]+",\n\nhtml:\n"+hfrag);
							} else {
								if(civis){
									newc.style.display="";//reset?
								}else{
									newc.style.display="none";
								}
								newc.innerHTML = hdrco;	
								if (inscripts!= "") {
									try {
										inscripts.each(
											function(val) { 
												if (wi.ActiveXObject){ 
													wi.execScript(val);
												} else {
													//to reach global scope: timeout instead of wi.eval(val);
													wi.setTimeout(val,0);
												}
											} );
									} catch(e2) {
										if (isdebug) {
											var s = "";
											inscripts.each(function(val) { s+= "\nERROR:::"+val;});
											alert("inscripts error:"+showerror(e2)+"\n\nfor: "+s);
										}
									}
								}
								if (jsol != "") {
									try {
										if (wi.ActiveXObject){ 
											wi.execScript(jsol);
										} else {
											wi.setTimeout(jsol,0);
										}
									} catch(e2) {
										if (isdebug) { 
											alert("jsol2 error:"+showerror(e2)+"\n\nwhile executing:::\n:::"+jsol+":::");
										}
									}
								}
								if (ishighlight) new Effect.Highlight(newc);
							}
						}
						break;
					case 3:  // createParentRedirectTo
						wi.o2c = 0;
						var rec = o_info.o_baseURI+"m/";
						var rurl = cda["rurl"];
						if(rurl.indexOf(rec) != -1){
							//in case of a mapper served media resource (xls,pdf etc.)
							wi.o_afterserver();
						}
						wi.document.location.replace(rurl);
						break;
					case 6: // createPrepareClientCommand
						wi.o2c = 0;
						wi.o_afterserver();
						break;
					case 4: // reload e.g. in case where a command could not be dispatched to the component
						if (isdebug) alert("now reloading win since not dispatched");
						wi.document.location.reload();
						break;
					default:
						if (isdebug) alert("unknown command "+co); 
						break;
				}		
			} else {
				// window closed
			}		
		}
	}
	//o_afterserver();
}
//
// wrapper for show busy calls from event listeners added with EXTjs
// param e is an Ext.EventObject
// param target is an Ext.Element
// param options is an object (literal) with name, value pairs like options.myName
function extShowBusy(e,target,options){
	showBusy(options.captionText);
}

function showBusy(captionText) {
	// Add an overlay div and on top of the div 
	// a layer that contains a busy message with a caption.
	// The reason why this is done dynamically is to not bloat the
	// HTML code and to prevent IE to render the page ugly due to 
	// CSS and background images bugs
	// (fg)
	// add overlay div at very top of page
	var root = document.getElementsByTagName("body")[0];
	var overlay = document.createElement("div");
	overlay.id="o_overlay";
	root.insertBefore(overlay, root.firstChild);
	// add busy layer, also on top
	var busy = document.createElement("div");
	busy.id="o_busy";
	// add busy caption	
	var caption = document.createElement("div");
	caption.id="o_busyCaption";
	caption.innerHTML=captionText;
	busy.appendChild(caption);
	root.insertBefore(busy, overlay);
	o_info.guibusy = true;
}

function removeBusy() {
	if (o_info.guibusy) {
		o_info.guibusy = false;
		// Removes the overlay div and the busy screen (untested)
		var root = document.getElementsByTagName("body")[0];
		root.removeChild($('o_busy'));
		root.removeChild($('o_overlay'));
	}
}

function showAjaxBusy() {
	if (o_info.busyon) {
		$("o_ajax_busy").className = "o_ajax_busy";
	}
	noResponseTimer = setTimeout("o_noResponseFromServer()",27000);
}

function removeAjaxBusy() {
	o_info.busyon = false;
	var el = $("o_ajax_busy");
	if (el) el.className = "";
	clearTimeout(noResponseTimer);
}

var noResponseTimer;
function o_noResponseFromServer() {
	if (o_info.busyon) {
		alert(o_info.serverNoResponse);
		//just rerender the screen without warning msg.
		var url = this.window.location+"?o_winrndo=1"
		this.window.location.replace(url);
	}
}

// moved to package js - delete here if enabeld: guido
function toggleCheck(field, doCheck) {
	for (i = 0; i < field.length; i++) {
		field[i].checked = doCheck;
	}
}

function checkDom() {
	return document.hasChildNodes();
}

var htmlEditorEnabled = (checkDom() && (Prototype.Browser.IE || Prototype.Browser.Gecko));
var scormPlayerEnabled = (checkDom() && (Prototype.Browser.IE || Prototype.Browser.Gecko || Prototype.Browser.WebKit));

function setFormDirty(formId) {
	// sets dirty form content flag to true and renders the submit button
	// of the form with given dom id as dirty.
	// (fg) 
	o2c=1;
	if (checkDom()) {
		// fetch the form and the forms submit button is identified via the olat 
		// form submit name
		var myForm = document.getElementById(formId);
		//TODO:gs:a why not directly accessing the submit button by an id. name="olat_fosm" send additional parameter which is unused. OLAT-1363
		var mySubmit = myForm.olat_fosm_0;
		if(mySubmit == null){
			mySubmit = myForm.olat_fosm;
		}
		// set dirty css class
		if(mySubmit) mySubmit.className ="o_form_button_changes";
	}
}

//
//
function o_ffRegisterSubmit(formId, submElmId){
	var myForm = document.getElementById(formId);
	myForm["FlexiSubmit"] = submElmId;
}

//
// param formId a String with flexi form id
function setFlexiFormDirtyByListener(e,target,options){
	setFlexiFormDirty(options.formId);
}
function setFlexiFormDirty(formId){
	//if old form on same page with flexi.form
	o2c=1;
	
	var isRegistered = o3c.indexOf(formId) > -1;
	if(!isRegistered){
		o3c.push(formId);
	}
	var myForm = document.getElementById(formId);
	var submitButton = document.getElementById(myForm["FlexiSubmit"]);
	if(submitButton != null){
		//not all forms must have a submit element! 
		submitButton.className ="o_form_button_changes";
	}
}

function moveMessagesToContent() {
	// Hack to move error messages from the o_main div to the 
	// o_content div. Works only with dom browsers
	// (fg)
	if (checkDom()) {
		var messages = document.getElementById("o_messages");
		var content = document.getElementById("o_content");
		var modalc = document.getElementById("o_modalcontent");
		if (modalc != null) content = modalc;
		if (content != null) {
		//alert(messages.innerHTML);
			if(content.firstChild.id == "o_messages") {
				Element.remove(content.firstChild);
			}
			content.insertBefore(messages, content.firstChild);
		}	
	}
}

// functions for tooltip layer
var _ie=(document.all)?1:0,_nn=(document.layers)?2:0,_w3=(document.getElementById)?3:0;

function showtip(e,n) { var x,y,ex,ey,dw,lw,z; 
if(_nn){
	z=document.layers[n];
	ex=e.pageX;
	ey=e.pageY;
if(document.width){
	dw=document.width;
}else if(window.innerWidth){
	dw=window.innerWidth;
}
else {
	dw=800;
}
if(z.clip.width) {
	lw=z.clip.width;
}else{
	lw=400;
} 
if(ex+lw>dw){
	x=ex-lw-12;if(x<0){x=0;}
}
else {
	x=ex+8;
} 
y=ey+12;

z.clip.width=lw;

z.left=parseInt(x);
z.top=parseInt(y);
z.visibility="show";
}
else if(_w3) {z=$(n);if(e.pageX){ex=e.pageX;ey=e.pageY;} else {ex=e.clientX;ey=e.clientY;}

if(document.width){dw=document.width;}
else if(document.body.offsetWidth){dw=document.body.offsetWidth;}
else if(window.innerWidth){dw=window.innerWidth;}else {dw=800;}
if(z.style.width){lw=z.style.width;}else if(document.all){var _w=document.all[n];lw=_w.offsetWidth;}
if(!lw){lw=100;}if(ex+lw>dw){x=ex-lw-12;if(x<0){x=0;}} else {x=ex+8;}y=ey+12;
if(document.body.scrollTop){y+=document.body.scrollTop;}

//z.getAttributeNode("style").setAttribute("left", parseInt(x));

z.style.left=parseInt(x);
z.style.top=parseInt(y);
z.style.visibility="visible";
//alert("x"+x+","+z.style.left);
}

else if(_ie){z=document.all[n]; ex=e.clientX;ey=e.clientY;dw=document.body.offsetWidth;
lw=z.offsetWidth; if(!lw) {lw=100;}if(ex+lw>dw){x=ex-lw-12;if(x<0){x=0;}} else {x=ex+8;}
y=ey+12; if(document.body.scrollTop){y+=document.body.scrollTop;}

z.style.pixelLeft=parseInt(x);
z.style.pixelTop=parseInt(y);
z.style.visibility="visible";}}

function hidetip(n){if(_nn){document.layers[n].visibility="hide";}
else if(_w3){$(n).style.visibility="hidden";}
else if(_ie){document.all[n].style.visibility="hidden";}
}


//Pop-up window for context-sensitive help
function contextHelpWindow(URI) {
helpWindow = window.open(URI, "HelpWindow", "height=400, width=600, left=0, top=0, location=no, menubar=no, resizable=yes, scrollbars=yes, toolbar=no");
helpWindow.focus();
}

var activeNode;
function o_debugHighlight(enabled, currentNode) {
	// highlight div in debuging mode
	// enabled: true: do highlight: false: do not
	// currentNode: the node to be highlighted
	// (fg)
	if (currentNode != activeNode) {
		o_debugHighlight(false, activeNode);
		activeNode = currentNode;
	}
	if (currentNode == null) return;
	if (currentNode.style == null) return;
	if (enabled) {
		currentNode.style.border='1px solid gold';
		currentNode.style.background='#FCFCB8';
	} else {
		currentNode.style.border='1px dotted black';
		currentNode.style.background='';
	}
}

function openMovieViewer(vieweraddress, maddress, mname, displayname, displayduration, width, height) {
	// function to start movie viewer (see radeox macro s)
	// (fg)
	// height+60 (some browsers need this space) + 20 (to show playButton tag)
	// width+40 (some browsers need this space)
	var args = 'width=' + (parseInt(width)+40) + ',height=' + (parseInt(height)+80) + ',resizable=yes,scrollbars=yes';
	//IE does not like (crashed) writing out header data with javascript loaded again, so wo load a static file, pass the vars and write out the code there
	var viewer =  window.open("../../raw/movie/popup.html?vieweraddress="+encodeURIComponent(vieweraddress)+"&maddress="+encodeURIComponent(maddress)+"&mname="+encodeURIComponent(mname)+"&displayname="+encodeURIComponent(displayname)+"&displayduration="+encodeURIComponent(displayduration)+"&width="+width+"&height="+height+"", mname, args);
}

function o_playButtonTag(name, start, end, displayname, displayduration) {
	// function called by timemarker quicktime movie to create a forum
	// movie play button
	// (fg) 

 	var buttonElement = $("o_movieButtonTag");
	if (buttonElement != null) {
		var tag = "{movieButton:name=" + name + "|start=" + start + "|end=" + end + "|displayduration=" + displayduration + "}" + displayname + "{movieButton}";
		buttonElement.value = tag;
	}
}


function writeMovieViewerCode(doc, vieweraddress, maddress, mname, displayname, displayduration, width, height) {
	// function to write movie viewer to given html document. 
	// Used by radeox macro and openMovieViewer function
	// (fg)

	// title
	if(displayname == "null" || displayname == null) displayname = "";
	if(displayduration == "null" || displayduration == null) displayduration = "";
	if (displayname != "" || displayduration != "") {
		doc.write("<span class='o_movietitle'>");
		if (displayname != "") {
			doc.write(displayname);
			if (displayduration != "") {
				doc.write(": ");
			}
		}
		if (displayduration != "") {
			doc.write(displayduration);
		}
		doc.write("</span><br><br>");
	}
	// movie object
	doc.write("<object classid=\"clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B\"  width=\"" + width + "\" height=\"" + height + "\" codebase=\"http://www.apple.com/qtactivex/qtplugin.cab\">");
	doc.write("<param name=\"SRC\" value=\"" + vieweraddress + "\">");
	doc.write("<param name=\"CONTROLLER\" value=\"TRUE\">");
	doc.write("<param name=\"AUTOPLAY\" value=\"FALSE\">");
	doc.write("<param name=\"MOVIENAME\" value=\"" + mname + "\">");
	doc.write("<param name=\"CACHE\" value=\"FALSE\">");
	doc.write("<param name=\"MovieQTList\" value=\"<movieinfo><address>" + maddress + "</address><displayname>" + displayname + "</displayname></movieinfo>\">");
	doc.write("<embed");
	doc.write(" src=\"" + vieweraddress + "\"");
	doc.write(" width=\"" + width + "\" height=\"" + height + "\"");
	doc.write(" controller=\"TRUE\"");
	doc.write(" autoplay=\"FALSE\"");
	doc.write(" moviename=\"" + mname + "\"");
	doc.write(" cache=\"FALSE\"");
	doc.write(" MovieQTList=\"<movieinfo><address>" + maddress + "</address><displayname>" + displayname + "</displayname></movieinfo>\"");
	doc.write(" type=\"video/quicktime\"");
	doc.write(" pluginspage=\"http://www.apple.com/quicktime/download/\">");
	doc.write("</embed>");
	doc.write("</object>");
	doc.write("<br><input type=\"text\" size=\"40\" id=\"o_movieButtonTag\" style=\"font: x-small sans-serif; padding-top: 5px; width: " + width + "px;\">");
}


function o_hideDiv(divId) {
	// helper function: remove element from screen using css
	// (fg)
	var divElem = $(divId);
	if (divElem != null) {
		divElem.style.display = "none";
	}
}

function o_showDiv(divId) {
	// helper function: show element on screen using css
	// (fg)
	var divElem = $(divId);
	if (divElem != null) {
		divElem.style.display = "block";
	}
}
xMenuEnabled = false;
function o_xMenu(showMenu){
	// showMenu: true: show the menu layer
	//           false: hide the menu layer and show the opener instead
	// (fg)
	if (!xMenuEnabled && showMenu) {
		o_hideDiv("o_xmenuopener");
		o_showDiv("o_xmenucontent");
		xMenuEnabled = true;
	} else if (xMenuEnabled && !showMenu) {
		o_hideDiv("o_xmenucontent");
		o_showDiv("o_xmenuopener");
		xMenuEnabled = false;
	}
}

xToolsEnabled = false;
function o_xTools(showTools){
	// showTools: true: show the tools layer
	//           false: hide the tools layer and show the opener instead
	// (fg)
	if (!xToolsEnabled && showTools) {
		o_hideDiv("o_xtoolsopener");
		o_showDiv("o_xtoolscontent");
		xToolsEnabled = true;
	} else if (xToolsEnabled && !showTools) {
		o_hideDiv("o_xtoolscontent");
		o_showDiv("o_xtoolsopener");
		xToolsEnabled = false;
	}
}

function o_openPopUp(url, windowname, width, height, menubar) {
	// generic window popup function
	attributes = "height=" + height + ", width=" + width + ", resizable=yes, scrollbars=yes, left=100, top=100, ";
	if (menubar) {
		attributes += "location=yes, menubar=yes, status=yes, toolbar=yes";
	} else {
		attributes += "location=no, menubar=no, status=no, toolbar=no";
	}
	var win = window.open(url, windowname, attributes);
	win.focus();
}

function o_openClose(iconId, divId, openCss, closeCss) {
	var div = $(divId);
	if (div != null) {
		if (div.style != null && div.style.display == "none") {
			var icon = $(iconId);
			if (icon != null) {
				icon.className = openCss;
				// make div visible
				o_showDiv(divId);
			}
		} else {
			// change opener icon
			var icon = $(iconId);
			if (icon != null) {
				icon.className = closeCss;
				// make div invisible
				o_hideDiv(divId);
			}
		}
	
	}
}

o_addEventListener = function (obj, name, handler) {
	// Generic add event listener method that works both
	// with IE and other browsers. Make sure you remove
	// listeners that you add, latest when unloading a page!
	// (IE has memory leaks, added events are not removed 
	// just by the fact that you load another page!)
	// (fg)
	if (obj.addEventListener)
		obj.addEventListener(name, handler, false);
	else
		obj.attachEvent("on" + name, handler);
}
o_removeEventListener = function (obj, name, handler) {
	// Generic remove event listener method that works both
	// with IE and other browsers.
	// (fg)
	if (obj.removeEventListener)
		obj.removeEventListener(name, handler, false);
	else
		obj.detachEvent("on" + name, handler);
}


function O_DynObject (wrapperId, dynamicId) {
	// Object for showing a dynamic child element contained in a wrapper
	// element using a rollover effect. As soon as you leave the rollover 
	// area, the element will be removed from the visible screen.
	// IN: wrapperID: DOM tree ID of the wrapper element
	// IN: dynamicID: DOM tree ID of the dynamic child element.
	// (fg)
	this.wrapperId = wrapperId;
	this.dynamicId = dynamicId;
	this.isVisible = false; // current state is "not visible"
}
O_DynObject.prototype.o_isInWrapper = function(node) {
	// Internal helper method: recursive check if given node
	// is a child of the wrapper element
	// IN: node: the node that should be testd
	// OUT: true: node is a child; false: node is not a child
	// (fg)
	if (node == null || node.id == null)
		return false;
	if (node.id == this.wrapperId) 
		return true;
	else {
		if (node.parentNode != null) 
			return this.o_isInWrapper(node.parentNode);
		else 
			return false;
	}
}
O_DynObject.prototype.o_showDynObject = function () {
	// Makes the dynamic object visible and starts event capturing.
	// Will remove event capturing when leaving the dynamic object
	// and hide it from the visible screen.
	// (fg)
	if (this.isVisible) return; // do not attach listener twice
	// mark object as visible so listener gets attached ony once
	this.isVisible = true; 
	$(this.dynamicId).style.display = "block";		
	// dynamic callback method as anonymous function, refering 
	// to itself for the remove listener code.
	var my = this;
	var listener = function(e) {
		// get node which fired event
		var target = e["target"];
		// fix IE event handling
		if (target == null) target = e["srcElement"];
		var isInWrapper = my.o_isInWrapper(target);	
		if (!isInWrapper) {
			o_removeEventListener(document, 'mousemove',listener);
			$(my.dynamicId).style.display = "none";	
			my.isVisible = false; // mark as not visible	
		}
	};
	o_addEventListener(document, 'mousemove', listener);
}


function gotonode(nodeid) {
	// get the "olatmain" window
	var w = top;
	try {
		if (w.opener && w.opener.o_info) {
		  w = w.opener;
		}
	} catch (e) {}
	
	w.focus();
	var str = w.location.href;
	var pos = str.search(/\/auth\//);
	var strnew = str.substring(0, pos+6);
	if (w.o_info && w.o_info.course_id) {
		var alu = strnew + "repo/go?rid="+w.o_info.course_id+"&par="+nodeid;
		w.location.replace(alu);
	}
}

function o_openUriInMainWindow(uri) {
	// get the "olatmain" window
	var w = top;
	try {
		if (w.opener && w.opener.o_info) {
		  w = w.opener;
		}
	} catch (e) {}
	
	w.focus();
	w.location.replace(uri);
}

o_getDisplayableInnerContentHeight = function () {
	// calculate the height of the inner content area that can be used for 
	// displaying content without using scrollbars. Uses the o_info.o_topBottomLayoutWaste
	// variable set in the main layout to know how much space is used by header and footer.
	// Depends on prototype library!
	// (fg)
	
	if (!checkDom()) return 0;
	// rule is: window height - o_topBottomLayoutWaster
	var windowHeight = 0;
	if (window.innerHeight) 
		windowHeight = window.innerHeight - 18;
   	else if (document.documentElement && document.documentElement.clientHeight) 
    		windowHeight = document.documentElement.clientHeight;
   	else if (document.body && document.body.clientHeight) 
    		windowHeight = document.body.clientHeight;
    if ($("o_messages")) var messagesHeight = Element.getHeight("o_messages"); // using prototype
    return (windowHeight - o_info.o_topBottomLayoutWaste - messagesHeight);
}
  
  
function o_adjustIframeHeight(iframeId) {

	// adjust the given iframe to use as much height as possible
	// (fg)
	if (!checkDom()) return;
	var theIframe = $(iframeId);
	if (theIframe) {
		var contentHeight = o_getDisplayableInnerContentHeight();
		if (contentHeight > 0) 
			theIframe.style.height = contentHeight + "px";
		else 
			// could not calculate content height, use fallback
			theIframe.style.height = "600px";
	}
}

function o_addShadow(shadowWrapperDiv) { 
	// Add a shadow effect to an element that is wrapped with a 
	// shadow wrapper div. The shadow wrapper must have with and height set
	// to auto and be positioned. 
	// <div style="width: auto; height: auto; position: relative;" id="shadowWrapper">
	// <div> mystuff comes here </div>
	// </div>
	// <a href="#shadow" onclick="o_addShadow('shadowWrapper')">add shadow</a>
	//
	
	// Add a shaddow effect to a containerpositioned div that is within a 
	// positioned container. The content div must be the first child
	// of the container div to work properly. 
	// The shadow effect is done by adding transparent div underneth
	// the content div. The number of div equals the number of iterations.
	// In each iteration the div is placed using the xFactor and yFactor
	// to calculate an offset.
	// 
	// container: id of the container div
	// iterations (optional): number of shadow iterations, default is 7
	// xFactor (optional): shadow position factor in x dimension, default is 1
	// yFactor (optional): shadow position factor in y dimension, default is 1.1
	// css (optional): css class used to style the shadow, default is o_shadow
	//
	// Florian Gnaegi, frentix GmbH, http://www.frentix.com
	if (!checkDom()) return;
	var containerElem = $(shadowWrapperDiv);
	var iterations =  (arguments.length > 1 ? arguments[1] : 7);
	var xFactor = (arguments.length > 2 ? arguments[2] : 1);
	var yFactor = (arguments.length > 3 ? arguments[3] : 1.1);
	var css = (arguments.length > 4 ? arguments[4] : "o_shadow");
	
	var dimensions = Element.getDimensions(containerElem);
	for (var i = 0; i < iterations; i++) {
		var shadow = "<div class='" + css + "' style='top: " + (i*yFactor) + "px; left: " + (i*xFactor) + "px;";
		if (Prototype.Browser.IE) {
			// Fix for IE: does not understand the with / height 100% css settings
			shadow += "width: " + dimensions.width + "; height: " + dimensions.height;
		}
		shadow += "'></div>";
		
		var shadowElem = new Insertion.Top(containerElem, shadow);
	}
}

function o_moveModalDialogToCenter() {
	// Move the modal dialog div to center of the screen. This depends on the modal
	// contents widh and height and will move the modal content wrapper. It's a bit 
	// complicated to make it generic thus a specialized version that is only usable
	// in the modal dialog case. 
	//
	// Florian Gnaegi, frentix GmbH, http://www.frentix.com
	if (!checkDom()) return;
	var dimensions = Element.getDimensions($("o_modalcontent"));
	var viewportSize = Element.getDimensions(document.getElementsByTagName('html')[0]);
	var top = $("o_top");
	var topNav = $("o_tn");
	var topHeight = 0;
	if (topNav != 'unknown' && top != 'unknown') {
		topHeight = top.getHeight();
		if (topNav.getHeight() > topHeight) {
			// IE doesn't get it right! add height of wrapper and 
			// top nav table to get the right height of the top navigation
			topHeight = topHeight + topNav.getHeight();
		}
	}
	// to make it look nice add 10 pixels
	topHeight = topHeight + 10;
	
	// default values
	var topVal = topHeight + "px";
	var leftVal = "0px";
	
	// Check if browser window is large enough for centering, else use the 
	// default values
	// Subtract the modalDialog shadow (7px)
	// Position modal dialog below top navigation since this is not part of the overlay!
	if (viewportSize.height > dimensions.height) {
		topVal = (((viewportSize.height - topHeight - dimensions.height - 7 ) / 3) + topHeight) + "px";
	}
	if (viewportSize.width > dimensions.width) {
		leftVal = ((viewportSize.width - dimensions.width - 7 ) / 2) + "px";
	} 
	// assign new top and left values
	Element.setStyle("o_modalshadowwrapper", {top: topVal, left: leftVal});
}
