var bbLockRegistry = new Array ();
var bbPageSize = 20;
var bbMenuID = -1;
var bbOnLoadRegistry;
var bbOnSubmitRegistry;
var bbErrorFieldNames = new Array ();

// submits the form, adding the nosave parameter if it is set to true
// component: can be the form itself, or any object within a form
function submitForm (component, noSave) {
	// if component is a form, just submit it
	if (component && component.nodeName.toLowerCase () == 'form') {
		if (noSave) {
			var hidden = AJS.INPUT ({ type: 'hidden', value: 'nosave', name: 'form_nosave' });
			component.appendChild (hidden);
		}
		component.submit ();
	}
	// if component is not a form, find its surrounding form tag and submit that
	else {
		component = AJS.getParentBytc (component, 'form', null);
		submitForm (component, noSave);
	}
}


function reloadByGet(){
  var url = location.href;
  url += url.indexOf('?')!=-1?'&':'?';
  url += "mn="+new Date().getTime();
  var obj = findObject('form_id');
  if(obj!=null){
    url += '&id='+obj.value;
  }
  location.href = url;
}

// Focuses the first visible textfield
function setFocus (form) {
	if (!document.documentclicked) {
		var f = document.forms[form];
		if (f != null) {
			// do we have errors? focus first erroneus field
			if (bbErrorFieldNames && bbErrorFieldNames.length > 0) {
				var errorElements = new Array ();
				for (ii = 0; ii < bbErrorFieldNames.length; ii++) {
					var element = null;
					element = AJS.getElement ('form_' + bbErrorFieldNames[ii]);
					if (element && isFocusable (element)) {
						errorElements[errorElements.length] = element;
					}
					else if (element) {
						// the element exists but it's not focusable
						// try to find next focusable field in same tr.inputerror
						var tr = AJS.getParentBytc (element, 'tr', 'inputerror');
						if (tr) {
							// we have the surrounding tr, get all inputs
							var innerElements = AJS.getElementsByTagAndClassName ('input', null, tr);
							for (var jj = 0; jj < innerElements.length; jj++) {
								if (isFocusable (innerElements[jj])) {
									errorElements[errorElements.length] = innerElements[jj];
								}
							}
						}
					}
					else {
						element = AJS.getElement (bbErrorFieldNames[ii]);
						if (element && isFocusable (element)) {
							errorElements[errorElements.length] = element;
						}
					}
				}
				setFocusOnFirstElement (errorElements, null, true);
			}
			else {
				setFocusOnFirstElement (f.elements);
			}
		}
		// set focus to first available form if one
		else {
			var pos = 0;
			// don't focus search form and searchsave/constraintsave
			while (document.forms[pos].id.substr (0, 6) == 'search' && pos < document.forms.length) {
				pos++;
			}
			if (pos < document.forms.length && document.forms[pos] != null) {
				setFocusOnFirstElement (document.forms[pos].elements);
			}
		}
	}
	//Init show error
	if (window.bbShowRelationsDBRecordName != null) {
		var f = document.forms[form];
		if (f != null) {
			var id = findObject ('form_id', f);
			if (id != null && id.value != null && id.value.trim ().length > 0) {
				var td = AJS.getElementsByTagAndClassName ('td', 'showrelations', f, true);
				if (td != null) {
					var a = AJS.getElementsByTagAndClassName ('a', null, td, true);
					if (a != null) {
						a.href = 'javascript:openPopup(\'' + createURL ('administration/maintenance', 'showrelations', bbMenuID, 'id=' + id.value + '&dbrecordname='+window.bbShowRelationsDBRecordName) + '\', 700, 600)';
						a.style.display = 'block';
					}
				}
			}
		}
	}
}

// elements can be an array of inputs or any container (div, etc.) inside the form
// optional: container is the container surrounding the inputs
// optional: showParents if this is true the first element will be focused and all it's parents will be made visible (tabs for example)
function setFocusOnFirstElement (elements, container, showParents) {
	if (elements != null) {
		// it's an array
		if (isArray (elements)) {
			for (var i = 0; i < elements.length; i++) {
				var input = elements[i];
				// if there's no container just take the first visible input
				// if container is specified, check whether the input is within this container
				if (!container || (container && input && AJS.hasParent (input, container, 30)))  {
					if (isFocusable (input)) {
						if (isInputVisible (input)) {
							try {
								if (input.fckEditorObject) {
									input.fckEditorObject.Focus ();
								}
								else {
									input.focus ();
									if (input.select != null) {
										input.select ();
									}
								}
							} catch (ex) { }
							break;
						}
						else if (showParents) {
							var parent = elements[i];
							// get any parent which is a tab and display='none'
							while (parent = parent.parentNode) {
								if (parent.style && parent.className == 'tabwrapper') {
									if (parent.style.display == 'none') {
										activateTab (parent.id.replace ('bbtabcontent_', ''));
										break;
									}
								}
							}
							try {
								if (input.fckEditorObject) {
									input.fckEditorObject.Focus ();
								}
								else {
									input.focus ();
									if (input.select != null) {
										input.select ();
									}
								}
							} catch (ex) { }
							break;
						}
					}
				}
			}
		}
		// we received a container (i.e. a tab) on which we will focus the first input
		else {
			// get the surrounding form
			var container = elements;
			elements = new Array ();
			try {
				var f = AJS.getParentBytc (container, 'form');
				if (f && f.elements) {
					setFocusOnFirstElement (f.elements, container);
				}
			} catch (ex) {}
		}
	}
}

function isFocusable (element) {
	if (element != null) {
		// don't focus the buttons in the formhead (div id="formhead")
		if (!isInFormHead (element) && element.nodeName) {
			var nodeName = element.nodeName.toLowerCase ();
			var type = (element.type != null) ? element.type.toLowerCase () : '';
			var isReadOnly = (element.readOnly != null) ? element.readOnly : false;
			var isVisible = (element.style != null && element.style.visibility != null && element.style.visibility.toLowerCase () == 'hidden') ? false : true;
			var isDisplaied = (element.style != null && element.style.display != null && element.style.display.toLowerCase () == 'none') ? false : true;
			var types = 'text,password,button,submit';
//			alert (element.name + ':' + type + ':' + (readOnly == true ? 'true' : 'false') + ':' + (visible == true ? 'true' : 'false') + ':' + (display == true ? 'true' : 'false'));
			if (!isReadOnly && isVisible && isDisplaied && ((',' + types + ',').indexOf (',' + type + ',') != -1 || nodeName == 'textarea' || nodeName == 'select')) {
				return true;
			}
			else if (element.nodeName.toLowerCase () == 'textarea' && element.id) {
				// maybe we have an fck editor here?
				try {
					var editor = FCKeditorAPI.GetInstance (element.id);
					if (editor != null) {
						// alert ('we have an editor here: ' + element.id + ': ' + editor);
						var iFrame = AJS.getElement (element.id + '___Frame');
						// check if the editor's iframe is focusable
						isReadOnly = (iFrame.readOnly != null) ? iFrame.readOnly : false;
						isVisible = (iFrame.style != null && iFrame.style.visibility != null && iFrame.style.visibility.toLowerCase () == 'hidden') ? false : true;
						isDisplaied = (iFrame.style != null && iFrame.style.display != null && iFrame.style.display.toLowerCase () == 'none') ? false : true;
						if (!isReadOnly && isVisible && isDisplaied) {
							// store the editor on the textarea
							element.fckEditorObject = editor;
							return true;
						}
					}
				} catch (ex) { /* if fckeditor is not even defined, there can't be one :) */ }
			}
		}
	}
	return false;
}

function isInputVisible (input) {
	if (input) {
		// if there are tabs get the selected one and find out if the input type is on it
		return !hasInvisibleParents (input);
	}
	// default
	return false;
}

function isInFormHead (element) {
	while (element.parentNode) {
		if (element.tagName == 'DIV' && element.id == 'formhead') {
			return true;
		}
		element = element.parentNode;
	}
	return false;
}

function hasInvisibleParents (element) {
	var p = element.parentNode;
	while (p) {
		if (p.style) {
			if (p.style.display && p.style.display == 'none') {
				return true;
			}
		}
		p = p.parentNode;
	}
	return false;
}

/**
 * function to be called by each form before submission
 */
function bbOnSubmit (form) {
	if (form) {
		// check if locks are lost
		if (document.bbLocksLost) {
			//Try to get the getLowerOwner function from registry
			var fgetLockOwner;
			if (bbOnLoadRegistry != null) {
				for (var i in bbOnLoadRegistry) {
					if (bbOnLoadRegistry[i].toLowerCase ().trim ().indexOf ('getlockowner') == 0) {
						fgetLockOwner = bbOnLoadRegistry[i];
						break;
					}
				}
			}
			if (fgetLockOwner != null) {
				var elm = AJS.getElement ('lockindicator0');
				if (elm != null) {
					var els = elm.parentNode.getElementsByTagName ('div');
					if (els.length > 0){
						els[0].style.display = 'block';
						var f = new Function ('a ', ' ' + fgetLockOwner + ' ');
						f ();
					}
				}
			}
			return false;
		}
		// check if this form has a pwd field
		var fields = AJS.getElementsByTagAndClassName ('input', null, form);
		for (i = 0; i < fields.length; i++) {
			if (fields[i].getAttribute ('type') && fields[i].getAttribute ('type').toLowerCase () == 'password') {
				// if there is a hidden field next to the password field, copy md5 value and empty password field
				if (fields[i].value) {
					var next = fields[i].nextSibling;
					if (next != null && next.tagName.toLowerCase () == 'input' && next.getAttribute ('type') && next.getAttribute ('type').toLowerCase () == 'hidden') {
						//Default pwd set, do nothing
						if (fields[i].value != '*****') {
              if(window.hex_md5==null){
                alert('function hex_md5 not found');
                return false;
              }
              next.value = hex_md5 (fields[i].value);
							var next = next.nextSibling;
							if (next != null && next.tagName.toLowerCase () == 'input' && next.getAttribute ('type') && next.getAttribute ('type').toLowerCase () == 'hidden') {
								next.value = fields[i].value.length;
							}
							fields[i].value = '*****';
						}
					}
				}
			}
		}
	}
	// execute the functions in bbOnSubmitRegistry
	if (bbOnSubmitRegistry != null) {
		var returnValue = true;
		for (var i in bbOnSubmitRegistry) {
			returnValue = (returnValue && eval (bbOnSubmitRegistry[i]));
		}
		return returnValue;
	}
	return true;
}

/**
 * Goes to a given url (if url contains 'javascript:', then it will be evaluated)
 */
function goToURL (url) {
	if (url.toLowerCase ().indexOf ('javascript:') != -1) {
		eval (url);
	}
	else {
		location.href = url;
	}
}

/**
 * takes the event, the inputfield where enter was pressed, and the position in the list view
 * checks whether the entered number is valid for the given record
 */
function executeAction (evt, input, name, position) {
	if (isEnterKey (evt)) {
		if (input.value) {
			try {
				// record id
				var id = AJS.getElement ('record_' + name + '_' + position + '_id').value;
				// record actions
				var accessKeys = AJS.getElement ('record_' + name + '_' + position + '_accesskeys').value;
				// check if input value is in accessKeys
				if (accessKeys.indexOf (';' + input.value + ';') >= 0) {
					ActionMenu.execute (name, position, input.value);
				}
				else {
				    ajaxCall (createURL ('administration/resource', 'alertResource', 0, 'resourcekey=action_unavailable'));
				}
			} catch (ex) {
				alert (ex);
			}
		}
		input.value = '';
	}
}

var bbOpenActionMenu = null;
var ActionMenu = {
	///<description>creates and opens the action menu in a list view</description>
	open: function (evt, name, position) {
		// get info about this position
		try {
			closeMenus ();
			stopEventPropagation (evt);
			// record id
			var id = AJS.getElement ('record_' + name + '_' + position + '_id').value;
			// record actions
			var accessKeys = AJS.getElement ('record_' + name + '_' + position + '_accesskeys').value;
			// the actionmenu div
			var am = AJS.getElement ('record_' + name + '_' + position + '_actionmenu');
			am.style.zIndex = 2;
			var keys = accessKeys.split (';');
			var tbl = '<table cellpadding="0" cellspacing="0" border="0" onclick="stopEventPropagation">';
			for (var i = 0; i < keys.length; i++) {
				if (keys[i]) {
					tbl += '<tr><td onclick="ActionMenu.execute(\'' + name + '\', ' + position + ', ' + keys[i] + ')">' + bbActionNames[name][keys[i]] + '</td><td onclick="ActionMenu.execute(\'' + name + '\', ' + position + ', ' + keys[i] + ')">' + keys[i] + '</td></tr>';
				}
			}
			am.innerHTML = tbl + '</table>';
			// the actionmenu opener
			var button = AJS.getElement ('record_' + name + '_' + position + '_button');
			if (button.src.indexOf ('_open') < 0) {
				button.src = button.src.replace ('actionmenu', 'actionmenu_open');
			}
			button.onclickbackup = button.onclick;
			button.onclick = function () { ActionMenu.close (); };
			// show selected
			fadeIn (am.firstChild, 'table');
			bbOpenActionMenu = am;
		} catch (ex) {
			alert (ex);
		}
	},

	///<description>Closese the actionmenu stored in bbOpenActionMenu.</description>
	close: function () {
		if (bbOpenActionMenu) {
			bbOpenActionMenu.style.zIndex = 0;
			fadeOut (bbOpenActionMenu.firstChild);
			var button = AJS.getElement (bbOpenActionMenu.id.replace ('_actionmenu', '') + '_button');
			if (button.src.indexOf ('_open') > 0) {
				button.src = button.src.replace ('_open', '');
				button.onclick = button.onclickbackup;
			}
			bbOpenActionMenu = null;
		}
	},

	///<description>Executes the action identified by accessKey on the record of the given position</description>
	execute: function (name, position, accessKey) {
		// get the url
		var url = AJS.getElement ('record_' + name + '_' + position + '_' + accessKey + '_url').value;
		goToURL (url);
		ActionMenu.close ();
	}
}

/// <description>Hides an element on mouseout.</description>
/// <param name="comp">May be a single component or an array of components.</param>
/// <param name="graceTime">Delay in milliseconds between mouseout and hiding (optional).</param>
/// <param name="hideAll">If comp is an array and hideAll=true all components will be hidden.
/// If hideAll=false only the first component in the array will be hidden (optional).</param>
function hideOnMouseOut (comp, graceTime, hideAll, callBack) {
	if (!graceTime) {
		graceTime = 750;
	}
	///<todo>components loose onmouseout and onmouseover, add</todo>
	if (isArray (comp)) {
		for (var i = 0; i < comp.length; i++) {
			if (i == 0) {
				comp[0].onmouseout = function () { this.hideOnMouseOutTimeout = window.setTimeout (function () { fadeOut (comp[0], callBack); }, graceTime); }
				comp[0].onmouseover = function () { window.clearTimeout (comp[0].hideOnMouseOutTimeout); }
			}
			else {
				if (hideAll) {
					comp[i].onmouseout = function () { comp[0].hideOnMouseOutTimeout = window.setTimeout (function () { for (var j = 0; j < comp.length; j++) { fadeOut (comp[j], callBack); } }, graceTime); }
				}
				else {
					comp[i].onmouseout = function () { comp[0].hideOnMouseOutTimeout = window.setTimeout (function () { fadeOut (comp[0], callBack); }, graceTime); }
				}
				comp[i].onmouseover = function () { window.clearTimeout (comp[0].hideOnMouseOutTimeout); }
			}
		}
	}
	else {
		comp.onmouseout = function () { this.hideOnMouseOutTimeout = window.setTimeout (function () { fadeOut (comp, callBack); }, graceTime); }
		comp.onmouseover = function () { window.clearTimeout (comp.hideOnMouseOutTimeout); }
	}
}

/**
 * display: what display attribute to set (ie. block (default), table, inline, ....)
 * for ie: anything else than 'block' always falls back to block in case of an exception
 */
function fadeIn (comp, display) {
	if (comp.style.opacity == '' || isNaN (comp.style.opacity) || (comp.style.opacity * 1) == 1 || (comp.style.opacity * 1) == 0) {
		// init
		if (comp.fadeOutTimeout) window.clearTimeout (comp.fadeOutTimeout);
		comp.style.opacity = 0.1;
		comp.style.filter = 'alpha(opacity=' + (comp.style.opacity * 100) +')';
		if (display) {
			try {
				comp.style.display = display;
			} catch (ex) {
				comp.style.display = 'block';
			}
		}
		else {
			comp.style.display = 'block';
		}
		comp.fadeInTimeout = window.setTimeout (function () { fadeIn (comp); }, 15);
	}
	else {
		comp.style.opacity = (comp.style.opacity * 1) + 0.1;
		comp.style.filter = 'alpha(opacity=' + (comp.style.opacity * 100) +')';
		if (comp.style.opacity * 1 < 1) {
			comp.fadeInTimeout = window.setTimeout (function () { fadeIn (comp); }, 15);
		}
		else {
			comp.style.opacity = 1;
			comp.style.filter = 'alpha(opacity=100)';
		}
	}
}

function fadeOut (comp, callBack) {
	if (comp.fadeInTimeout) {
		window.clearTimeout (comp.fadeInTimeout);
	}
	comp.style.opacity = (comp.style.opacity * 1) - 0.15;
	comp.style.filter = 'alpha(opacity=' + (comp.style.opacity * 100) +')';
	if (comp.style.opacity * 1 > 0) {
		comp.fadeOutTimeout = window.setTimeout (function () { fadeOut (comp, callBack); }, 15);
	}
	else {
		comp.style.opacity = 0;
		comp.style.filter = 'alpha(opacity=0)';
		comp.style.display = 'none';
		if (callBack) {
			callBack ();
		}
	}
}

function delayFadeOut (id, delay) {
	if (!delay) {
		var comp = AJS.getElement (id);
		if (comp) {
			comp.style.opacity
			fadeOut (comp);
		}
	}
	else {
		window.setTimeout ('delayFadeOut(\'' + id + '\')', delay * 1000);
	}
}

function openPopup (url, width, height, returnWindow) {
	// position on the screen
	var left = (screen.width - width) / 2;
	var top = (screen.height - height) / 2.5;
	var win = window.open (url, '', 'width=' + width + ',height=' + height + ',left=' + left + ',top=' + top + ',location=0,status=1,menubar=0,resizable=1,toolbar=0,scrollbars=1');
	// popup-blocker ?
	if (!win) {
	    ajaxCall (createURL ('administration/resource', 'alertResource', 0, 'resourcekey=popup_blocked'));
	}
	// set opener
	else if (!win.opener) {
		win.opener = self;
	}
	if (returnWindow) {
		return win;
	}
}

/**
 *
 */
function markRecordDeleted (id) {
  var tr = getRecordTR (id);
  if (tr) {
		// cross it out
		tr.className = tr.className + ' deleted';
		// hide action menu
		if ((btn = AJS.getElement (tr.id + '_button'))) {
			btn.onclick = function () {};
		}
		// remove actions
		if ((acts = AJS.getElement (tr.id + '_accesskeys'))) {
			acts.value = '';
		}
	}
}
function markRecordModified (id) {
	var tr = getRecordTR (id);
	if (tr) {
		// change background color
		tr.className = tr.className + ' modified';
	}
}
function getRecordTR (id) {
  var trs = document.getElementsByTagName('tr');
  if(trs!=null){
    for (var i = 0; i <= trs.length; i++) {
      if(trs[i]!=null){
        var c = trs[i].className;
        if(c!=null && c.indexOf(' ID_'+id)!=-1){
          return trs[i]; 
        }
      }
    }
  }
	return null;
}

/**
 * everything about locks
 */
function updateLocks () {
	// create lock indicator icons
	try {
		if (!AJS.getElement ('lockindicator0')) {
			var wrap = AJS.getElement ('formhead').firstChild.firstChild.firstChild.firstChild;
			if (wrap) {
				var li = AJS.IMG ();
				li.src = bbURLPrefix + 'img/lock_ok.png';
				li.id = 'lockindicator0';
				wrap.appendChild (li);
			}
			wrap = AJS.getElement ('formfoot').firstChild.firstChild.firstChild.firstChild;
			if (wrap) {
				li = AJS.IMG ();
				li.src = bbURLPrefix + 'img/lock_ok.png';
				li.id = 'lockindicator1';
				wrap.appendChild (li);
			}
		}
		var lockIDs = '';
		for (var i = 0; i < bbLockRegistry.length; i++) {
			lockIDs += (lockIDs.length > 0 ? ';' : '') + bbLockRegistry[i];
		}
		ajaxCall (createURL ('administration/lock', 'update', bbMenuID, 'ids=' + lockIDs), null, locksLost);
	} catch (ex) {
		alert ('Error in updateLocks.' + ex);
	}
}
function locksUpdated () {
	window.setTimeout (updateLocks, bbLockObserverInterval * 1000);
}
function locksLost () {
	// are there already lock indicators?
	if (AJS.getElement ('lockindicator0')) {
		AJS.getElement ('lockindicator0').src = bbURLPrefix + 'img/lock_lost.png';
	}
	if (AJS.getElement ('lockindicator1')) {
		AJS.getElement ('lockindicator1').src = bbURLPrefix + 'img/lock_lost.png';
	}
	document.bbLocksLost = true;
	// disable the form
	for (var i = 0; i < document.forms.length; i++) {
		for (var j = 0; j < document.forms[i].elements.length; j++) {
			document.forms[i].elements[j].disabled = true;
      if(document.forms[i].elements[j].nodeName!=null && document.forms[i].elements[j].nodeName.toLowerCase()=='textarea' && document.forms[i].elements[j].id!=null && document.forms[i].elements[j].id.length>0){
        //Close FCKEditor
        closeFCKEditor(document.forms[i].elements[j].id,true);
      }
		}
	}
	disableOrderedTableRows ();
	//disable buttons
	var buttons = AJS.$bytc ('td', 'buttons');
	if (buttons != null){
		for (var i = 0; i < buttons.length; i++) {
			var anchors = buttons[i].getElementsByTagName ('a');
			if (anchors != null) {
				for (var j = 0; j < anchors.length; j++) {
					anchors[j].href = 'javascript:void(0)';
					var imgs = anchors[j].getElementsByTagName ('img');
					if (imgs != null) {
						for (var k = 0; k < imgs.length; k++) {
							imgs[k].onmouseover = function () {return void (0); };
							imgs[k].onmouseout = function () {return void (0); };
							imgs[k].style.opacity = 0.5;
							imgs[k].style.filter = 'alpha(opacity=50)';
						}
					}
				}
			}
		}
	}
}

function getLockOwner (itemId, tableName) {
	var elm = AJS.getElement ('lockindicator0');
	if (elm != null) {
		var els = elm.parentNode.getElementsByTagName ('div');
		var div = null;
		if (els.length == 0) {
			div = AJS.DIV ();
			div.style.zIndex = 10000;
			div.className = 'lockownerinfo';
			elm.parentNode.appendChild (div);
		}
		else {
			div = els[0];
		}
		if (div != null) {
			elm.style.cursor = 'pointer';
			AJS.addEventListener (elm, 'click', AJS.bind (
					function (event, div) {
						stopEventPropagation (event);
						if (div != null) {
							var open = false;
							if (div.innerHTML.trim ().length == 0) {
								open = false;
							}
							else if (div.style.display == null || div.style.display.length == 0 || div.style.display.toLowerCase () == 'none') {
								open = true;
							}
							if (open) {
								if (isIE6 ()) {
									hideSelects ();
								}
								div.style.display = 'block';
								document.bbLockOwnerInfo = div;
							}
							else {
								closeMenus ();
								if (isIE6 ()) {
									showSelects ();
								}
								div.style.display = 'none';
								document.bbLockOwnerInfo = null;
							}
						}
					}, window, div)
			);
		}
	}
	ajaxCall (createURL ('administration/lock', 'getowner', bbMenuID, 'itemid=' + itemId + '&tablename=' + tableName));
}

function updateLockOwnerInfo (data) {
	var elm = AJS.getElement ('lockindicator0');
	if(elm!=null){
		var els = elm.parentNode.getElementsByTagName('div');
		if(els.length>0){
			var div = els[0];
			if(data!=null && data.length>0){
				div.innerHTML = data;
			}
			else {
				div.style.display = 'none';
			}
		}
	}
}

// 
function createURL (contextName, actionName, menuID, params) {
	if (bbUseISAPI) {
		return createBBURL (bbURLPrefix, true, contextName, actionName, menuID, params);
	}
	else {
		var urlPrefix = bbURLPrefix;
		if (urlPrefix.indexOf ('.aspx') == -1) {
			urlPrefix += 'index.aspx';
		}
		return createBBURL (urlPrefix, false, contextName, actionName, menuID, params);
	}
}

function createBBURL (urlPrefix, useISAPI, contextName, actionName, menuID, params) {
	if (!contextName) {
		contextName = bbContextName;
	}
	if (!actionName) {
		actionName = bbActionName;
	}
	if (!menuID) {
		menuID = bbMenuID;
	}
	var url = '';
	if (useISAPI) {
		var language;
		if (window.bbAppLanguage == null) {
			if ((language = getLanguageByMetaTag()) == null) {
				language = 'de';
			}
		} else {
			language = bbAppLanguage;
		}
		url = urlPrefix + language + '/' + contextName + '/' + actionName + '/' + menuID + '/?'
	}
	else {
		url = urlPrefix + '?context=' + contextName + '&action=' + actionName + '&menuid=' + menuID + '&';
	}
	return url + (params ? params : '');
}

function extendURL (url, params) {
	if (params != null && params.length > 0) {
		if (params.indexOf ('&') == 0 || params.indexOf ('?') == 0) {
			params = params.substring (1, params.length);
		}
		url += (url.indexOf ('?') != -1 ? '&' : '?') + params;
	}
	return url;
}

// callback: to be executed for successful requests
// errorCallback: for errors
// data: json object for example
function ajaxCall (url, callback, errorCallback, data) {
	// add magicnumber for every browser
	url += (url.indexOf ('?') > 0 ? '&' : '?') + 'mn=' + new Date ().getTime ();
	//alert (url);
	var req = AJS.getRequest (url);
	if (callback) {
		req.addCallback (callback);
	}
	else {
		// default callback does javascript eval
		req.addCallback (function (data, req) { try { eval (data); } catch (ex) { (errorCallback ? eval (errorCallback) : alert (url + "\n\n" + ex)); }});
	}
	req.addErrback (function (data, req) { if (errorCallback) { eval (errorCallback) } else { try { eval (data); } catch (ex) { alert ('An error occured.'); } } });
	req.sendReq ();
	return req;
}

/**
 * search form functions
 */
var bbSearchSaveMenu = null;
var SearchForm = {
	addSearchRow: function (tr) {
		SearchForm.closeSaveMenu ();
		if (SearchForm.getRowCount (tr.parentNode) == 1) {
			// show remove button in first row
			for (var i = 0; i < AJS.getElement ('form_search_rowcount').value * 1; i++) {
				if (AJS.getElement ('search_removebutton_' + i)) {
					AJS.getElement ('search_removebutton_' + i).style.display = 'block';
				}
			}
			// move submit buttons if there are no constraints
			if (!bbSearchHasConstraints) {
				var trs = AJS.getElementsByTagAndClassName ('tr', 'bbsearchquery', tr.parentNode);
				if (trs && trs.length > 0) {
					AJS.getElement ('bbsearchcombination').lastChild.innerHTML = trs[0].lastChild.innerHTML;
					trs[0].lastChild.innerHTML = '';
				}
			}
		}
		try { AJS.getElement ('bbsearchcombination').style.display = 'table-row'; } catch (ex) { AJS.getElement ('bbsearchcombination').style.display = 'block'; }
		var tr2 = tr.cloneNode (true);
		// remove names and ids from tr2
		SearchForm.updateIDs (tr2, (AJS.getElement ('form_search_rowcount').value * 1));
		AJS.insertAfter (tr2, tr);
		// for ie and firefox set value of cloned pulldowns
		SearchForm.syncroniseSelectValues (tr.firstChild, tr2.firstChild);
		// hide searchlabel
		tr2.firstChild.innerHTML = '';
		AJS.getElement ('form_search_rowcount').value = (AJS.getElement ('form_search_rowcount').value * 1) + 1;
		// refresh the new row
		SearchForm.updateSearchRow (tr2);
	},

	getRowCount: function (tbody) {
		// count the search rows
		var rowCount = 0;
		for (var i = 0; i < tbody.childNodes.length; i++) {
			if (tbody.childNodes[i].className == 'bbsearchquery') {
				rowCount++;
			}
		}
		return rowCount;
	},

	removeSearchRow: function (tr) {
		SearchForm.closeSaveMenu ();
		var tbody = tr.parentNode;
		// move search label
		if (tr.firstChild.innerHTML) {
			tr.nextSibling.firstChild.innerHTML = tr.firstChild.innerHTML;
		}
		tbody.removeChild (tr);
		if (SearchForm.getRowCount (tbody) == 1) {
			// hide remove button
			for (var i = 0; i < AJS.getElement ('form_search_rowcount').value * 1; i++) {
				if (AJS.getElement ('search_removebutton_' + i)) {
					AJS.getElement ('search_removebutton_' + i).style.display = 'none';
				}
			}
			AJS.getElement ('bbsearchcombination').style.display = 'none';
			// move submit buttons from the last to the first row if there are no constraints
			if (!bbSearchHasConstraints) {
				var trs = AJS.getElementsByTagAndClassName ('tr', 'bbsearchquery', tbody);
				if (trs && trs.length > 0) {
					trs[0].lastChild.innerHTML = AJS.getElement ('bbsearchcombination').lastChild.innerHTML;
					AJS.getElement ('bbsearchcombination').lastChild.innerHTML = '';
				}
			}
		}
	},

	// syncronises the selects and clears textfields in the clone
	syncroniseSelectValues: function (orig, clone) {
		if (orig.tagName == 'SELECT' && clone.tagName == 'SELECT') {
			clone.value = orig.value;
		}
		if (clone.tagName == 'INPUT' && clone.type == 'text') {
			clone.value = '';
		}
		if (orig.childNodes && clone.childNodes && orig.childNodes.length > 0 && clone.childNodes.length > 0) {
			for (var i = 0; i < orig.childNodes.length && i < clone.childNodes.length; i++) {
				SearchForm.syncroniseSelectValues (orig.childNodes[i], clone.childNodes[i]);
			}
		}
		if (orig.nextSibling && clone.nextSibling) {
			SearchForm.syncroniseSelectValues (orig.nextSibling, clone.nextSibling);
		}
	},

	/// clearQuery: set this to true, if the query fields shall be emptied
	updateSearchRow: function (tr, clearQuery) {
		SearchForm.closeSaveMenu ();
		SearchForm.showHideSearchRow (tr, false);
		// get the td containing the queryfield(s)
		var comparatorContainer = tr.firstChild.nextSibling.nextSibling;
		var queryContainer = tr.firstChild.nextSibling.nextSibling.nextSibling;
		var params = "";
		// get the comparator
		if (comparatorContainer.firstChild && comparatorContainer.firstChild.tagName == 'SELECT') {
			if (comparatorContainer.firstChild.value) {
				params += '&' + comparatorContainer.firstChild.name + '=' + comparatorContainer.firstChild.value;
			}
		}
		// get all available values in queryfields and append them to the querystring
		for (var i = 0; i < queryContainer.childNodes.length; i++) {
		    if (queryContainer.childNodes[i].name && (queryContainer.childNodes[i].value + '').length > 0) {
				if (queryContainer.childNodes[i].tagName != 'SELECT') {
			        params += '&' + queryContainer.childNodes[i].name + '=' + queryContainer.childNodes[i].value;
				}
		    }
		}
		ajaxCall (createURL ('administration/search', 'update', bbMenuID, 'searchcontext=' + bbContextName + '&searchaction=' + bbActionName + '&searchdbrecordname=' + bbSearchDBRecordName + '&column=' + tr.firstChild.nextSibling.firstChild.value + '&position=' + tr.firstChild.nextSibling.firstChild.id + (clearQuery ? '&clearquery=true' : '') + params));
	},

	setSearchRow: function (id, comparator, queryField) {
		var tr = AJS.getElement (id).parentNode.parentNode;
		tr.firstChild.nextSibling.nextSibling.innerHTML = comparator;
		tr.firstChild.nextSibling.nextSibling.nextSibling.innerHTML = queryField;
		// SearchForm.updateIDs (tr.parentNode);
		SearchForm.showHideSearchRow (tr, true);
	},

	showHideSearchRow: function (tr, show) {
		tr.className = (show ? 'bbsearchquery' : 'bbsearchquery hidden');
	},

	updateIDs: function (parent, count) {
		for (var i = 0; i < parent.childNodes.length; i++) {
			if (parent.childNodes[i].id && parent.childNodes[i].id.length > 0) {
				parent.childNodes[i].id = parent.childNodes[i].id.replace (/_([0-9]+)$/, '_' + count);
				parent.childNodes[i].id = parent.childNodes[i].id.replace (/_([0-9]+)_autocompleter/, '_' + count + '_autocompleter');

				if (parent.childNodes[i].name && parent.childNodes[i].name.length > 0) {
					parent.childNodes[i].name = parent.childNodes[i].name.replace (/_([0-9]+)$/, '_' + count);
					parent.childNodes[i].name = parent.childNodes[i].name.replace (/_([0-9]+)_autocompleter/, '_' + count + '_autocompleter');
				}
			}
			SearchForm.updateIDs (parent.childNodes[i], count);
		}
	},

	clearSearch: function (tbody) {
		SearchForm.closeSaveMenu ();
		var trs = tbody.childNodes;
		for (var i = trs.length - 1; i > 0; i--) {
			// if it's a search column
			if (trs[i].firstChild.nextSibling.className == 'columnselect') {
				SearchForm.removeSearchRow (tbody.childNodes[i]);
			}
		}
		// reset column selector in first search row
		//    tr         td         td          select                   tr         td         td          select     option
		tbody.firstChild.firstChild.nextSibling.firstChild.value = tbody.firstChild.firstChild.nextSibling.firstChild.firstChild.value;
		SearchForm.updateSearchRow (tbody.firstChild, true);
	},

	// sets the id from the autocompleter to the hiddenfield
	setAutocompleterID: function (fieldName, id, text, autoCompleter) {
		if (id != null && id.length > 0) {
			AJS.getElement ('form_' + fieldName + '_autocompleter_id').value = id;
		}
		else {
			alert ('not an id');
		}
	},

	// clears the hidden field when autocompleter has been modified
	removeAutocompleterID: function (fieldName) {
		AJS.getElement ('form_' + fieldName + '_autocompleter_id').value = '';
	},

	// opens the submenu to save a search with its textfield and button
	showSaveDialog: function (evt) {
		stopEventPropagation (evt);
		this.closeSaveDialog ();
		this.closeConstraintDialog ();
		var div = AJS.getElement ('bbsearchsaveprompt');
		if (div) {
			// clear results
			AJS.getElement ('searchsaveupdate').innerHTML = '';
			div.style.display = 'block';
			ajaxCall (createURL ('administration/search', 'getsavedsearches', bbMenuID, 'searchcontext=' + bbContextName + '&searchaction=' + bbActionName + '&searchdbrecordname=' + bbSearchDBRecordName), SearchForm.loadSavedSearches4Update);
			// clear input and focus
			div.firstChild.nextSibling.firstChild.firstChild.value = '';
			div.firstChild.nextSibling.firstChild.firstChild.focus ();
		}
	},
	
	closeSaveDialog: function () {
		var div = AJS.getElement ('bbsearchsaveprompt');
		if (div) {
			div.style.display = 'none';
		}
	},

	showConstraintDialog: function (evt) {
		stopEventPropagation (evt);
		this.closeSaveDialog ();
		this.closeConstraintDialog ();
		var div = AJS.getElement ('bbconstraintsaveprompt');
		if (div) {
			div.style.display = 'block';
			ajaxCall (createURL ('administration/search', 'getconstraints', bbMenuID, 'searchcontext=' + bbContextName + '&searchaction=' + bbActionName + '&searchdbrecordname=' + bbSearchDBRecordName), SearchForm.loadConstraints4Update);
			// clear input and focus
			div.firstChild.nextSibling.firstChild.firstChild.value = '';
			div.firstChild.nextSibling.firstChild.firstChild.focus ();
		}
	},
	
	closeConstraintDialog: function () {
		var div = AJS.getElement ('bbconstraintsaveprompt');
		if (div) {
			div.style.display = 'none';
		}
	},

	loadSavedSearches4Load: function (data, req) {
		SearchForm.loadSavedSearches (data, req, 'load');
		// do we need to add additional paramaters to the search query? i.e. if we're in a select popup
		var additionalParams = '';
		// get hiddenfields and check for callback and calling information
		var elems = AJS.getElementsByTagAndClassName ('input', null, AJS.getElement ('searchform'));
		for (var i = 0; i < elems.length; i++) {
			if (elems[i].type == 'hidden') {
				if (elems[i].name == 'callbackfunction') {
					additionalParams += '&callbackfunction=' + elems[i].value;
				}
				else if (elems[i].name == 'callbackfunctionargs') {
					additionalParams += '&callbackfunctionargs=' + elems[i].value;
				}
			}
		}
		// get the available info from javascript variables
		try {
			if (bbcallingcomponentname) {
				additionalParams += '&callingcomponentname=' + bbcallingcomponentname;
			}
			if (bbcallingcontext) {
				additionalParams += '&callingcontext=' + bbcallingcontext;
			}
			if (bbcallingpath) {
				additionalParams += '&callingpath=' + bbcallingpath;
			}
			if (additionalParams) {
				// add the additional parameters to the loaded searches
				var parent = AJS.getElement ('searchsaveload');
				if (parent) {
					var ul = parent.lastChild;
					if (ul) {
						for (var i = 0; i < ul.childNodes.length; i++) {
							if (ul.childNodes[i].firstChild && ul.childNodes[i].firstChild.firstChild && ul.childNodes[i].firstChild.firstChild.href) {
								ul.childNodes[i].firstChild.firstChild.href += additionalParams;
							}
						}
					}
				}
			}
		} catch (Exception) {}
	},
	loadSavedSearches4Update: function (data, req) { SearchForm.loadSavedSearches (data, req, 'update'); },
	loadSavedSearches4Delete: function (data, req) { SearchForm.loadSavedSearches (data, req, 'delete'); },
	loadSavedSearches: function (data, req, actionName) {
		if (actionName) {
			var parent = AJS.getElement ('searchsave' + actionName);
			eval (data);
			if (parent) {
				var ul = AJS.UL ();
				if (savedSearches.length > 0) {
					for (var i = 0; i < savedSearches.length; i++) {
						var li = AJS.LI ();
						li.appendChild (AJS.DIV ());
						li.firstChild.appendChild (AJS.A ());
						li.firstChild.firstChild.innerHTML = savedSearches[i].name;
						switch (actionName) {
							case 'load':
								li.firstChild.firstChild.href = savedSearches[i].url;
								li.firstChild.appendChild (AJS.SPAN ());
								li.firstChild.lastChild.innerHTML = '&nbsp;[<a href="javascript:SearchForm.deleteSavedSearch (' + savedSearches[i].id + ')">' + bbSearchSaveDelete + '</a>]';
								break;
							case 'update':
								li.firstChild.firstChild.href = 'javascript:SearchForm.saveSearch (\'' + savedSearches[i].name + '\', ' + savedSearches[i].id + ')';
								break;
						}
						ul.appendChild (li);
					}
				}
				else {
					var li = AJS.LI ();
					li.appendChild (AJS.DIV ());
					li.firstChild.innerHTML = bbSearchNoData;
					ul.appendChild (li);
				}
				parent.innerHTML = '';
				parent.appendChild (ul);
			}
		}
	},

	loadConstraints4Load: function (data, req) { SearchForm.loadConstraints (data, req, 'load'); },
	loadConstraints4Update: function (data, req) { SearchForm.loadConstraints (data, req, 'update'); },
	loadConstraints4Delete: function (data, req) { SearchForm.loadConstraints (data, req, 'delete'); },
	loadConstraints: function (data, req, actionName) {
		if (actionName) {
			var parent = AJS.getElement ('searchsaveconstraint' + actionName);
			eval (data);
			if (parent) {
				var ul = AJS.UL ();
				if (bbConstraints.length > 0) {
					for (var i = 0; i < bbConstraints.length; i++) {
						var li = AJS.LI ();
						li.appendChild (AJS.DIV ());
						li.firstChild.appendChild (AJS.A ());
						li.firstChild.firstChild.innerHTML = bbConstraints[i].name;
						switch (actionName) {
							case 'load':
								li.firstChild.firstChild.href = bbConstraints[i].url;
								if (true) {
									li.firstChild.appendChild (AJS.SPAN ());
									li.firstChild.lastChild.innerHTML = '&nbsp;[<a href="javascript:SearchForm.deleteSavedSearch (' + bbConstraints[i].id + ', true)">' + bbConstraintDelete + '</a>]';
								}
								break;
							case 'update':
								li.firstChild.firstChild.href = 'javascript:SearchForm.saveSearch (\'' + bbConstraints[i].name + '\', ' + bbConstraints[i].id + ', true)';
								break;
						}
						ul.appendChild (li);
					}
				}
				else {
					var li = AJS.LI ();
					li.appendChild (AJS.DIV ());
					li.firstChild.innerHTML = bbSearchNoData;
					ul.appendChild (li);
				}
				parent.innerHTML = '';
				parent.appendChild (ul);
			}
		}
	},

	// closes the save menu
	closeSaveMenu: function () {
		this.closeSaveDialog ();
		this.closeConstraintDialog ();
	},

	// deletes the saved search with the given id, or the constraint if isConstraint=true
	deleteSavedSearch: function (id, isConstraint) {
		if (id) {
			ajaxCall (createURL ('administration/search', (isConstraint ? 'deleteconstraint' : 'deletesearch'), bbMenuID, 'searchid=' + id));
		}
	},

	/// name: is necessary
	/// id: optional, if set it will execute an update
	/// isConstraint: optional
	saveSearch: function (name, id, isConstraint) {
		if (name) {
			// get the saved searches
			var parameters = '';
			// get the input types in the searchform
			var form = AJS.$('searchform');
			var inputs = AJS.getElementsByTagAndClassName ('INPUT', null, form);
			var selects = AJS.getElementsByTagAndClassName ('SELECT', null, form);
			for (var i = 0; i < inputs.length; i++) {
				if (inputs[i].name) {
					if (inputs[i].name.substring (0, 12) == 'form_search_') {
						if (inputs[i].type == 'radio' || inputs[i].type == 'checkbox') {
							if (inputs[i].checked) {
								parameters += (parameters.length > 0 ? '&' : '') + inputs[i].name + '=' + AJS.urlencode (inputs[i].value);
							}
						}
						else {
							parameters += (parameters.length > 0 ? '&' : '') + inputs[i].name + '=' + AJS.urlencode (inputs[i].value);
						}
					}
				}
			}
			for (var i = 0; i < selects.length; i++) {
				if (selects[i].name) {
					if (selects[i].name.substring (0, 12) == 'form_search_') {
						parameters += (parameters.length > 0 ? '&' : '') + selects[i].name + '=' + selects[i].value;
					}
				}
			}
			ajaxCall (createURL ('administration/search', (isConstraint ? 'saveconstraint' : 'savesearch'), bbMenuID, 'searchcontext=' + bbContextName + '&searchaction=' + bbActionName + '&searchdbrecordname=' + bbSearchDBRecordName + '&searchname=' + AJS.urlencode (name) + (id ? '&searchoverride=1' : '') + '&searchparameters=' + AJS.urlencode (parameters)));
		}
		else {
			alert (bbSearchSaveEnterName);
			AJS.getElement ('bbsearchsaveprompt' + (isConstraint ? 'constraint' : '')).firstChild.nextSibling.firstChild.firstChild.focus ();
		}
	}
}

// is used from AJS.getElement for ff and safari
function findObject (theObj, theDoc) {
	var p, i, foundObj;
	if (!theDoc) {
		theDoc = document;
	}
	if ((p = theObj.indexOf ("?")) > 0 && parent.frames.length) {
		theDoc = parent.frames[theObj.substring (p + 1)].document;
		theObj = theObj.substring (0, p);
	}
	if (!(foundObj = theDoc[theObj]) && theDoc.all) {
		foundObj = theDoc.all[theObj];
	}
	for (i = 0; !foundObj && i < theDoc.forms.length; i++) {
		foundObj = theDoc.forms[i][theObj];
	}
	for (i = 0; !foundObj && theDoc.layers && i < theDoc.layers.length; i++) {
		foundObj = findObj (theObj, theDoc.layers[i].document);
	}
	if (!foundObj && document.getElementById) {
		foundObj = document.getElementById (theObj);
	}
	return foundObj;
}

if(window.console==null){
	window.console = new Object();
	window.console.log = function (text){
		if(text==null || ((""+typeof(text)).toLowerCase()=='string' && text.length==0))
		
		var div = window.console.div;
		if(div==null){
			var div = AJS.DIV();
			div.style.position = 'absolute';
			div.style.display = 'block';
			div.style.zIndex = 10000;
			div.style.top = '50px';
			div.style.left = '50px';
			div.style.border = '2px solid red';
			div.style.backgroundColor = '#EFEFEF';
			document.body.appendChild(div);
			window.console.div = div;
		}
		
		if((""+typeof(text)).toLowerCase()=='string')
			text = text.replace(/</g,'&lt;').replace(/>/g,'&gt;');
		
		var html = div.innerHTML;
		if(html.length>0)
			html += '<br/>';
		html += text;
		div.innerHTML = html;
	}
}

var ImgButton = {
	mouseOver: function (img) {
		if (img.src.indexOf ('_hover.png') > 0) {
			img.src = img.src.replace ('_hover.png', '_hover.png');
		}
		else if (img.src.indexOf ('_pushed.png') > 0) {
			img.src = img.src.replace ('_pushed.png', '_hover.png');
		}
		else {
			img.src = img.src.replace ('.png', '_hover.png');
		}
	},
	mouseOut: function (img) {
		if (img.src.indexOf ('_pushed.png') > 0) {
			img.src = img.src.replace ('_pushed.png', '.png');
		}
		else {
			img.src = img.src.replace ('_hover.png', '.png');
		}
	},
	mouseDown: function (img) {
		if (img.src.indexOf ('_hover.png') > 0) {
			img.src = img.src.replace ('_hover.png', '_pushed.png');
		}
		else if (img.src.indexOf ('_pushed.png') == 0) {
			img.src = img.src.replace ('.png', '_pushed.png');
		}
	},
	mouseUp: function (img) {
		if (img.src.indexOf ('_pushed.png') > 0) {
			img.src = img.src.replace ('_pushed.png', '_hover.png');
		}
	}
}

function setFontSize (size) {
	var increaseButton = AJS.$('fontsizeincrease');
	var decreaseButton = AJS.$('fontsizedecrease');
	switch (size) {
		case 's':
			setUserPreference ('fontsize', 's');
			decreaseButton.src = decreaseButton.src.replace ('_hover', '').replace ('fontsize_decrease', 'fontsize_decrease_inactive');
			decreaseButton.onclick = function () {};
			increaseButton.onclick = function () { setFontSize ('m') };
			setActiveStyleSheet ('fonts.css');
			break;
		case 'l':
			setUserPreference ('fontsize', 'l');
			increaseButton.src = increaseButton.src.replace ('_hover', '').replace ('fontsize_increase', 'fontsize_increase_inactive');
			decreaseButton.onclick = function () { setFontSize ('m') };
			increaseButton.onclick = function () {};
			setActiveStyleSheet ('fontl.css');
			break;
		default:
			setUserPreference ('fontsize', 'm');
			decreaseButton.src = decreaseButton.src.replace ('fontsize_decrease_inactive', 'fontsize_decrease');
			increaseButton.src = increaseButton.src.replace ('fontsize_increase_inactive', 'fontsize_increase');
			decreaseButton.onclick = function () { setFontSize ('s') };
			increaseButton.onclick = function () { setFontSize ('l') };
			setActiveStyleSheet ('fontm.css');
	}
}

function setActiveStyleSheet (fileName) {
	var i, a, main;
	for (i = 0; (a = document.getElementsByTagName ("link")[i]); i++) {
		if (a.getAttribute ("rel").indexOf ("style") != -1 && a.getAttribute ("title")) {
			a.disabled = true;
			if (a.getAttribute ("href").indexOf (fileName) > -1) {
				a.disabled = false;
			}
		}
	}
}

function setUserPreference (key, value, actionID) {
	ajaxCall (createURL ('administration/userpreference', 'setpreference', bbMenuID, 'key=' + key + '&value=' + value + (actionID ? '&actionid=' + actionID : '')));
}

function hideSelects () {
	var selects = AJS.getElementsByTagAndClassName ('select');
	for (var i = 0; i < selects.length; i++) {
		selects[i].style.visibility = 'hidden';
		selects[i].wasHidden = true;
	}
}

function showSelects () {
	var selects = AJS.getElementsByTagAndClassName ('select');
	for (var i = 0; i < selects.length; i++) {
		if (selects[i].style.visibility == 'hidden' && selects[i].wasHidden) {
			selects[i].style.visibility = 'visible';
			selects[i].wasHidden = false;
		}
	}
}

function shortenTextShow (span, show) {
	var spanToShow = (show ? span.nextSibling : span.previousSibling);
	var spanToHide = span;
	if (spanToShow && spanToHide) {
		spanToShow.style.display = '';
		spanToHide.style.display = 'none';
	}
	else {
		alert ('Error: ' + spanToShow + '/' + spanToHide);
	}
}

function preloadImages () {
    if (document.images) {
        var imgFiles = preloadImages.arguments;
        if (document.preloadArray == null) {
            document.preloadArray = new Array ();
        }
        var i = document.preloadArray.length;
        with (document) {
            for (var j = 0; j < imgFiles.length; j++) {
                if (imgFiles[j].charAt (0) != "#") {
                    document.preloadArray[i] = new Image ();
                    document.preloadArray[i++].src = imgFiles[j];
                }
            }
        }
    }
}

/// Adds the function closeMenus to the document onclick event.
function addDocumentClickListener () {
	AJS.addEventListener (document, 'click', closeMenus, false, false);
}

/// tries to find all open menues on the page if the page was clicked
/// if a user may click somewhere and the menus shall not be closed you need to stopEventPropagation on the given onclick event of that component
function closeMenus () {
	document.documentclicked = true;
	// close the searchsavemenu
	SearchForm.closeSaveMenu ();
	// find any action menu
	ActionMenu.close ();
	// close the roleselector
	closeAlternativeRoles ();
	// find lockownerinfo
	if (document.bbLockOwnerInfo) {
		document.bbLockOwnerInfo.style.display = 'none';
		if (isIE6 ()) {
			showSelects ();
		}
	}
	// find div with class='autocompleter'
	var divs = AJS.getElementsByTagAndClassName ('div', 'autocompleter');
	for (var i = 0; i < divs.length; i++) {
		// find inner div with class='output'
		var output = AJS.getElementsByTagAndClassName ('div', 'output', divs[i])
		if (output[0] && output[0].style.display == 'block') {
			fadeOut (output[0]);
			if (isIE6 ()) {
				showSelects ();
			}
		}
	}
}

/// stops event propagation for the given event
/// used to stop event from going up to the document causing the menus to be closed onclick
function stopEventPropagation (evt) {
	if (!evt) {
		var evt = window.event;
	}
	evt.cancelBubble = true;
	if (evt.stopPropagation) {
		evt.stopPropagation ();
	}
}

function unscrambleEmail (id, sUrl, sText, isEmail) {
	var obj = document.getElementById (id);
	if (obj == null) {
		alert ('unscrambleLink: Object not found (' + id + ')');
		return;
	}
	var parent = obj.parentNode;
	if (parent == null) {
		alert ('unscrambleLink: Parent object not found');
		return;
	}
	// to create standards compliant xhtml, use <div><a></a><-- scramble --></div>
	if (parent.nodeName.toLowerCase () == 'div') parent = parent.firstChild;
	if (parent.nodeName.toLowerCase () != 'a') {
		alert ('unscrambleLink: Parent object is not an anchor tag');
		return;
	}
	if (sUrl != null && sUrl.length > 0) {
		eval ('var txt = String.fromCharCode(' + sUrl + ');');
		parent.href = txt;
	}
	if (sText != null && sText.length > 0) {
		var firstChild = parent.firstChild;
		//First node is a text node with input
		if (firstChild && firstChild.nodeType == 3 && firstChild.nodeValue != null && firstChild.nodeValue.replace (' ', '').length > 0) return;
		eval ('var txt = String.fromCharCode (' + sText + ');');
		txt = txt.replace (/&amp;/g, '&');
		parent.innerHTML = txt;
		if (parent.title != null && parent.title.length == 0) {
      //No html tags
      if(txt.indexOf('<')==-1)
        parent.title = txt;
		}
	}
}

function doNothing () { }

var Manual = {
	showTOC: function () {
		AJS.getElement ('manualsearch').style.display = 'none';
		AJS.getElement ('manualtoc').style.display = 'block';
		var ul = AJS.getElement ('manualsidebar').firstChild;
		/* 
		    JF 03.11.2009
		    add a new item in the horizontal menu
		    the use of lastChid is no more correct because of the new added item.
		    we must activate the second menu's item which is no more the last one
		*/
		ul.firstChild.className = 'active';
		ul.childNodes[1].className = '';
		//ul.lastChild.className = '';
	},
	showSearch: function () {
		AJS.getElement ('manualtoc').style.display = 'none';
		AJS.getElement ('manualsearch').style.display = 'block';
		var ul = AJS.getElement ('manualsidebar').firstChild;
		ul.firstChild.className = '';
		/* 
		    JF 03.11.2009
		    add a new item in the horizontal menu
		    the use of lastChid is no more correct because of the new added item.
		    we must activate the second menu's item which is no more the last one
		*/
		ul.childNodes[1].className = 'active';
		//ul.lastChild.className = 'active';
		var tfs = AJS.getElementsByTagAndClassName ('input', 'textfield');
		if (tfs.length == 1) {
			tfs[0].focus ();
		}
	}
}

/* functions for role hot swap */
function openAlternativeRoles (evt) {
	var r = AJS.getElement ('alternativeroles');
	if (r.parentNode.className != 'opened') {
		stopEventPropagation (evt);
		if (r) {
			r.parentNode.className = 'opened';
			r.onclick = stopEventPropagation;
			if (isIE6 ()) {
				hideSelects ();
			}
			fadeIn (r, 'block');
		}
	}
}

function closeAlternativeRoles () {
	var r = AJS.getElement ('alternativeroles');
	if (r) {
		r.parentNode.className = '';
		fadeOut (r);
		if (isIE6 ()) {
			showSelects ();
		}
	}
}

function activateRole (roleID) {
	closeAlternativeRoles ();
	ajaxCall (createURL ('authentication/login', 'switch', 0, 'role_id=' + roleID));
}

function setStartpage (name, slct) {
	if (slct) {
		// this is the empty root node -> use default startpage
		var value = '';
		if (slct.value != '' || slct.selectedIndex > 0) {
			if (isNumeric (slct.value)) {
				// this is a node with an id -> use this as startpage
				value = slct.value;
			}
			else {
				// this is a node with no action associated, get next available action in menutree
				if (slct.selectedIndex > 0 && slct.selectedIndex + 1 < slct.options.length) {
					for (var i = slct.selectedIndex; i < slct.options.length && (value == ''); i++) {
						if (isNumeric (slct.options[i].value)) {
							value = slct.options[i].value;
							slct.selectedIndex = i;
						}
					}
				}
			}
		}
		setUserPreference (name, value);
		if (value = '') {
			slct.selectedIndex = 0;
		}
	}
}

function observeNewMessages (checkInterval) {
	if (!checkInterval) { checkInterval = 60; }
	
	s = window.setInterval (
		function () { checkForNewMessages (); }
	, checkInterval * 1000);
}

function checkForNewMessages () {
	ajaxCall (
		createURL ('administration/message', 'ajaxcheck'), 
		showNewMessagesAlert
	);
}

function formatDate(dateObject) {
	if (typeof dateObject !== 'string') { dateObject = dateObject + ''; }	
	if (dateObject.length === 1) {
		return '0' + dateObject;
	}
	return dateObject;
}

function showNewMessagesAlert (jsonData, req) {
	try {
		var data = eval('(' + jsonData + ')');
		if (data.reload && data.reload == true) {
			window.location.reload();
		}
		if (data.shutdown && data.shutdown != '') {
			alert(data.shutdown);	
		}
		if (data.message > 0) {
			document.getElementById('new_message_alert').innerHTML = "&nbsp;<a style=\"border: 1px solid #000; padding: 6px; background-color: #9CF;\" href=\"" + 
				createURL ('administration/message', 'listinbox') + "\"><img src=\"" + bbURLPrefix  + "img/mail_icon.gif\" />New Message!</a>";
			try {
				clearInterval(s);
			} catch (ex) { }
		}
	} catch (ex) { }
}

function getTitleFromSwissdoc () {
	var contentElement = AJS.$bytc('td', 'content', AJS.$('mappinglist_swissdocs'));
	if (contentElement == null) { 
		return;
	}
	var swissdocString = contentElement[0].innerHTML;
	swissdocString = swissdocString.replace(/.*:\s/, '');
	document.getElementById('title').value = swissdocString;
}

function saveAccountSetting (name, module, value, callback) {
	var callbackFunc = callback;
	if (callbackFunc == null) {
		callbackFunc = function () {}
	}
	ajaxCall (createURL ('administration/account', 'ajaxsaveaccountsetting', -1, 'name=' + name + '&module=' + module + '&value=' + value), callbackFunc);
}

function getAccountSetting (name, module, callback) {
	ajaxCall (createURL ('administration/account', 'ajaxgetaccountsetting', -1, 'name=' + name + '&module=' + module), callback);
}

function getWWPageNumber () {
	var re = /.*\/(\d+).*$/;
	var arr = re.exec (location.href);
	return arr[1];
}

function getLanguageByMetaTag () {
	var metas = document.getElementsByTagName ('meta');
	for (var i = 0; i < metas.length; i++) {
		if (metas[i].httpEquiv == 'content-language') {
			return metas[i].content.toLowerCase ();
			break;
		}
	}
	return null;
}

var keepMeAlive = {
	'default': {
		url: "/keep_me_alive.aspx", //url for session refreshing
		timeout: 1500000 //25*60*1000 = 25min
	},
	ping: function(url, timeout) {
		var _req, _url, _timeout, _def = keepMeAlive['default'];
		this.setUrl = function(url){
			_url = url?url:_def.url;return this;
		}
		this.setTimeout = function(timeout){
			_timeout = timeout?timeout:_def.timeout;return this;
		}
		var send = function() {
			_req.sendReq();
		}
		var initializeTimeout = function(data){
			window.setTimeout(ini, _timeout);
		}
		var ini = function(){
			_req = null;
			_req = AJS.getRequest (_url, null, 'GET');
			_req.addCallback (initializeTimeout);
			_req.addErrback (function (data, req) {ini()});
			send();
		}
		this.setUrl(url).setTimeout(timeout);ini();
	}
}