/*
 * knwebstd-tools: Basic JavaScript library of the Kuehne+Nagel WebStandard Framework
 *
 * Copyright (c) 2008 Kuehne+Nagel
 *
 * This code is not freeware. It may not be used for any (private or commercial) purposes except by
 * Kuehne+Nagel and its associated companies.
 *
 * This library requires the jQuery-xx.js to be loaded before this one, with version xx: 1.2.3 <= xx < 1.3 .
 */
// create namespaces
if (!window.knwebstd) {
	window.knwebstd = new Object();
}

// Checks if the current browser is Internet Explorer
knwebstd.isIE = function() {
    var _info = navigator.userAgent;
    var _ie = (_info.indexOf("MSIE") > 0);
    return _ie;
}

/**
* Draws an IFRAME under the layer of an element with given id.
* IFRAME is drawn only if the given object exists and if
* used browser is an Internet Explorer.
*/
knwebstd.drawIframe = function(elementId, zIndex) {
    zIndex--;
    if(knwebstd.isIE()) {
        var elCount = $("#" + elementId).size();
        if(elCount >0) {
            $("body").append("<iframe id='v_iframe"+ zIndex +"' src='javascript:false;' style='position: absolute; top: 0px; left 0px; width: 100%; height: 100%; z-index: "+ zIndex +"; filter: progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0);'></iframe>");
        }
    }
}

// Removes an IFRAME that is placed below the given layer
knwebstd.removeIframe = function(zIndex) {
    if(knwebstd.isIE()) {
        zIndex--;
        $("#v_iframe"+zIndex).remove();
    }
}

// centers the given element on the page (correct initial CSS style assumed)
knwebstd.centerOnPage = function(selector) {
    var element = $(selector);
    // The css style places the element (top-left-corner) at the center of the page.
    // This move it back out by half its width and height to center it on the page
    // To avoid moving it too far out the actual window dimensions are considered the limit.
    // Goal is to show at least the icon that will close the element.
    var jqWindow = $(window);
    var height = Math.min(jqWindow.height()-20,element.height());
    var width = Math.min(jqWindow.width()-20,element.width());
    // if element could not be placed as desired, allow scrolling so that users can read the whole page
    if (((height!=element.height()) || (width!=element.width())) && element.is(".knwebstd_overlay_centered_fixed")) {
    	element.removeClass("knwebstd_overlay_centered_fixed");
    	element.addClass("knwebstd_overlay_centered");
    }
    element.css("margin-top","-"+Math.round(height/2)+"px");
    element.css("margin-left","-"+Math.round(width/2)+"px");
}

// Calculate dynamic parameter string from object or function
knwebstd.paramStr = function(dynamicParams) {
    var result = '';
    if (dynamicParams) {
       var params = (typeof dynamicParams == 'function') ? dynamicParams() : dynamicParams;
       for (var param in params) {
           if (result != '') {
               result += '&';
           }
           result+=param+'='+encodeURIComponent(params[param]);
       }
    }
    return result;
}

// Extract the body content of an HTML text and put it into an enclosing DIV. Need to do this extra work as JQuery traversal
// does not detect top level DIVs and does not work with body tag at all.
knwebstd.extractBodyContent = function(data) {
    if (data.indexOf('<body>') >= 0) {
        data = data.substring(data.indexOf('<body>')+6);
        if (data.indexOf('</body>') >= 0) {
            data = data.substring(0, data.indexOf('</body>'));
        }
    }
    return '<div>' + data + '</div>';
}

// Process error response to be displayed inline/as overlay (extract the actual error message and replace link
// target by proper link to remove error message).
knwebstd.processInlineErrorResponse = function(data, target) {
	var errorMessage = $(data);
    $('#knwebstd_error_nav a', errorMessage).each(function() {
        $(this).attr('href', target ? 'javascript:knwebstd.closeError(\'' + target + '\');' : 'javascript:knwebstd.closeError();');
        $(this).html('Close');
    });
    if ($('#knwebstd_error_message', errorMessage).size() == 1) {
       var trailer = '<div><div id="knwebstd_error_message"';
       if (!target) {
           trailer += 'style="width:450px;margin-left:12px;margin-right:12px">';
       } else {
           trailer += '>';
       }
       return $(trailer + $('#knwebstd_error_message', errorMessage).html() + '</div></div>');
    } else {
       return $('<div>' + errorMessage.html() + '</div>');
    }
}

// Create standard error message for client side errors (with optional close link).
knwebstd.createError = function(errorText, showLink, target) {
    var errorMessage = "<div id=\"knwebstd_error_message\" style=\"width:450px;margin-left:12px;margin-right:12px\"><table class=\"knwebstd_msg_error_table\"><tr>" +
                       "<td class=\"knwebstd_msg_error_title\">Internal Server Error</td></tr><tr><td class=\"knwebstd_msg_error_body\"><p>";
    errorMessage += errorText;
    errorMessage += "</p></td></tr>";
    errorMessage += "<tr><td class=\"knwebstd_msg_error_nav\">"
    if (showLink) {
        errorMessage += "<div id=\"knwebstd_error_nav\"><a href=\"javascript:knwebstd.closeError(";
	    if (target) {
	        errorMessage += '\'' + target + '\'';
	    }
        errorMessage += ");>Close</a></div>";
    } else {
        errorMessage += "&nbsp;";
    }
    errorMessage += "</td></tr></table></div>";
    return errorMessage;
}

// Trigger closing of an error message that was displayed in response to a sub-dialog or ajax request. This will either close
// an overlay or empty an Ajax zone depending on the context.
knwebstd.closeError = function(target) {
     if (target) {
         $('#' + target).empty();
     } else if ((window.parent && window.parent.knwebstd.dialog && window.parent.knwebstd.dialog.currentDialog) ||
                (knwebstd.dialog && knwebstd.dialog.currentDialog)) {
         knwebstd.dialog.closeMe();
     } else if (knwebstd.lookup && knwebstd.lookup.currentLookup) {
         knwebstd.lookup.cancelOverlayLookup();
     }
}

/**
 * Wrapper for JQuery(selecor, context) function - resp. its abbreviation '$(selecor, context)'.
 * It can be used when the selector is HTML represented by a String and provides a much better performance than the direct usage of
 * the JQuery object because its omits the time consuming implementation that checks if selector is a String.
 * @param selector: a String that represents HTML
 * @param context, optionally JQuery context (see JQuery for an explanation).
 * @return The JQuery object, that would be returned if JQuery would have been called directly.
 */
knwebstd.JQueryFromHtmlString = function(selector, context) {
	// Make sure that a selection was provided
	selector = selector || document;

	selector = jQuery.clean( [ selector ], context );
	return $(selector);
}

/**
 * Wrapper for JQuery(selector, context) that expects the selector to be an id of a DOM element.
 * Takes care of escaping dots (.) in the id string and adds the required '#' in front.
 */
knwebstd.JQueryFromIdString = function(selector, context) {
	// Make sure that a selection was provided
	selector = selector || document;

	selector = '#'+selector.replace(/\./g,"\\.");
	return $(selector);
}

// needs refactoring (strange order of parameters)
function setDispatch(form, value) {
	// support for simply setting the dispatch of the first form
	if (value==null) { value=form; form=0; }
	return set(form, 'dispatch', value);
}

// needs refactoring (strange order of parameters)
function setEvent(form, value) {
	// support for simply setting the event of the first form
	if (value==null) { value=form; form=0; }
	return set(form, 'event', value);
}

// needs refactoring (strange order of parameters)
function setEventDispatch(form, value) {
	// support for simply setting the event/dispatch of the first form
	if (value==null) { value=form; form=0; }
	dialogEvent = document.forms[form].elements['event'];
	if (dialogEvent!=null) { dialogEvent.value=value; }
	dispatch = document.forms[form].elements['dispatch'];
	if (dispatch!=null) { dispatch.value=value; }
}

function startLookup(lookupTargetField, lookupType, form) {
	setEventDispatch(form,'lookupStart');
	set(form,'lookupTargetField',lookupTargetField);
	set(form,'lookup',lookupType);
	return submitMonitor();
}

// needs refactoring (strange order of parameters and masking of errors)
function set(form, field, value) {
	if (form==null) { form = 0; }
	if(document.forms[form] && document.forms[form].elements[field]) {
		document.forms[form].elements[field].value=value;
	}
	return true;
}

// needs refactoring (strange order of parameters)
function setEventAndSubmit(form, eventValue) {
	setEvent(form, eventValue);
	return submit(form);
}

function submit(form) {
	document.forms[form].submit();
	return submitMonitor();
}

// needs refactoring (strange order of parameters, rename to setDispatchAndSubmit)
function submitForm(form, dispatchValue) {
 	// combines the onclick script of the pages into one routine
 	// better to use this from the javascript menu
 	setDispatch(form,dispatchValue);
	submit(form);
}

var submitCounter = 0;
function submitMonitor() {
    submitCounter++;
    return ( submitCounter == 1 );
}

function maySubmit() {
    return submitCounter == 0;
}

function resetSubmitMonitor() {
    submitCounter = 0;
}

// needs refactoring (strange order of parameters and masking of errors)
function setFocusControl(formName, elementName) {
	if(document.forms[formName] && document.forms[formName].elements[elementName]) {
		var focusControl = document.forms[formName].elements[elementName];
		if (focusControl.type != "hidden" && !focusControl.disabled) {
			focusControl.focus();
		}
	}
}

// rethink location of this function (lookup specific!)
function disableLookupAcceptButton(listName, formName, buttonName, buttonFormName) {
	if (buttonFormName==null) buttonFormName = formName;
	if(document.forms[formName]) {
		list = document.forms[formName].elements[listName];
		if(list) {
			for (i=0; i<list.length;i++) {
				if (list.options[i].selected) {
					setFocusControl(buttonFormName, buttonName);
					return true;
				}
			}
			disableElement(buttonFormName, buttonName, true);
			setFocusControl(formName, listName);
		}
	}
	return true;
}

// rethink location of this function (lookup specific!)
function updateLookupAcceptButton(listName, formName, buttonName, buttonFormName) {
	if (buttonFormName==null) buttonFormName = formName;
	if(document.forms[formName]) {
		list = document.forms[formName].elements[listName];
		if(list) {
			for (i=0; i<list.length;i++) {
				if (list.options[i].selected) {
					disableElement(buttonFormName, buttonName, false);
					return true;
				}
			}
			disableElement(buttonFormName, buttonName, true);
		}
	}
	return true;
}

// needs refactoring (strange order of parameters and masking of errors)
function disableElement(formName, elementName, isDisabled) {
	if(document.forms[""+formName] && document.forms[""+formName].elements[""+elementName]) {
		document.forms[""+formName].elements[""+elementName].disabled = isDisabled;
	}
}

// rename to disableFormElements
function disableForm(formName) {
	if (formName==null) formName=0;
	form = document.forms[formName];
	if(form) {
		for (i=0; i<form.elements.length; i++) {
    		form.elements[i].disabled=true;
		}
	}
}

function updateTextareaCounter(textAreaField, maxLen, counterField) {
	var value = textAreaField.value;
	var currentLen = value.length;

	// Count leading and trailing whitespaces
	var trailingSpaces = 0;
	while((trailingSpaces < currentLen) && isWhitespace(value.charAt(currentLen - trailingSpaces - 1))) {
		trailingSpaces++;
	}
	var leadingSpaces = 0;
	while((leadingSpaces < currentLen - trailingSpaces) && isWhitespace(value.charAt(leadingSpaces))) {
		leadingSpaces++;
	}

	updateTextareaCounterFromTo(textAreaField, maxLen, counterField, leadingSpaces, currentLen-trailingSpaces);
}

function updateTextareaCounterUntrimmed(textAreaField, maxLen, counterField) {
    var value = textAreaField.value;
	var currentLen = value.length;

	updateTextareaCounterFromTo(textAreaField, maxLen, counterField, 0, currentLen);
}

function updateTextareaCounterFromTo(textAreaField, maxLen, counterField, from, to) {
    var value = textAreaField.value;
 	// ASCII 10 = Line Feed (LF) = Escape sequence '\n'
	// ASCII 13 = Carriage Return (CR) = Escape sequence '\r'
	// Firefox, Aix/Unix, Java: New Line = LF (1 char)
	// Internet Explorer, Windows: New Line = CR + LF (2 char)
	// => Ignore CR characters in text area
/*	Changed due to RT #1571917.
 *
 *  Just ignoring of \r is not conform to validation of length in Validator. Both, the \n and the \r will be
 *  stored in the database, so they both count for the length restriction.
 *  In fact, even if the browser only uses the \n character, the string sent to the application
 *  server contains \r\n. So we don't count the \r but count the \n twice.
 *  The amount of line feeds is concidered once in the value of currentLen, so it has to be
 *  applied once again.
 *
 */
	var returnCount = 0;
	var feedCount = 0;
	for(var i = from; i < to; i++) {
	    if(value.charCodeAt(i) == 13) {
	        returnCount++;
	    }
	    if(value.charCodeAt(i) == 10) {
	        feedCount++;
	    }
	}
	var counter = maxLen - to + from + returnCount - feedCount;
	counterField.value = counter;

	if(counter < 0) {
		counterField.style.backgroundColor = '#ff9999';
	} else {
		counterField.style.backgroundColor = '#ebebeb';
	}
}

function isWhitespace(c) {
	return (c == ' ') || (c == '\t') || (c == '\n') || (c == '\r') || (c == '\f');
}

function updateBlockDisplay(openElement, closedElement, fieldName, toggle) {
	var displayOpen='';
	var displayClosed='none';
	var field = document.forms[0].elements[fieldName];

	if (toggle) {
		if(field.value == 'true') {
			field.value = 'false';
		} else {
			field.value = 'true';
		}
	}

	if(field.value == 'true') {
	    // do nothing
	} else {
		displayOpen = 'none';
		displayClosed = '';
	}

	document.getElementById(openElement).style.display=displayOpen;
	document.getElementById(closedElement).style.display=displayClosed;
}

function toggleBlockDisplay(openElement, closedElement, fieldName) {
	updateBlockDisplay(openElement,closedElement,fieldName,true);
}

// determines the vertical position of an object on the page
function findPosY(obj) {
	var curtop = 0;
	if (obj.offsetParent) {
		while (obj.offsetParent) {
			curtop += obj.offsetTop
			obj = obj.offsetParent;
		}
	} else if (obj.y) {
		curtop += obj.y;
    }
	return curtop;
}

// determines the horizontal position of an object on the page
function findPosX(obj) {
	var curleft = 0;
	if (obj.offsetParent) {
		while (obj.offsetParent) {
			curleft += obj.offsetLeft
			obj = obj.offsetParent;
		}
	} else if (obj.x) {
		curleft += obj.x;
	}
	return curleft;
}

// aligns two objects on the page by adjusting the vertical position of the second object to that
// of the first, optionally adding an offset.
// if the first object is not specified, only the offset will be applied, effectively moving the object by that value
function alignTop(elem1, elem2, offset) {
	if (elem2!=null && (elem1!=null || (offset!=null && offset!=0))) {
		var yPos = findPosY(elem2);
		elem2.style.position="relative";
		if (offset==null) { offset = 0; }
		if (elem1!=null) {
			elem2.style.top=findPosY(elem1)-yPos+offset;
		} else {
			elem2.style.top=offset;
		}
	}
}

// aligns two objects on the page by adjusting the vertical position of the second object to that
// of the first, optionally adding an offset.
// The two objects need to be given by their id, which will then be used to find the objetcts themselves.
function alignTopById(elem1Id, elem2Id, offset) {
	alignTop(document.getElementById(elem1Id),document.getElementById(elem2Id),offset);
}

// copies the value of the first field to another
function syncField(source, targetName, targetForm) {
   set(targetForm,targetName,source.value);
}

// clears up to 5 fields
function clearFields(form, field1, field2, field3, field4, field5) {
   if (field1!=null) { set(form,field1,""); }
   if (field2!=null) { set(form,field2,""); }
   if (field3!=null) { set(form,field3,""); }
   if (field4!=null) { set(form,field4,""); }
   if (field5!=null) { set(form,field5,""); }
}

// adds an event handler for the onload event
function addOnloadHandler(handler) {
   if ( window.addEventListener ) { // Mozilla, Netscape, Firefox
      addEventListener("load", handler, false);
   } else if ( window.attachEvent ) { // IE
      attachEvent("onload", handler);
   }
}

// deactivates all links contained inside an element by replacing the "a"-elements with their html content inside a "span"-element
function deactivateLinksInElement(element) {
	if (element) {
	   // get all "a"-elements contained inside element
		var anchors=element.getElementsByTagName("a");
		// copy array (we want to manipulate it later)
		var length=anchors.length;
		var copyArray=new Array();
		for (i=0; i<length; i++) {
			copyArray[i]=anchors[i];
		}
		// now manipulate the anchors, replacing them with their content to remove the link
		for (i=0; i<length; i++) {
		    var anchor=copyArray[i];
		    if (anchor.href && anchor.href!="" && anchor.innerHTML && anchor.innerHTML!="") {
				// copy html content to a new "span"-element
				var content = document.createElement("span");
				content.innerHTML=anchor.innerHTML;
				// preserve style information as provided by style class.
				// (Inline styles are not copied, too difficult to get right for all browsers!)
				// Remember: Styles defined in surrounding elements are kept by inheritance, use a span around the anchor if needed.
				content.className=anchor.className;
				// replace original anchor with newly created element
				anchor.parentNode.replaceChild(content,anchor);
			}
		}
	}
}

// deactivates all links contained inside an element given by it's id by replacing the "a"-elements with their html content inside a "span"-element
function deactivateLinksInElementById(id) {
	// retrieve the element and deactivate it's links
	var element = document.getElementById(id);
	deactivateLinksInElement(element);
}

// tab2 dialog method for tab2 navigation with post: edit or write dialogs, not for readonly dialogs
function changeTabWithPost(currentBlockName, nextTab) {
	if(submitMonitor()) {
		document.getElementById(currentBlockName + ".nextTab").value = nextTab;
		setEventAndSubmit(0, currentBlockName + ".changeTab");
	}
}

// Sets a hidden field (to be mapped to a Boolean form property) depending on the state of a checkbox
// The naming convention is checkboxName = hiddenFieldName+"Checkbox"
// used to overcome the problem that unchecked checkboxes result in missing request parameters
function setBooleanFromCheckbox(property) {
	var hidden = document.forms[0].elements[property];
	var checkBox = document.forms[0].elements[property+"Checkbox"];
	if (hidden != null && checkBox != null) {
		if(checkBox.checked == 1) {
			hidden.value = true;
	    } else {
	    	hidden.value = false;
	    }
	}
}

// Sets the state of a checkbox to reflect the value of a hidden field (to be mapped to a Boolean form property)
// The naming convention is checkboxName = hiddenFieldName+"Checkbox"
// used to overcome the problem that unchecked checkboxes result in missing request parameters
function setCheckboxFromBoolean(property) {
	var hidden = document.forms[0].elements[property];
	var checkBox = document.forms[0].elements[property+"Checkbox"];
	if (hidden != null && checkBox != null) {
		if(hidden.value == "true") {
			checkBox.checked = 1;
		} else {
			checkBox.checked = 0;
		}
	}
}

// opens a popup window to show the screen help in
function openHelpWindow(url, width, height) {
    if (!width) {
        width=619;
    }
    if (!height) {
        height=600;
    }
    vWinHlp = window.open(url, "Help",
    "width=" + width + ",height=" + height + ",status=no,resizable=yes,scrollbars=yes,top=50,left=150");
    vWinHlp.opener = self;
    vWinHlp.focus();
};


// functionality for an intelligent date input field
var month_names = new Array();
month_names[0]="JAN";
month_names[1]="FEB";
month_names[2]="MAR";
month_names[3]="APR";
month_names[4]="MAY";
month_names[5]="JUN";
month_names[6]="JUL";
month_names[7]="AUG";
month_names[8]="SEP";
month_names[9]="OCT";
month_names[10]="NOV";
month_names[11]="DEC";

function validateDate(obj,destDate,monthDayOrder) {
  var content=obj.value;
  var parse=false;

  // Do not validate emtpy date fields.
  if(content==""){
    return;
  }

  // Actual date
  var myDate = new Date();

  // Rules to check
  var rule_t = /^[t]{1}$/i;
  var rule_t_plus_days = /^[t]{1}[\+]{1}\d{1,}$/i;
  var rule_t_minus_days = /^[t]{1}[\-]{1}\d{1,}$/i;
  var rule_nn = /^\d{1,2}$/i;
  var rule_nn_xxx = /^\d{1,2}\s\w{3}$/i;
  var rule_nnxxx = /^\d{1,2}\w{3}$/i;
  var rule_nn_xxxx = /^\d{1,2}\s\d{4}$/i;
  var rule_nnnnnn = /^\d{6}$/i;
  var rule_ddmmmyyyy = /^\d{1,2}\w{3}(\d{2}|\d{4})$/i;
  var rule_dd_mmm_yyyy = /^\d{1,2}[\s]{1}\w{3}[\s]{1}(\d{2}|\d{4})$/i;
  var rule_dd_mm_yy = /^\d{1,2}[\.|\s|\-|\/]{1}\d{1,2}[\.|\s|\-|\/]{1}\d{1,2}$/;

	var day, month, year;

  if(rule_t.test(content)) { //	t 	the system date
    parse=true;
  } else if(rule_t_plus_days.test(content)) { //	t+x 	the system date + x days
    myDate.setDate(myDate.getDate()+eval(content.substr(2)));
    parse=true;
  } else if(rule_t_minus_days.test(content)) { //	t-x 	system date ? x days
    myDate.setDate(myDate.getDate()-eval(content.substr(2)));
    parse=true;
  } else if(rule_nn.test(content)) { //  N or NN = Day; autofill current month and current year
    day=eval(content);
    month=myDate.getMonth();
    year=myDate.getYear();
    parse=isValidDate(day, month, year);
    myDate.setDate(day);
  } else if(rule_nn_xxx.test(content)) { //	NN XXX  NN=Day; XXX=Month; autofill current year
    var parts=content.split(/\s/);
    day=eval(parts[0]);
    month=getMonthFor(parts[1]);
	year=myDate.getYear();
    parse=isValidDate(day, month, year);
	myDate.setMonth(month,day);
  } else if(rule_nnxxx.test(content)) { //	NNXXX  NN=Day; XXX=Month; autofill current year
    day=eval(content.substr(0,content.length-3));
    month=getMonthFor(content.substr(content.length-3, 3));
	year=myDate.getYear();
    parse=isValidDate(day, month, year);
	myDate.setMonth(month,day);
  } else if(rule_nn_xxxx.test(content)) { //	NN XXXX  autofill current day
    var parts=content.split(/\s/);
    day=myDate.getDate();
    month=eval(parts[0])-1;
    year=eval(parts[1]);
    parse=isValidDate(day, month, year);
    myDate.setYear(year);
    myDate.setMonth(month);
  } else if(rule_nnnnnn.test(content)) { //	NNNNNN = 040806  order of month/day depends on function argument
    if (monthDayOrder) {
	    month=eval(content.substr(0,2))-1;
	    day=eval(content.substr(2,2));
    } else {
	    day=eval(content.substr(0,2));
	    month=eval(content.substr(2,2))-1;
	}
    year=completeYear(eval(content.substr(4,2)));
    parse=isValidDate(day, month, year);
    myDate.setYear(year);
    myDate.setMonth(month,day);
  } else if(rule_ddmmmyyyy.test(content)) { //	DDMMMYYYY or DDMMMYY
    if(isNumeric(content.substr(0,2))) {
      day=eval(content.substr(0,2));
      month=getMonthFor(content.substr(2,3));
      year=completeYear(eval(content.substr(5)));
    } else {
      day=eval(content.substr(0,1));
      month=getMonthFor(content.substr(1,3));
      year=completeYear(eval(content.substr(4)));
    }
    parse=isValidDate(day, month, year);
    myDate.setYear(year);
    myDate.setMonth(month,day);
  } else if(rule_dd_mmm_yyyy.test(content)) { //	DD MMM YYYY or DD MMM YY
    var parts=content.split(/\s/);
    day=eval(parts[0]);
    month=getMonthFor(parts[1]);
    year=completeYear(eval(parts[2]));
    parse=isValidDate(day, month, year);
    myDate.setYear(year);
    myDate.setMonth(month,day);
  } else if(rule_dd_mm_yy.test(content)) { // DD MM YY
  	var parts=content.split(/[\.|\s|\-|\/]{1}/);
  	day=eval(parts[0]);
  	month=eval(parts[1]-1);
  	year=completeYear(eval(parts[2]));
  	parse=isValidDate(day, month, year);
		myDate.setYear(year);
		myDate.setMonth(month,day);
	}

  // Create output value
  if(parse) {
    // create date
    var tempdate=destDate;

    // YEAR
    var date_yyyy=/YYYY/i;
    var date_yy=/YY/i;

    if(tempdate.match(date_yyyy)) {
      tempdate = tempdate.replace(date_yyyy, myDate.getFullYear().toString());
    } else if(tempdate.match(date_yy)) {
      tempdate = tempdate.replace(date_yy, myDate.getFullYear().substr(2).toString());
    }

    // MONTH
    var date_mmm=/MMM/i;
    var date_mm=/MM/i;
    var date_m=/M/i;

    if(tempdate.match(date_mmm)) {
      tempdate = tempdate.replace(date_mmm, month_names[myDate.getMonth()]);
    } else if(tempdate.match(date_mm)) {
      tempdate = tempdate.replace(date_mm, ((myDate.getMonth()+1 < 10) ? "0" + (myDate.getMonth()+1) : (myDate.getMonth()+1)).toString() );
    } else if(tempdate.match(date_m)) {
      tempdate = tempdate.replace(date_m, (myDate.getMonth()+1).toString());
    }

    // DAY
    var date_dd=/DD/i;
    var date_d=/D/i;

    if(tempdate.match(date_dd)) {
      tempdate = tempdate.replace(date_dd, ((myDate.getDate() < 10) ? "0" + myDate.getDate() : myDate.getDate()).toString() );
    } else if(tempdate.match(date_d)) {
      tempdate = tempdate.replace(date_d, myDate.getDate().toString());
    }

    obj.value=tempdate;
  } else {
    alert("Invalid entry in the date field, please correct or click on the \"Help\" menu for further explanations!");
  	obj.value="";
  }
}

var number_of_days = new Array();
number_of_days[0] = 31;
number_of_days[1] = 29;
number_of_days[2] = 31;
number_of_days[3] = 30;
number_of_days[4] = 31;
number_of_days[5] = 30;
number_of_days[6] = 31;
number_of_days[7] = 31;
number_of_days[8] = 30;
number_of_days[9] = 31;
number_of_days[10] = 30;
number_of_days[11] = 31;

function isValidDate(day, month, year) {
	if(year < 0) return false;

	if(month < 0 || month > 11) return false;

	if(month != 1) {
		if(day < 1 || day > number_of_days[month]) return false;
	} else {
		if(isLeapYear(year)) {
			if(day < 1 || day > number_of_days[month]) return false;
		} else {
			if(day < 1 || day > number_of_days[month]-1) return false;
		}
	}

	return true;
}

function isLeapYear(year) {
	return ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0));
}

// returns the nr of the month shortname
function getMonthFor(shortname) {
  var rc=-1;

  for(i=0;i<12;i++) {
    if(month_names[i].toLowerCase()==shortname.toLowerCase()) {
      rc=i;
    }
  }

  return rc;
}

// check if content of the variable is numeric
function isNumeric(x) {
  var RegExp = /^(-)?(\d*)(\.?)(\d*)$/;
  var result = x.match(RegExp);
  return result;
}

// complete a year that is only 2-digit
// 00-79 = 2000-2079
// 80-99 = 1980-1999
function completeYear(year) {
  if(year>=0 && year<=79) {
    year=year+2000;
  }
  return year;
}

// simply hides from the projects the fact that we use a 3rd party script
function addTooltipHandler() {
	document.write('<script language="javascript" src="static/js/wz_tooltip.js"></script>');
}

/**
*    Override split to always return empty values and overcome other browser inconsistencies.
*    See http://blog.stevenlevithan.com/archives/cross-browser-split
*/

String.prototype.nativeSplit = String.prototype.nativeSplit || String.prototype.split;

String.prototype.split = function (s /* separator */, limit) {
    // If separator is not a regex, use the native split method
    if (!(s instanceof RegExp))
        return String.prototype.nativeSplit.apply(this, arguments);


    var flags = (s.global ? "g" : "") + (s.ignoreCase ? "i" : "") + (s.multiline ? "m" : ""),
        s2 = new RegExp("^" + s.source + "$", flags),
        output = [],
        lastLastIndex = 0,
        i = 0,
        match;

    if (!s.global)
        s = new RegExp(s.source, "g" + flags);

    while ((!limit || i++ <= limit) && (match = s.exec(this))) {
        var zeroLengthMatch = !match[0].length;

        // Fix IE's infinite-loop-resistant but incorrect lastIndex
        if (zeroLengthMatch && s.lastIndex > match.index)
            s.lastIndex = match.index; // The same as s.lastIndex--

        if (s.lastIndex > lastLastIndex) {
            // Fix browsers whose exec methods don't consistently return undefined for non-participating capturing groups
            if (match.length > 1) {
                match[0].replace(s2, function () {
                    for (var j = 1; j < arguments.length - 2; j++) {
                        if (arguments[j] === undefined)
                            match[j] = undefined;
                    }
                });
            }

            output = output.concat(this.slice(lastLastIndex, match.index), (match.index === this.length ? [] : match.slice(1)));
            lastLastIndex = s.lastIndex;
        }

        if (zeroLengthMatch)
            s.lastIndex++;
    }

    return (lastLastIndex === this.length) ?
        (s.test("") ? output : output.concat("")) :
        (limit      ? output : output.concat(this.slice(lastLastIndex)));
};

//extend jQuery ajax with the capability of remembering the count of active ajax requests to allow selenium to check
//if all ajax requests are finished by checking knwebstd.activeAjaxRequestCount = 0;
//idea: inc counter for each ajax request sent, dec again if successful or error occured.
//theoretically there could be a problem if a fast repeating ajax request does not give selenium the chance to catch the counter at 0, but that's very unlikely.
knwebstd.activeAjaxRequestCount = 0;

$().ajaxSend(function() {
  knwebstd.activeAjaxRequestCount++;
  // register lazily to make sure it's the last one and get executed after all other handlers
  if (!knwebstd._ajaxErrorHandlerAdded) {
      $().ajaxError(function() {
      	if (knwebstd.activeAjaxRequestCount > 0) {
              knwebstd.activeAjaxRequestCount--;
      	}
      });
  knwebstd._ajaxErrorHandlerAdded = true;
}
})
.ajaxSuccess(function() {
  if (knwebstd.activeAjaxRequestCount > 0) {
      knwebstd.activeAjaxRequestCount--;
	}
});