function checkIsMostRecentRequest(path, serverMethod, requestNumber)
{
	var requestParameters = {
		requestNumber: requestNumber.toString()
	};
	var responseParameters = performAjaxRequest(path, serverMethod, requestParameters);
	if (responseParameters.status != "ok")
	{
		window.location.reload();
	}
}

// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
// Funktionen zum Navigieren (Url-Aufrufe, Back, Hilfsfunktionen, ...)
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----


function cancelAndBack()
{
	window.history.back(1);
	return false;
}

function navigateTo(uri)
{
	uri = checkForAdditionalUrlParameter(uri);
	// Ursprünglich enthielt die Funktion lediglich folgenden Aufruf:
	//  window.location.href = uri;
	// Leider ist überträgt der IE dabei nicht den Referrer (so wie bei einem Klick auf einen
	// Link). Mit Firefox hingegen funktioniert es. Daher wird für den IE hier der Umweg mit dem
	// Link gemacht:
	var a = document.createElement("a");
	if (a.click)
	{
		a.href = uri;
		a.style.display = "none";
		document.body.appendChild(a);
		a.click();
	}
	else
	{
		window.location.href = uri;
	}
	return false;
}

var additionalUrlParameter = new Object();

function checkForAdditionalUrlParameter(uri)
{
	for (var key in additionalUrlParameter)
	{
		var pos = uri.indexOf(key + "=");
		if (pos != -1)
		{
			// Schlüssel bereits vorhanden => entfernen
			var partOne = uri.substr(0, pos - 1);
			var partTwo = uri.substr(pos)
			while (partTwo[0] != "&" && partTwo.length > 0)
			{
				partTwo = partTwo.subtsr(1);
			}
			uri = partOne + partTwo;			
		}
		if (uri.lastIndexOf("&") < uri.length -1)
		{
			uri += "&";
		}
		uri += key + "=" + additionalUrlParameter[key];
	}
	return uri;
}

function closeWindow()
{
	window.close();
	return false;
}

// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
// Fehler- und Infomeldungen anzeigen
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----

function displayError(messages)
{
	clearAndHideMslErrorAndMslInfo();
	fillMessageList(mslError, messages);	
}

function displayInfo(messages)
{
	clearAndHideMslErrorAndMslInfo();
	fillMessageList(mslInfo, messages);	
}

function clearAndHideMslErrorAndMslInfo()
{
	if (mslError) 
	{
		mslError.innerHTML = "";
		mslError.style.display = 'none';	
	}
	if (mslInfo)
	{
		mslInfo.innerHTML = "";
		mslInfo.style.display = 'none';	
	}
}

function fillMessageList(msl, messages)
{
	if (msl) 
	{
		msl.innerHTML = "";
		var trennzeichen = "\n";
		var count = 0;
		if (messages) 
		{
			messages = messages.trim();
			var ul = document.createElement("ul");
			while (messages)
			{
				count++;
				var index = messages.indexOf(trennzeichen) + 1;
				if (index == 0)
				{
					index = messages.length;
				}
				var text = messages.substring(0, index).trim();
				messages = messages.substring(index, messages.length).trim();
				var li = document.createElement("li");
				li.innerHTML = text;
				ul.appendChild(li);
			}
			msl.appendChild(ul);
		}
		if (count > 0) 
		{
			msl.style.display = 'block';		
		}
		else
		{
			msl.style.display = 'none';		
		}
	}
}

// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
// ENDE: Fehler- und Infomeldungen anzeigen
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----

	String.prototype.leftTrim = function () {
		return (this.replace(/^\s+/,""));
	};
	
	String.prototype.rightTrim = function () {
		return (this.replace(/\s+$/,""));
	};

	String.prototype.trim = function () {
		return (this.replace(/\s+$/,"").replace(/^\s+/,""));
	};
	


// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
// Auswahlfenster öffnen usw.
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----

function clearSelection(idOfElementSavingId, idOfElementSavingText)
{
	var elementSavingId = document.getElementById(idOfElementSavingId);
	elementSavingId.value = null;
	var elementSavingText = document.getElementById(idOfElementSavingText);
	elementSavingText.value = null;
	return false;
}

//TODO
//	What you need to use them:
//		Write yourself a couple of easy to use JavaScript functions to take care of opening and
//		closing them.
//
//		function closeDialog(returnValue)
//		{
//			window.returnValue = returnValue;
//			window.close();
//		}
//
//		function GetDialogFeatures(dialogWidth, dialogHeight, resizable)
//		{
//			return "dialogWidth: " + dialogWidth + "px;dialogHeight: " + dialogHeight + "px;"
//				+ "status: no;unadorned: yes;scroll: no;help: no;"
//				+ (resizable ? "resizable: yes;" : "");
//		}
//
//	Usage Example
//
//		var retValue indow.showModalDialog("SomePage?id=" + id, "", GetDialogFeatures(500, 240, false));
//		if (retValue)
//		{
//			window.location.reload(true);
//		}
//
//	Include in the <head> section of your page the following tag:
//
//		<base target="_self"></base>

function openSelectWindow(relativePath, idOfElementSavingId, idOfElementSavingText)
{
	//TODO
	//	In FireFox, using window.open() method, the html doc in the dialog can have something like
	//	<body onblur="window.focus();"> which will make it modal.
	//
	//	You may want to test for browser compatibility, something like this:
	//
	//	if (window.showModalDialog)
	//	{
	//		//do the showModalDialog way
	//	}
	//	else
	//	{
	//		//do the window.open() way
	//	}
	var url = applicationRoot + "global/modalFrameSet.aspx?path=" + relativePath + "%3fmode%3dmodal";
	var options = 'dialogWidth=800px;dialogHeight=600px;scroll=no;status=no;';
	var result = window.showModalDialog(url, "", options);
	if (result)
	{
		var elementSavingId = document.getElementById(idOfElementSavingId);
		elementSavingId.value = result["id"];
		var elementSavingText = document.getElementById(idOfElementSavingText);
		elementSavingText.value = result["text"];
	}
	return false;
}

function returnSelection(selectedId, selectedText)
{
	window.returnValue = {
		"id": String(selectedId),
		"text": String(selectedText)
	};
	window.close();
	return false;
}

// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
// DataInfo mit ID/Bea/BeaZ aktualisieren
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----

function fillDataInfo(alias, objectId, bea, beaZ)
{
	// DataInfo-Daten mit Hilfe des Alias im Array suchen
	var dataInfo = null;
	for (var i = 0; i < dataInfoArray.length && dataInfo == null; i++)
	{
		if (dataInfoArray[i].alias == alias)
		{
			dataInfo = dataInfoArray[i];
		}
	}
	if (dataInfo != null)
	{
		document.getElementById(dataInfo.lbObjectId).innerText = objectId;
		document.getElementById(dataInfo.lbBea).innerText = bea;
		document.getElementById(dataInfo.lbBeaZ).innerText
			= parseDate(beaZ).format(dataInfoBeaZFormatString);
	}
}

// Macht aus übergebener Zeichenkette eine Date-Objekt (sofern möglich, sonst wird null
// zurückgegeben)
function parseDate(dateAsString)
{
	dateAsString = String(dateAsString);
	var date = null;
	if (dateAsString.length > 0)
	{
		// z.B. "12.05.2008 17:43:44" wird geteilt in "12.05.2008" und "17:43:44"
		var ar = dateAsString.split(" ");
		// Datumsteil konvertieren (erlaubt auch etwas unkonventionellere Angaben wie "12508" für
		// das o.g. Beispiel - aber immer in einer Form mit der Reihenfolge Tag-Monat-Jahr)
		date = CF.convertDate(ar[0]);
		if (date != null && ar.length > 1 && ar[1].length > 1)
		{
			// Ließ sich der Datumsteil konvertieren und gibt es einen Zeitanteil, dann wird dieser
			// zunächst in seine Bestandteile getrennt (o.g. Bsp.: "17", "43" und "44")
			var time = CF.convertStringAndTrim(ar[1]).replace(/:/g, ".").replace(/,/g, ".")
				.replace(/-/g, ".").split(".");
			// Enthält der Stundenanteil eine Zahl?
			if (time[0].length > 0 && isFinite(Number(time[0])))
			{
				// Stundenanteil speichern
				date.setHours(Number(time[0]));
				// Gibt es einen Minutenanteil und enthält dieser eine Zahl?
				if (time.length > 1 && time[1].length > 0 && isFinite(Number(time[1])))
				{
					// Minutenanteil speichern
					date.setMinutes(Number(time[1]));
					// Gibt es einen Sekundenanteil und enthält dieser eine Zahl?
					if (time.length > 2 && time[2].length > 0 && isFinite(Number(time[2])))
					{
						// Sekundenanteil speichern
						date.setSeconds(Number(time[2]));
					}
				}
			}
		}
	}
	return date;
}

// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
// Druckvorschau öffnen
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----

// Methode verarbeitet n Parameter:
// - Erster Parameter ist Pfad zur zu öffnenden Seite
// - Ab dem zweiten Parameter gibt es immer Parameterpaare der Form "Schlüssel, Wert"
// - Beispiel für einen Aufruf: openPrintWindow("print.html", "name", "Johnsson", "age", 32);
function openPrintWindow(relativePath)
{
	var parameters = "mode=print";
	for (var i = 1; i < arguments.length; i++)
	{
		if (i % 2 == 1)
		{
			parameters += ("&" + arguments[i] + '=' + MaskParameterValue(arguments[i + 1]));
		}
	}
	window.open(applicationRoot + relativePath + "?" + parameters);
	return false;
}

// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
// Ajax-Request abschicken
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----

// Parameter:
// - path: string
// - serverMethod: string
// - requestParameters: HashTable
// Rückgabe:
// - Objekt mit drei Eigenschaften:
//   - status: string ("ok" oder "error")
//   - message: string (Erfolgs- bzw. Fehlermeldung)
//   - parameters: HashTable
function performAjaxRequest(path, serverMethod, requestParameters)
{
	var url = path + "?mode=ajaxProcess&method=" + serverMethod;
	var requestParameterString = "";
	for (var parameterName in requestParameters)
	{
		requestParameterString += (
			";" + MaskParameterValue(parameterName)
			+ "=" + MaskParameterValue(requestParameters[parameterName])
		);
	}
	if (requestParameterString.length > 0)
	{
		// Erstes ";" wegschneiden
		requestParameterString = requestParameterString.substring(1);
	}
	var responseParameterString = gsCallServerMethod(url, requestParameterString);
	var pairs = responseParameterString.split(";");
	var responseParameters = {};
	for (var i = 0; i < pairs.length; i++)
	{
		var keyValue = pairs[i].split("=");
		responseParameters[UnmaskParameterValue(keyValue[0])] = UnmaskParameterValue(keyValue[1]);
	}
	var status = responseParameters["status"];
	delete(responseParameters["status"]);
	var message = responseParameters["message"];
	delete(responseParameters["message"]);
//	if (message.length > 0)
//	{
//		if (status == "error")
//		{
//			displayError(message);
//		}
//		else
//		{
//			displayInfo(message);
//		}
//	}
//	return responseParameters;
	return {
		status: status,
		message: message,
		parameters: responseParameters
	};
}

function gsCallServerMethod(sURL, sParams, lFlags)
{
	var oSMthHttp;
	if (window.XMLHttpRequest) // Mozilla, Safari, ...
	{
		oSMthHttp = new XMLHttpRequest();
	}
	else if (window.ActiveXObject) // IE
	{
		oSMthHttp = new ActiveXObject("Microsoft.XMLHTTP");
	}
	oSMthHttp.open('POST', sURL, false);
	oSMthHttp.send(sParams);
	// trim the response
	var sResponse = oSMthHttp.responseText;
	oSMthHttp = null;
	sResponse = sResponse.replace(/(^\s*)|(\s*$)/g, "");
	return(sResponse);
}

// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
// Hilfsfunktionen zum Arbeiten mit Parameter-Zeichenketten
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----

function MaskParameterValue(sParamStr)
{
    // Die Sonderzeichen '=' und ';' müssen maskiert werden
    // es wird der ASCII-Wert ohne abschließendes ';' verwendet
    sParamStr = sParamStr.replace(/=/g, '&#061');
    sParamStr = sParamStr.replace(/;/g, '&#059');
    return sParamStr;
}

function UnmaskParameterValue(sParamStr)
{
    if (sParamStr == null)
        return "";
    // Die Sonderzeichen '=' und ';' müssen maskiert werden
    // es wird der ASCII-Wert ohne abschließendes ';' verwendet
    sParamStr = sParamStr.replace(/&#061/g, '=');
    sParamStr = sParamStr.replace(/&#059/g, ';');
    
    return sParamStr;
}

function GetParameter(sName, sParamStr)
{
    sParamStr = UnmaskParameterValue(sParamStr);
	var arPairs = sParamStr.split(";");
	var arPairsGleich
	for (var i = 0; i < arPairs.length; i++)
	{
		arPairsGleich = arPairs[i].split("=");
		if (arPairsGleich[0] == sName)
			return arPairsGleich[1];
	}
	return "";
}		 



// ********************************************************************************
// *                                                                              *
// *   Globale Funktionen                                                         *
// *                                                                              *
// ********************************************************************************

var CF = (function(){
	//Fügt Tausender-Trennzeichen in einen String hinzu (rekursiv)
	this.addThousandsSeperator = function(str)
	{
		var ret = "";
		str = String(str);
		if(str.length > 3)
		{
			var beforeSeparator = str.substr(0, str.length - 3);
			var behindSeparator = str.substr(str.length - 3, 3);
			ret = addThousandsSeperator(beforeSeparator) + "." + behindSeparator;
		}
		else
		{
			ret = str;
		}
		return (ret);
	}

	//Hängt zwei Funktionen aneinander
	//	ev = Vorhandene Funktion
	//	fu = Funktion, die vor die vorhandene Funktion gehängt wird
	this.appendFunction = function(ev, fu)
	{
		if(typeof(ev) == "function")
		{
			ev = ev.toString();
			ev = ev.substring(ev.indexOf("{") + 1, ev.lastIndexOf("}"));
		}
		else
		{
			ev = "";
		}
		return new Function(fu + "; " + ev);
	}

	//Hängt zwei Funktionen aneinander
	//	ev = Vorhandene Funktion
	//	fu = Funktion, die hinter die vorhandene Funktion gehängt wird
	this.appendFunction2 = function(ev, fu)
	{
		if(typeof(ev) == "function")
		{
			ev = ev.toString();
			ev = ev.substring(ev.indexOf("{") + 1, ev.lastIndexOf("}"));
		}
		else
		{
			ev = "";
		}
		return new Function(ev + "; " + fu);
	}

	//Gibt immer einen boolschen Wert zurück (true oder false)
	//	false: 0, null, undefined, NaN
	//	sonst true
	this.convertBoolean = function(value)
	{
		//Hinweis: !! ist ein JavaScript-Operator zum Konvertieren in einen boolschen Wert.
		return (!!value);
	}

	//Wandelt übergebenen Wert in ein Date-Objekt um (null, wenn nicht möglich)
	//	startOfCenturyRange = Zweistellige Zahl (Standard = 50), die den Bereich angibt, der bei
	//		einer zweistelligen Jahreseingabe erkannt wird (z.B. 50 für den Bereich 1950 bis 2049,
	//		aus Eingaben 50 bis 99 werden Jahre 1950 bis 1999, aus 0 bis 49 werden 2000 bis 2049)
	this.convertDate = function(value, startOfCenturyRange)
	{
		var ret = null;
		var isDateAlready = false;
		if(value.getFullYear != null && value.getMonth != null && value.getDate != null)
		{
			isDateAlready = true;
		}
		else
		{
			value = convertStringAndTrim(value).replace(/,/g, ".");
		}
		if(isDateAlready || value.length > 0)
		{
			var year = 0;
			var month = -1;
			var day = 0;
			var now = new Date();
			if(isDateAlready)
			{
				year = value.getFullYear();
				month = value.getMonth();
				day = value.getDate();
			}
			else
			{
				var ar = value.split(".");
				if(ar.length >= 3)
				{
					var s0 = convertStringAndTrim(ar[0]);
					if(s0.length > 0)
					{
						day = parseInt(s0, 10);
						var s1 = convertStringAndTrim(ar[1]);
						if(s1.length == 0)
						{
							month = now.getMonth();
						}
						else
						{
							month = parseInt(s1, 10) - 1;
						}
						var s2 = convertStringAndTrim(ar[2]);
						if(s2.length == 0)
						{
							year = now.getFullYear();
						}
						else
						{
							year = parseInt(s2, 10);
						}
					}
				}
				else if(ar.length == 2)
				{
					var s0 = convertStringAndTrim(ar[0]);
					if(s0.length > 0)
					{
						day = parseInt(s0, 10);
						var s1 = convertStringAndTrim(ar[1]);
						if(s1.length == 0)
						{
							month = now.getMonth();
						}
						else
						{
							month = parseInt(s1, 10) - 1;
						}
						year = now.getFullYear();
					}
				}
				else if(value.length == 8 || value.length == 6 || value.length == 4)
				{
					//Annahme, daß Eingabe im Format "ddMMyyyy", "ddMMyy" bzw. "ddMM"
					day = parseInt(value.substr(0, 2), 10);
					month = parseInt(value.substr(2, 2), 10) - 1;
					if(value.length == 8)
					{
						year = parseInt(value.substr(4, 4), 10);
					}
					else if(value.length == 6)
					{
						year = parseInt(value.substr(4, 2), 10);
					}
					else
					{
						year = now.getFullYear();
					}
				}
				else if(value.length == 7 || value.length == 5 || value.length == 3)
				{
					//Annahme, daß Eingabe im Format "dMMyyyy", "dMMyy" bzw. "dMM"
					//                oder im Format "ddMyyyy", "ddMyy" bzw. "ddM"
					//Erster Versuch: einstelliger Tag, zweistelliger Monat
					day = parseInt(value.substr(0, 1), 10);
					month = parseInt(value.substr(1, 2), 10) - 1;
					if(month < 0 || 11 < month)
					{
						//Zweiter Versuch: zweistelliger Tag, einstelliger Monat
						day = parseInt(value.substr(0, 2), 10);
						month = parseInt(value.substr(2, 1), 10) - 1;
					}
					if(value.length == 7)
					{
						year = parseInt(value.substr(3, 4), 10);
					}
					else if(value.length == 5)
					{
						year = parseInt(value.substr(3, 2), 10);
					}
					else
					{
						year = now.getFullYear();
					}
				}
				else
				{
					day = parseInt(value, 10);
					month = now.getMonth();
					year = now.getFullYear();
				}
				if(year < 100)
				{
					if(startOfCenturyRange == null)
					{
						startOfCenturyRange = 50;
					}
					else
					{
						startOfCenturyRange = convertInt(startOfCenturyRange);
						if(!isFinite(startOfCenturyRange) || startOfCenturyRange < 0 || 99 < startOfCenturyRange)
						{
							startOfCenturyRange = 50;
						}
					}
					if(year < startOfCenturyRange)
					{
						year += 2000;
					}
					else
					{
						year += 1900;
					}
				}
			}
			var check = new Date(year, month, day);
			if(check.getFullYear() == year && check.getMonth() == month && check.getDate() == day)
			{
				ret = check;
			}
		}
		return (ret);
	}

	//Wandelt übergebenen Wert in ein Date-Objekt um, das den ersten des Monats enthält (null,
	//	wenn nicht möglich)
	//	startOfCenturyRange = Zweistellige Zahl (Standard = 50), die den Bereich angibt, der bei
	//		einer zweistelligen Jahreseingabe erkannt wird (z.B. 50 für den Bereich 1950 bis 2049,
	//		aus Eingaben 50 bis 99 werden Jahre 1950 bis 1999, aus 0 bis 49 werden 2000 bis 2049)
	this.convertFirstOfMonth = function(value, startOfCenturyRange)
	{
		var ret = null;
		var isDateAlready = false;
		if(value.getFullYear != null && value.getMonth != null)
		{
			isDateAlready = true;
		}
		else
		{
			value = convertStringAndTrim(value).replace(/\./g, "/").replace(/,/g, "/").replace(/-/g, "/");
		}
		if(isDateAlready || value.length > 0)
		{
			var year = 0;
			var month = -1;
			var now = new Date();
			if(isDateAlready)
			{
				year = value.getFullYear();
				month = value.getMonth();
			}
			else
			{
				var ar = value.split("/");
				var containsDelimiters = (ar.length >= 2);
				if(containsDelimiters)
				{
					var s0 = convertStringAndTrim(ar[0]);
					if(s0.length > 0)
					{
						month = parseInt(s0, 10) - 1;
						var s1 = convertStringAndTrim(ar[1]);
						if(s1.length == 0)
						{
							year = now.getFullYear();
						}
						else
						{
							year = parseInt(s1, 10);
						}
					}
				}
				else if(value.length == 6 || value.length == 4)
				{
					//Annahme, daß Eingabe im Format "MMyyyy" bzw. "MMyy"
					month = parseInt(value.substr(0, 2), 10) -1 ;
					if(value.length == 6)
					{
						year = parseInt(value.substr(2, 4), 10);
					}
					else
					{
						year = parseInt(value.substr(2, 2), 10);
					}
				}
				else if(value.length == 5 || value.length == 3)
				{
					//Annahme, daß Eingabe im Format "Myyyy" bzw. "Myy"
					month = parseInt(value.substr(0, 1), 10) - 1;
					if(value.length == 5)
					{
						year = parseInt(value.substr(1, 4), 10);
					}
					else
					{
						year = parseInt(value.substr(1, 2), 10);
					}
				}
				else
				{
					month = parseInt(value, 10) - 1;
					year = now.getFullYear();
				}
				if(!containsDelimiters)
				{
					//Wurde ein komplettes Datum eingegeben, z.B. "010906" - gemeint als 09/2006,
					// dann wurde oben für month 1 und für year 906 erkannt. Dieser Umstand ist mit
					// den Jahren 100 bis 1299 möglich und wird hier korrigiert:
					if(100 <= year && year <= 1299)
					{
						var valueAsDate = convertDate(value, startOfCenturyRange);
						if(valueAsDate != null)
						{
							year = valueAsDate.getFullYear();
							month = valueAsDate.getMonth();
						}
					}
				}
				if(year < 100)
				{
					if(startOfCenturyRange == null)
					{
						startOfCenturyRange = 50;
					}
					else
					{
						startOfCenturyRange = convertInt(startOfCenturyRange);
						if(!isFinite(startOfCenturyRange) || startOfCenturyRange < 0 || 99 < startOfCenturyRange)
						{
							startOfCenturyRange = 50;
						}
					}
					if(year < startOfCenturyRange)
					{
						year += 2000;
					}
					else
					{
						year += 1900;
					}
				}
			}
			var check = new Date(year, month, 1);
			if(check.getFullYear() == year && check.getMonth() == month)
			{
				ret = check;
			}
		}
		return (ret);
	}

	//Gibt immer einen Integer-Wert zurück (NaN, Infinity oder Zahl)
	//	NaN: undefined, NaN, String mit nicht interpretierbarer Zahl
	//	Infinity: Infinity, String mit zu großer/kleiner Zahl
	//	1: true
	//	0: false, Leerstring, null
	//	sonst die entsprechende Zahl
	this.convertInt = function(value)
	{
		//Hinweis: + ist ein JavaScript-Operator zum Konvertieren in eine Zahl.
		var ret = +value;
		if(isFinite(ret))
		{
			ret = Math.round(ret);
		}
		return (ret);
	}

	//Schneidet führende und nachfolgende Leerzeichen eines Strings ab, gibt immer einen
	// String zurück (nicht null)
	this.convertStringAndTrim = function(value)
	{
		var s = (value == null ? "" : String(value));
		//Folgende zwei Zeilen kopiert aus MS.Net-ClientValidationScript:
		var m = s.match(/^\s*(\S+(\s+\S+)*)\s*$/);
		return (m == null) ? "" : m[1];
	}

	//Liefert true, wenn eine der Pfeiltasten gedrückt wurde
	this.cursorMoved = function()
	{
		var ev = window.event;
		return (ev != null && 36 < ev.keyCode && ev.keyCode < 41);
	}

	//Formatiert übergebenen Wert als Datum
	//	startOfCenturyRange = Zweistellige Zahl (Standard = 50), die den Bereich angibt, der bei
	//		einer zweistelligen Jahreseingabe erkannt wird (z.B. 50 für den Bereich 1950 bis 2049,
	//		aus Eingaben 50 bis 99 werden Jahre 1950 bis 1999, aus 0 bis 49 werden 2000 bis 2049)
	//	renderTwoDigitYear = boolscher Wert (Standard = false), der angibt, ob Jahreszahl nur
	//		zweistellig ausgegeben werden soll (z.B. "05.03.99" anstatt "05.03.1999")
	this.formatDate = function(value, startOfCenturyRange, renderTwoDigitYear)
	{
		var ret = "";
		value = convertDate(value, startOfCenturyRange);
		if(value != null)
		{
			var year = value.getFullYear();
			var sYear = (year < 10 ? "0" : "") + String(year);
			renderTwoDigitYear = convertBoolean(renderTwoDigitYear);
			if(renderTwoDigitYear)
			{
				sYear = sYear.substr(sYear.length - 2, 2);
			}
			var month = value.getMonth() + 1;
			var day = value.getDate();
			ret = (day < 10 ? "0" : "") + String(day) + "." + (month < 10 ? "0" : "") + String(month) + "." + sYear;
		}
		return (ret);
	}

	//Formatiert übergebenen Wert als Monatsangabe (MM/yyyy)
	//	startOfCenturyRange = Zweistellige Zahl (Standard = 50), die den Bereich angibt, der bei
	//		einer zweistelligen Jahreseingabe erkannt wird (z.B. 50 für den Bereich 1950 bis 2049,
	//		aus Eingaben 50 bis 99 werden Jahre 1950 bis 1999, aus 0 bis 49 werden 2000 bis 2049)
	//	renderTwoDigitYear = boolscher Wert (Standard = false), der angibt, ob Jahreszahl nur
	//		zweistellig ausgegeben werden soll (z.B. "03/99" anstatt "03/1999")
	this.formatMonth = function(value, startOfCenturyRange, renderTwoDigitYear)
	{
		var ret = "";
		value = convertFirstOfMonth(value, startOfCenturyRange);
		if(value != null)
		{
			var year = value.getFullYear();
			var sYear = (year < 10 ? "0" : "") + String(year);
			renderTwoDigitYear = convertBoolean(renderTwoDigitYear);
			if(renderTwoDigitYear)
			{
				sYear = sYear.substr(sYear.length - 2, 2);
			}
			var month = value.getMonth() + 1;
			ret = (month < 10 ? "0" : "") + String(month) + "/" + sYear;
		}
		return (ret);
	}

	//Formatiert übergebenen Wert als Zahl
	//	decimalPlaces = Anzahl Nachkommastellen (Standard = 0), die ausgegeben werden, wird u.U.
	//		gerundet, fehlende Stellen mit Nullen aufgefüllt
	//	renderThousandsSeperator = boolscher Wert (Standard = false), der angibt, ob der Wert mit
	//		Tausendertrennzeichen ausgegeben werden soll (z.B. "1.561,92" anstatt "1561,92")
	this.formatNumber = function(value, decimalPlaces, renderThousandsSeperator)
	{
		var ret = "";
		var valueIsNumber = (typeof(value) == "number");
		if(!valueIsNumber)
		{
			value = convertStringAndTrim(value);
			//Enthält value ein Komma oder mehr als einen Punkt, dann werden alle Punkte entfernt
			// (ein einziger Punkt wird als Komma betrachtet)
			if(value.indexOf(",") >= 0 || (value.indexOf(".") != value.lastIndexOf(".")))
			{
				value = value.replace(/\./g, "");
			}
			value = value.replace(/,/g, ".");
		}
		if(valueIsNumber || (value.length > 0 && !isNaN(value)))
		{
			decimalPlaces = convertInt(decimalPlaces);
			if(!isFinite(decimalPlaces) || decimalPlaces < 0)
			{
				decimalPlaces = 0;
			}
			var factor = Math.pow(10, decimalPlaces);
			//Weist value einen ganzzahligen Wert zu: Soll z.B. 12,489 auf zwei Nachkommastellen
			// gerundet werden, enthält value dann 1250 (auf null Nachkommastellen gerundet wäre es
			// 12, auf eine 125)
			value = Math.round(Number(value).toFixed(decimalPlaces) * factor);
			var isNegative = false;
			if(value < 0)
			{
				isNegative = true;
				value = -value;
			}
			value = String(value);
			var integral = "";
			var fractional = "";
			if(decimalPlaces == 0)
			{
				integral = value;
			}
			else
			{
				//Der oben ermittelte Wert wird nun an der entsprechenden Stelle geteilt und mit
				// einem Punkt dazwischen wieder zusammengesetzt. Dabei muß der Wert wenigstens
				// Anzahl Nachkommastellen + eine Vorkommastelle lang sein. Das ist u.a. nicht der
				// Fall, wenn man 0,0526 auf drei Nachkommastellen rundet - value enthält dann "53"
				// anstatt "0053" - hier muß mit Nullen aufgefüllt werden.
				if(value.length < decimalPlaces + 1)
				{
					var j = decimalPlaces + 1 - value.length;
					for(var i = 0; i < j; i++)
					{
						value = "0" + value;
					}
				}
				integral = value.substr(0, value.length - decimalPlaces);
				fractional = value.substr(value.length - decimalPlaces, decimalPlaces);
			}
			renderThousandsSeperator = convertBoolean(renderThousandsSeperator);
			if(renderThousandsSeperator)
			{
				integral = addThousandsSeperator(integral);
			}
			ret = integral;
			if(fractional.length > 0)
			{
				ret = ret + "," + fractional;
			}
			if(isNegative)
			{
				ret = "-" + ret;
			}
		}
		return (ret);
	}

	//Formatiert übergebenen Wert als Uhrzeit
	//	allow24 = boolscher Wert (Standard = false), der aussagt, ob Eingabe 24:00 Uhr erlaubt sein
	//		soll (sonst nur Eingaben zwischen 0:00 Uhr und 23:59 Uhr)
	//	renderHourWithoutLeadingZero = boolscher Wert (Standard = false), der aussagt, ob
	//		Stundenzahl ohne führende Null ausgegeben werden soll (z.B. "9:12" anstatt "09:12")
	this.formatTime = function(value, allow24, renderHourWithoutLeadingZero)
	{
		var ret = "";
		value = convertStringAndTrim(value).replace(/:/g, ".").replace(/,/g, ".").replace(/-/g, ".");
		if(value.length > 0 && !isNaN(value))
		{
			value = Number(value);
			if(value >= 100)
			{
				value = (value / 100);
			}
			var h = parseInt(value, 10);
			var min = parseInt(Math.round((value - h) * 100), 10);
			allow24 = convertBoolean(allow24);
			if(h >= 0 && h < 24 && min >= 0 && min < 60 || allow24 && h == 24 && min == 0)
			{
				renderHourWithoutLeadingZero = convertBoolean(renderHourWithoutLeadingZero);
				ret = (!renderHourWithoutLeadingZero && h < 10 ? "0" : "") + String(h)
					+ ":" + (min < 10 ? "0" : "") + String(min);
			}
		}
		return (ret);
	}

	//Entfernt Zeichen von angegebener Stelle aus einem String
	this.removeChar = function(str, index)
	{
		str = String(str);
		var substr1 = str.substring(0, index);
		var substr2 = str.substring(index + 1, str.length);
		return (substr1 + substr2);
	}
	
	this.StringIsNullOrEmpty = function(str)
	{
		if (str != null)
		{
			return (str.length == 0);
		}
		return true;
	}

	return (this);
})();


// ********************************************************************************
// *                                                                              *
// *   TextBox-AutoValidate- und -Format-Funktionen                               *
// *                                                                              *
// *   (entfernen sofort beim Tastendruck illegale Zeichen aus Textboxen)         *
// *                                                                              *
// ********************************************************************************

//Entfernt alle Zeichen aus dem String value, die nicht im String valid enthalten sind
function ValidateString(value, valid)
{
	for (var i=0; i<value.length;)
	{
		if (valid.indexOf(value.charAt(i)) == -1)
			value = removeChar(value, i);
		else
			i++;
	}
	return value;
}

//Entfernt alle Zeichen ausser Zahlen und dem jeweils erstvorkommenden Komma bzw. Prozentzeichen
function ValidatePercentage(value)
{
	var valid = ",% 0123456789";
	var index = 0;
	var komma = false;
	var prozent = false;
	for(var i = 0; i < value.length;)
	{
		index = valid.indexOf(value.charAt(i));
		if(index == -1 || index == 0 && komma || index == 1 && prozent)
		{
			value = removeChar(value, i);
		}
		else
		{
			komma = (index == 0);
			prozent = (index == 1);
			i++;
		}
	}
	return value;
}

//Entfernt alle Zeichen ausser Zahlen und dem 1. Komma aus dem String
function ValidateFloat(value, allowminus)
{
	var valid = ",0123456789";
	var index = 0;
	var kommas = 0;
	for (var i=0; i<value.length;)
	{
		index = valid.indexOf(value.charAt(i));
		if (index == -1)
		{
			if (i==0 && allowminus)
			{
				// "-" ist ist an erster Stelle zulässig
				if (value.charAt(0) == "-")
				{
					i++;
				}
				else
				{
					value = removeChar(value, i);
				}
			}
			else
			{
				value = removeChar(value, i);
			}
		}
		else
		{
			if (index == 0)
			{
				kommas++;
				if (kommas > 1)
				{
					value = removeChar(value, i);
					kommas--;
				}
				else
				{
					i++;
				}
			}
			else
			{
				i++;
			}
		}
	}
	return value;
}

//Entfernt alle Zeichen ausser Zahlen
function ValidateInteger(value, allowminus)
{
	var valid = "0123456789";
	for (var i=0; i<value.length;)
	{
		if (valid.indexOf(value.charAt(i)) == -1)
		{
			if (i==0 && allowminus)
			{
				if (value.charAt(0) == "-")
				{
					i++;
				}
				else
				{
					value = removeChar(value, i);
				}
			}
			else
			{
				value = removeChar(value, i);
			}
		}
		else
		{
			i++;
		}
	}
	return value;
}

//Entfernt alle Zeichen ausser Zahlen und der zulässigen Anzahl an Doppelpunkten
function ValidateTime(value, mode)
{
	var valid = ":0123456789";
	var index = 0;
	var dp = 0;
	var dpanz = 0;
	switch(mode)
	{
		case "timelong":
			dpanz = 3;
			break;
		case "time":
		case "timeshort":
		case "timenontechnical":
			dpanz = 2;
			break;
	}
	for (var i=0; i<value.length;)
	{
		index = valid.indexOf(value.charAt(i));
		if (index == -1)
		{
			value = removeChar(value, i);
		}
		else
		{
			if (index == 0)
			{
				dp++;
				if (dp > dpanz)
				{
					value = removeChar(value, i);
					dpanz--;
				}
				else
				{
					i++;
				}
			}
			else
			{
				i++;
			}
		}
	}
	return value;
}

//Entfernt alle Zeichen ausser Zahlen und der zulässigen Anzahl an Punkten
function ValidateDate(value)
{
	var valid = ".0123456789";
	var index = 0;
	var p = 0;
	var panz = 2;
	for (var i=0; i<value.length;)
	{
		index = valid.indexOf(value.charAt(i));
		if (index == -1)
		{
			value = removeChar(value, i);
		}
		else
		{
			if (index == 0)
			{
				p++;
				if (p > panz)
				{
					value = removeChar(value, i);
					panz--;
				}
				else
				{
					i++;
				}
			}
			else
			{
				i++;
			}
		}
	}
	return value;
}

//Entfernt alle Zeichen ausser Zahlen und dem Trennzeichen aus dem String
function ValidateMonth(value)
{
	var valid = "/0123456789";
	var index = 0;
	var trenner = 0;
	for (var i=0; i<value.length;)
	{
		index = valid.indexOf(value.charAt(i));
		if (index == -1)
		{
			value = removeChar(value, i);
		}
		else
		{
			if (index == 0)
			{
				trenner++;
				if (trenner > 1)
				{
					value = removeChar(value, i);
					trenner--;
				}
				else
				{
					i++;
				}
			}
			else
			{
				i++;
			}
		}
	}
	return value;
}

//Kürzt den Inhalt bei Bedarf auf maxlength
function ValidateMaxLength(id, maxlength)
{
	if (CF.cursorMoved())
		return;

	if (maxlength < 1)
		return;

	var ctrl = document.getElementById(id);
	if (ctrl.value.length > maxlength)
	{
		ctrl.value = ctrl.value.substring(0, maxlength);
	}
}

function Validate(element, validationFormat)
{
	if (CF.cursorMoved())
	{
		return;
	}
	if (validationFormat==null || validationFormat=="")
	{
		return;
	}

	var newvalue = element.value;
	var vf = CF.convertStringAndTrim(validationFormat).toLowerCase();

	switch(vf)
	{
		// TextBoxNumber
		case "float":
		case "currency":
			newvalue = ValidateFloat(element.value);
			break;
		case "floatminus":
		case "currencyminus":
			newvalue = ValidateFloat(element.value, true);
			break;
		case "integer":
			newvalue = ValidateString(element.value, "0123456789");
			break;
		case "integerminus":
			newvalue = ValidateInteger(element.value, true);
			break;
		case "percentage":
			newvalue = ValidatePercentage(element.value);
			break;
		// TextBoxDateTime
		case "date":
			newvalue = ValidateDate(element.value);
			break;
		case "time":
		case "timelong":
		case "timeshort":
		case "timenontechnical":
			newvalue = ValidateTime(element.value, vf);
			break;
		// TextBoxMonth
		case "monthshort":
		case "monthlong":
			newvalue = ValidateMonth(element.value);
			break;
		// TextBoxString
		case "callnumber":
			newvalue = ValidateString(element.value, " -0123456789");
			break;
	}

	if (element.value != newvalue)
	{
		element.value = newvalue;
	}
}

function FormatElement(element, validationFormat)
{
	var value = element.value;
	var formattedValue = null;
	var vf = CF.convertStringAndTrim(validationFormat).toLowerCase();
	switch(vf)
	{
		//TextBoxNumber
		case "float":
		case "floatminus":
			if(element.DP != null)
			{
				formattedValue = CF.formatNumber(value, element.DP);
			}
			break;
		case "currency":
		case "currencyminus":
			formattedValue = CF.formatNumber(value, 2);
			break;
		case "integer":
		case "integerminus":
			formattedValue = CF.formatNumber(value, 0);
			break;
		case "percentage":
			formattedValue = CF.formatNumber(value.replace(/%/g, ""), 2);
			if(formattedValue.length > 0)
			{
				formattedValue = formattedValue + " %";
			}
			break;
		//TextBoxDateTime
		case "date":
			//formatDate(value, startOfCenturyRange, renderTwoDigitYear)
			formattedValue = CF.formatDate(value, null, true);
			break;
		case "time":
		case "timelong":
		case "timeshort":
		case "timenontechnical":
			//formatTime(value, allow24, renderHourWithoutLeadingZero)
			formattedValue = CF.formatTime(value, true, false);
			break;
		//TextBoxMonth
		case "monthshort":
			//formatDate(value, startOfCenturyRange, renderTwoDigitYear)
			formattedValue = CF.formatMonth(value, null, true);
			break;
		case "monthlong":
			//formatDate(value, startOfCenturyRange, renderTwoDigitYear)
			formattedValue = CF.formatMonth(value, null, false);
			break;
		//TextBoxString
		case "callnumber":
			//TODO
			//	?
			break;
	}
	if(formattedValue != null && formattedValue != value)
	{
		element.value = formattedValue;
	}
}

// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
// Funktion "format" für Date-Objekte (nutzt FormatString)
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
// Der Code ist im Vergleich zum Original etwas geändert: Die Wirkung von "m" und "M" ist
// vertauscht, damit es genauso funktioniert wie unter .Net (im Originalscript stand "m" für
// Monat und "M" für Minuten - das ist jetzt andersherum).
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
// http://blog.stevenlevithan.com/archives/date-time-format
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----

/*
	Date Format 1.1
	(c) 2007 Steven Levithan <stevenlevithan.com>
	MIT license
	With code by Scott Trenda (Z and o flags, and enhanced brevity)
*/

/*** dateFormat
	Accepts a date, a mask, or a date and a mask.
	Returns a formatted version of the given date.
	The date defaults to the current date/time.
	The mask defaults ``"ddd mmm d yyyy HH:MM:ss"``.
*/
var dateFormat = function () {
	var	token        = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloZ]|"[^"]*"|'[^']*'/g,
		timezone     = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
		timezoneClip = /[^-+\dA-Z]/g,
		pad = function (value, length) {
			value = String(value);
			length = parseInt(length) || 2;
			while (value.length < length)
				value = "0" + value;
			return value;
		};

	// Regexes and supporting functions are cached through closure
	return function (date, mask) {
		// Treat the first argument as a mask if it doesn't contain any numbers
		if (
			arguments.length == 1 &&
			(typeof date == "string" || date instanceof String) &&
			!/\d/.test(date)
		) {
			mask = date;
			date = undefined;
		}

		date = date ? new Date(date) : new Date();
		if (isNaN(date))
			throw "invalid date";

		var dF = dateFormat;
		mask   = String(dF.masks[mask] || mask || dF.masks["default"]);

		var	d = date.getDate(),
			D = date.getDay(),
			M = date.getMonth(),
			y = date.getFullYear(),
			H = date.getHours(),
			m = date.getMinutes(),
			s = date.getSeconds(),
			L = date.getMilliseconds(),
			o = date.getTimezoneOffset(),
			flags = {
				d:    d,
				dd:   pad(d),
				ddd:  dF.i18n.dayNames[D],
				dddd: dF.i18n.dayNames[D + 7],
				M:    M + 1,
				MM:   pad(M + 1),
				MMM:  dF.i18n.monthNames[M],
				MMMM: dF.i18n.monthNames[M + 12],
				yy:   String(y).slice(2),
				yyyy: y,
				h:    H % 12 || 12,
				hh:   pad(H % 12 || 12),
				H:    H,
				HH:   pad(H),
				m:    m,
				mm:   pad(m),
				s:    s,
				ss:   pad(s),
				l:    pad(L, 3),
				L:    pad(L > 99 ? Math.round(L / 10) : L),
				t:    H < 12 ? "a"  : "p",
				tt:   H < 12 ? "am" : "pm",
				T:    H < 12 ? "A"  : "P",
				TT:   H < 12 ? "AM" : "PM",
				Z:    (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
				o:    (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4)
			};

		return mask.replace(token, function ($0) {
			return ($0 in flags) ? flags[$0] : $0.slice(1, $0.length - 1);
		});
	};
}();

// Some common format strings
dateFormat.masks = {
	"default":       "ddd mmm d yyyy HH:MM:ss",
	shortDate:       "m/d/yy",
	mediumDate:      "mmm d, yyyy",
	longDate:        "mmmm d, yyyy",
	fullDate:        "dddd, mmmm d, yyyy",
	shortTime:       "h:MM TT",
	mediumTime:      "h:MM:ss TT",
	longTime:        "h:MM:ss TT Z",
	isoDate:         "yyyy-mm-dd",
	isoTime:         "HH:MM:ss",
	isoDateTime:     "yyyy-mm-dd'T'HH:MM:ss",
	isoFullDateTime: "yyyy-mm-dd'T'HH:MM:ss.lo"
};

// Internationalization strings
dateFormat.i18n = {
	dayNames: [
		"Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat",
		"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
	],
	monthNames: [
		"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
		"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
	]
};

// For convenience...
Date.prototype.format = function (mask) {
	return dateFormat(this, mask);
}
