
if(typeof(HTMLElement) != "undefined")  {
	
	if ( ! HTMLElement.prototype.insertAdjacentElement) {
		
		/**
		*	Inserts HTML-Code into this DOM-Element
		*	
		*	@param string sWhere, specifies the location where the code should be inserted
		*		Options: "beforebegin", "afterbegin", "beforeend", "afterend"
		*	@param string sHTML the HTML-CODE to insert
		*/
		HTMLElement.prototype.insertAdjacentHTML = function(sWhere, sHTML) {
			var df;   // : DocumentFragment
			var r = this.ownerDocument.createRange();

			switch (String(sWhere).toLowerCase()) {  // convert to string and unify case
			  case "beforebegin":
				 r.setStartBefore(this);
				 df = r.createContextualFragment(sHTML);
				 this.parentNode.insertBefore(df, this);
				 break;

			  case "afterbegin":
				 r.selectNodeContents(this);
				 r.collapse(true);
				 //r.collapse(false);
				 df = r.createContextualFragment(sHTML);
				 this.insertBefore(df, this.firstChild);
				 break;

			  case "beforeend":
				 r.selectNodeContents(this);
				 r.collapse(false);
				 df = r.createContextualFragment(sHTML);
				 this.appendChild(df);
				 break;

			  case "afterend":
				 r.setStartAfter(this);
				 df = r.createContextualFragment(sHTML);
				 this.parentNode.insertBefore(df, this.nextSibling);
				 break;
			}   
		};
	}
}


function safariInsertAdjacentHTML(obj, sWhere, sHTML){
	var df; // : DocumentFragment
	var r = obj.ownerDocument.createRange();
	switch (String(sWhere).toLowerCase()) { // convert to string and unify case
		case "beforebegin":
			r.setStartBefore(obj);
			df = r.createContextualFragment(sHTML);
			obj.parentNode.insertBefore(df, obj);
			break;

		case "afterbegin":
			r.selectNodeContents(obj);
			r.collapse(true);
			//r.collapse(false);
			df = r.createContextualFragment(sHTML);
			obj.insertBefore(df, obj.firstChild);
			break;

		case "beforeend":
			r.selectNodeContents(obj);
			r.collapse(false);
			df = r.createContextualFragment(sHTML);
			obj.appendChild(df);
			break;

		case "afterend":
			r.setStartAfter(obj);
			df = r.createContextualFragment(sHTML);
			obj.parentNode.insertBefore(df, obj.nextSibling);
			break;
	}
}

/**
*	Clones this Date-Object
*	@return Date the clonesd Date
*/
Date.prototype.clone = function () {
	var newDate = new Date(this.getTime());
	return newDate;
};

/**
*	Checks if 2 date-Objects represent the same day (NOT: the same time)
*	
*	@param Date date the Date Objcect to compare this Date Object with
*	@return boolean, if the represented day is the same
*/
Date.prototype.isSameDay = function (date) {
	return (this.getFullYear() == date.getFullYear() 
		&& this.getMonth() == date.getMonth() 
		&& this.getDate() == date.getDate());
};

/**
*	Creates an SQL-formatted String of this date (YYYY-MM-DD)
*	@return string, the SQL-formatted date-String 
*/
Date.prototype.toSQLDate = function() {
	var str = "";
	var t = this.getDate();
	var m = this.getMonth() + 1;
	if (t < 10) t = "0"+t.toString();
	if (m < 10) m = "0"+m.toString();
	var str = this.getFullYear()+"-"+m+"-"+t;
	return str;
};

/**
*	Creates a formatted time String of this date (hh:mm:ss)
*	@return string, the time string
*/
Date.prototype.toTime = function() {
	var h = this.getHours();
	var m = this.getMinutes();
	var s = this.getSeconds();		
	if (h < 10) h = "0" + h.toString();
	if (m < 10) m = "0" + m.toString();		
	if (s < 10) s = "0" + s.toString();
	return h+":"+m+":"+s;	
};

/**
*	Creates an SQL-formatted String of this date inclunding the time (YYYY-MM-DD hh:mm:ss)
*	@return string, the SQL-formatted datetime-String 
*/
Date.prototype.toSQLDateTime = function() {
	return this.toSQLDate()+" "+this.toTime();
};

/**
*	Creates an european-style-formatted String of this date (DD.MM.YYYY)
*	@return string, the european-style-formatted date-String 
*/
Date.prototype.toEuroDate = function() {
	var str = "";
	var t = this.getDate();
	var m = this.getMonth() + 1;
	if (t < 10) t = "0"+t.toString();
	if (m < 10) m = "0"+m.toString();
	var str = t+"."+m+"."+this.getFullYear();
	return str;
};

/**
*	Creates an european-style-formatted String of this date inclunding the time (DD.MM.YYYY hh:mm:ss)
*	@return string, the european-style-formatted date-String 
*/
Date.prototype.toEuroDateTime = function() {
	return this.toEuroDate()+" "+this.toTime();
};

/**
*	Calculates the weeknumber of this Date
*	@return int the week number
*
*	@from: http://www.codeproject.com/csharp/gregorianwknum.asp
*/
Date.prototype.getWeekNr = function() {
	var year = this.getFullYear();
	var month = this.getMonth() + 1;  //use 1-12
	var day = this.getDate();

	//lets calc weeknumber the cruel and hard way :D
	//Find JulianDay
	var a = Math.floor((14-(month))/12);
	var y = year+4800-a;
	var m = (month)+(12*a)-3;
	var jd = day + Math.floor(((153*m)+2)/5) +
		 (365*y) + Math.floor(y/4) - Math.floor(y/100) +
		 Math.floor(y/400) - 32045;      // (gregorian calendar)
	var d4 = (jd+31741-(jd%7))%146097%36524%1461;
	var L = Math.floor(d4/1460);
	var d1 = ((d4-L)%365)+L;
	NumberOfWeek = Math.floor(d1/7) + 1;
	return NumberOfWeek;
};

/**
*	Adds some days to this Date-Object
*	
*	@param int days, how many days to add, may be negative
*	@return the new Date-object with the added Days, this Date-Object stays the same!
*/
Date.prototype.addDays = function(days) {	
	return new Date(this.getTime() + (days * 24 * 3600 * 1000));
};

/**
*	Adds some months to this Date-Object
*
*	@param int months, how many months to add, may be negative
*	@return the new Date-object with the added months, this Date-Object stays the same!
*/
Date.prototype.addMonths = function(months) {	
	var newMonth = this.getMonth() + months;
	var newYear = this.getFullYear();
	var deltaYears = Math.floor(newMonth / 12);
	
	var newDate = new Date(this.getTime());
	newDate.setMonth(newMonth - (12 * deltaYears)); 
	newDate.setFullYear(newYear + deltaYears);
		// Da sonst das berechnete datum z.B: 30.02 sein kann was dann 2.03 wird => korrigieren auf 28.02
	if (newDate.getMonth() != newMonth - (12 * deltaYears)) newDate = newDate.addDays(- newDate.getDate());
	
	debug.print(this+" => "+newDate);
	
	return newDate;
}

Date.prototype.WEEK_LENGTH = 7;

/**
*	Creates the nearest Date to this Date-Object that has the given Week-Day
*	
*	@param int dayNr, which dayNr is demanded, from 0 (Sunday) to 6 (Saturday)
*	@param boolean backwards, OPTIONAL, default false, set it to true to go backwards (e.g. "find the LAST Sunday")
*	@return the newly created Date-Object, this Date-Object stays the same!
*/
Date.prototype.moveToDayNr = function(dayNr, backwards) {	
	var deltaDays = dayNr - this.getDay();
	if (backwards == true && deltaDays > 0) deltaDays = deltaDays - this.WEEK_LENGTH;
	if (backwards != true && deltaDays < 0) deltaDays = deltaDays + this.WEEK_LENGTH;
	return this.addDays(deltaDays);	
}

/**
*	Counts the number of days from this Date-object to the given one
*		- posiive it the given date is after his one
*		- negative if the given date is earlier than this one
*		- 0 if they are the same 
*	NOTE: "1 day" means a time difference between 12 and 36 hours!
*	
*	@param Date date, the other date
*	@return int the number from this to the given Date
*/
Date.prototype.countDaysUntil = function(date) {
	var millisUntil = date.getTime() - this.getTime();
	return Math.round(millisUntil / 1000 / 3600 / 24);
}



/**
*	Url-Encodes this String
*	@return the Url-encoded String, this String stays the same!
*/

// ====================================================================
//       URLEncode and URLDecode functions
//
// Copyright Albion Research Ltd. 2002
// http://www.albionresearch.com/
//
// You may copy these functions providing that 
// (a) you leave this copyright notice intact, and 
// (b) if you use these functions on a publicly accessible
//     web site you include a credit somewhere on the web site 
//     with a link back to http://www.albionresarch.com/
//
// If you find or fix any bugs, please let us know at albionresearch.com
//
// SpecialThanks to Neelesh Thakur for being the first to
// report a bug in URLDecode() - now fixed 2003-02-19.
// ====================================================================

String.prototype.UrlEncode = function()  {
	// The Javascript escape and unescape functions do not correspond
	// with what browsers actually do...
	var SAFECHARS = "0123456789" +					// Numeric
					"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +	// Alphabetic
					"abcdefghijklmnopqrstuvwxyz" +
					"-_.!~*'()";					// RFC2396 Mark characters
	var HEX = "0123456789ABCDEF";

	var encoded = "";
	for (var i = 0; i < this.length; i++ ) {
		var ch = this.charAt(i);
	    if (ch == " ") {
		    encoded += "+";				// x-www-urlencoded, rather than %20
		} 
		else if (SAFECHARS.indexOf(ch) != -1) {
		    encoded += ch;
		} 
		else {
		    var charCode = ch.charCodeAt(0);
			if (charCode > 255) {
			    alert( "Unicode Character '" 
                        + ch 
                        + "' cannot be encoded using standard URL encoding.\n" +
				          "(URL encoding only supports 8-bit characters.)\n" +
						  "A space (+) will be substituted." );
				encoded += "+";
			} 
			else {
				encoded += "%";
				encoded += HEX.charAt((charCode >> 4) & 0xF);
				encoded += HEX.charAt(charCode & 0xF);
			}
		}
	} 

	return encoded;
};

/**
*	Simple String Extension functions
*	Hopefully not Comments needed since you use your common-sense ;-)
*/
String.prototype.nl2br = function()  {
	return this.replace(/\n/g, "<br>");
};
String.prototype.trim = function() {
	return this.replace(/^\s+|\s+$/g,"");
};
String.prototype.ltrim = function() {
	return this.replace(/^\s+/,"");
};
String.prototype.rtrim = function() {
	return this.replace(/\s+$/,"");
};
String.prototype.startsWith = function(s) { 
	return (this.indexOf(s) == 0); 
};
String.prototype.endsWith = function(s) { 
	return (this.lastIndexOf(s) == this.length - s.length) && (this.length > s.length); 
};

/**
*	Checks if this String is conteined in the given Array
*
*	@param array arr, the array to search
*	@return boolean if this stting is contained in the array
*/
String.prototype.containedIn = function(arr) {	
	return arr.contains(this);
};

/**
*	Used to determine if an JS-Object is actually a numeric array
*/
Array.prototype.$typeName = "array";

/**
*	Checks if this String is conteined in the given Array
*
*	@param array arr, the array to search
*	@return boolean if this stting is contained in the array
*/
Array.prototype.contains = function(item) {	
	var found = false;
	for (var n = 0; (n < this.length && found == false); n++) {
		if (this[n] == item) found = true;
	}
	return found;
};


//--------------------------------------------------
//tagetObj either objPointer or ID , position = "beforeBegin":"afterBegin":"beforeEnd":"afterEnd"
//--------------------------------------------------
// windows.location.href

/**
*	Loads a HTML-File (via HTTP-GET) into the given DOM-Object
*
*	@param string url, the url to load the file from
*	@param mixed targetObj where to insert the loaded HTML-String, may be a DOM-Object or an Id of a DOM-Object
*	@param string position, OPTIONAL where top place the HTML if the targetObj is not empty
			"beforebegin", "afterbegin", "beforeend", "afterend"
*/
function importHTML(url, targetObj, position){
	var html = syncGetFile(url);
	if(typeof(targetObj)!="object")
		targetObj = document.getElementById(targetObj);
	targetObj.insertAdjacentHTML(position, html);
}

//--------------------------------------------------

var IMPORTED_SCRIPTS = new Array();   	/* kaegi, um doppelte und zirkuläre import zu verhindern, 23.08.2005 */
var IMPORTED_CSS = {};   		/* kaegi, um doppelte und zirkuläre import zu verhindern, 23.08.2005 */

var SCRIPT_LOADED = {};
var LOADING_SCRIPTS = 0;   	

var TIME_OUT = 15000;

//--------------------------------------------------

/**
*	Imports the given CSS-File, works asynchron, creates a "<link rel='stylsheet'..."-Tag in the HTML-Head
*
*	@param string url, the url of the CSS-File
*	
*/
function importCSS(url) {
	if (IMPORTED_CSS[url] != true) {
		IMPORTED_CSS[url] = true;
		
		var styleTag = document.createElement('link');
		styleTag.setAttribute('rel', 'stylesheet');
		styleTag.setAttribute('href', url);
		styleTag.setAttribute('type', 'text/css');
		var htmlHead = document.getElementsByTagName('head').item(0);
		htmlHead.appendChild(styleTag);		
		htmlHead.appendChild(document.createTextNode("\n   "));		
	}
}


/**
*	Imports the given JS-File, works asynchron, creates a "<script..."-Tag in the HTML-Head
*
*	@param string url, the url of the JS-File
*	@param function onLoadFunc, OPTIONAL, if given this function will be called when the Scriptfile is completely loaded
*	
*	NOTES: 	- If a Script is already loaded it won't be loaded twice, but if given, the onLoadFunction will be called 
*		  	immediately.
*		- the global Variable TIME_OUT defines a Timeout 
*/
function importJS(url, onLoadFunc){
	if (IMPORTED_SCRIPTS[url] != true) {
	
		IMPORTED_SCRIPTS[url] = true;
		LOADING_SCRIPTS++;		

		var js = document.createElement('script');
		js.setAttribute('language', 'javascript');
		js.setAttribute('type', 'text/javascript');
		js.setAttribute('src', url);
		
		timer.setTimer(TIME_OUT, undefined, checkTimeOut, url);
		var browser = std.getBrowser();
		
		if (browser == std.NS || browser == std.SAFARI || browser == std.OPERA) {	// Für Mozilla
			js.onload = function() {
				debug.print("Loaded: "+url+" Still Loading: "+(LOADING_SCRIPTS - 1));
				LOADING_SCRIPTS--;
				SCRIPT_LOADED[url] = true;	
			}
		}
		
		if (browser == std.IE) { 	// Für IE			
			js.onreadystatechange = function() {
				LOADING_SCRIPTS--;
				SCRIPT_LOADED[url] = true;		
			}
		}
		
		var htmlHead = document.getElementsByTagName('head').item(0);
		htmlHead.appendChild(js);		
		htmlHead.appendChild(document.createTextNode("\n   "));		
	}

	/**
	*	Onload Funktion immer ausführen, auch wenn script schon mal importiert wurde!
	*/
	if (typeof(onLoadFunc) == "function") {
		executeWhenLoaded({'url':url, 'onLoadFunc':onLoadFunc});
	}
}

/**
*	To Execute the onLoadFunction when a Script is loaded 
*	@see importJS
*/
function executeWhenLoaded(param) {
	var url = param['url'];
	var onLoadFunc = param['onLoadFunc'];

	if (SCRIPT_LOADED[url] == true) {
		onLoadFunc();
	}
	else {
		timer.setTimer(50, undefined, executeWhenLoaded, {'url':url, 'onLoadFunc':onLoadFunc});
	}
}

/**
*	Checks if the TimeOut is reached 
*	@see importJS
*/
function checkTimeOut(url) {
	if (! (SCRIPT_LOADED[url] == true)) {
		var retry = confirm("Achtung!\n\nSkriptfile: \""+url+"\" nicht gefunden!\nTimeout: "+TIME_OUT+" ms\n\nRetry?");
		if (retry == true) {
			timer.setTimer(TIME_OUT, undefined, checkTimeOut, url);
		}
		else {
			LOADING_SCRIPTS--;		
		}		
	}
}

/**
*	Checks if there are still Javasriptfils loading
*	@return boolean, if Scripts are loading
*/
function isScriptLoading() {
	return (LOADING_SCRIPTS > 0);
}

//--------------------------------------------------
/**
*	Same as importJS but without Control if a Script is already loaded
*		and without onloadfunc and withou timout
*	DO NOT USE THIS FUNCTION ANYMORE, DEPRECATED.
*/
function includeJS(url){ // funktioniert async, dh, der neue Code ist mit etwas verzögerung parat
	var script = document.createElement('script');
	script.type = 'text/javascript';
	script.src = 'url';
	document.getElementsByTagName('head')[0].appendChild(script);
}
//--------------------------------------------------

/**
*	???
*	Who wrote this function??
*/
function changeClassProperty(classname, prop, val) {
	var rules,docstyle=document.styleSheets.item(0);
	if(docstyle.rules)rules=docstyle.rules;
	if(docstyle.cssRules)rules=docstyle.cssRules;
	var rl=rules.length;

	for(var i=0;i<rl;i++) {
		if(rules.item(i).selectorText=="."+classname)rules.item(i).style[prop]=	val;
	}
}

/**
*	Reads a file via HTTP-GET, works synchrone
*	
*	@param string url, the url to read from
*	@return string the loaded String
*/
function syncGetFile(url) {
	//alert(url);
	var xmlhttp = XMLHttpRequest_init();
	xmlhttp.open("GET", url, false);
	xmlhttp.setRequestHeader('Cache-Control', 'no-cache');
	xmlhttp.send(null);
	// alert(xmlhttp.responseText);
	var result = "";
	if (xmlhttp.status == 200) {
		result = xmlhttp.responseText;
	}
	else {
		alert("HTTP-Fehler!\n"+url+"\nFehlerCode: "+xmlhttp.status+"\n"+xmlhttp.statusText);
	}
	return xmlhttp.responseText;

	//--------------------------------------------------
	function XMLHttpRequest_init() {
		var A = null;
		var success = false;
		var MS_PROGIDS = ['MSXML2.XMLHTTP.5.0','MSXML2.XMLHTTP.4.0','MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'];
		for (var i=0;i < MS_PROGIDS.length && !success; i++) {
			try {
				A = new ActiveXObject(MS_PROGIDS[i]);
				success = true;
			} 
			catch (e) { 
				A=null;
			}
		}
		if(!A && typeof XMLHttpRequest != "undefined")
				A = new XMLHttpRequest();
		if (!A)
				alert("Could not create connection object.");
		return A;
	}
}

function debug() {
	
	this.subtitle = subtitle;
	this.getValue = getValue;
	this.getAlertString = getAlertString;
	this.doAlert = doAlert;
	
	this.print = print;
	this.getConsoleString = getConsoleString;
	
	this.show = show;
	this.get = get;
	this.decorateValue = decorateValue;
	this.isOneDimensional = isOneDimensional;
	this.forceHashtable = forceHashtable;
	
	/**
	*	Creates a subtitle for getAlertString
	*	
	*	@param string title, the title
	*	@param string item, th subtitle
	*	@returns string the created subtitle using the Brackets "[" and "]"
	*/
	function subtitle(title, item) {
		if (title == "") return item;
		return title+"["+item+"]";
	}
	
	/**	
	*	Returns a Value and its type information for getAlertString
	*	
	*	@param mixed value, the value to inspect
	*	@return string the values String-representation followed by its Type
	*/
	function getValue(value) {
		return value+" ("+typeof(value)+")";
	}
	
	/**
	*	Creates a human readable String representation of a (optionally complex) Value
	*
	*	@param mixed value, the value to create a String representation from
	*	@param string title, the title for this Representation
	*	@param boolean recurse, OPTIONAL, if the function schoul work recursively
	*	@param boolean notFirst, OPTIONAL, if we are in the TopLevel or not
	*
	*	@return string a good String Representation to use in an Alertbox or any other Plaintext viewer
	*/
	function getAlertString(value, title, recurse, notFirst) {
		if(recurse == undefined) recurse = true;
		var str = "";
		if (typeof(value) == "object") {
			if(recurse || !notFirst) {
				var len = 0;
				for (var n in value) {
					len++;
					str+= this.getAlertString(value[n], this.subtitle(title, n), recurse, true);
				}
				try {
					if (len == 0 && typeof(value.length) == "number") {
						for (var m = 0; m < value.length; m++) {
							str+= this.getAlertString(value[m], this.subtitle(title, m), recurse, true);
							len++;
						}
					}
				}
				catch (e) {		}
				if (len == 0) 	str+= title+" = [empty-array]\n";
			} else {
				str += title+" !!too much recursion!!\n";
			}
		}
		else {
			str+= title+" = "+this.getValue(value)+"\n";
		}
		return str;
	}

	/**
	*	Alerts the Stringrepresentation of a value
	*	
	*	@param mixed value, the value to create a String representation from
	*	@param string title, the title for this Representation
	*	@param boolean recurse, OPTIONAL, if the function schould work recursively
	*
	*	@uses getAlertString
	*/
	function doAlert(value, title, recurse) {
		alert(this.getAlertString(value, title, recurse, false));
	}

	/********************************************************
		analog zu PHP debug::show() / debug::get()
	********************************************************/


	this.keyColor = "#AAFFAA";
	this.valueColor = "#FFAAAA";
	this.titleColor = "#CCCCCC";  
	this.gridColor = "#AAAAFF";  


	/**
	*	Same as debug.get, but shows the created HTML-Code directly in a HTML-Window
	*
	*	@param mixed data: the PHP-Varible to look in
	*	@param string start: a title for the created structure-table
	*/
	function show(data, start) {
		var str = this.get(data, start);
		var win = window.open("about:blank", "DebugFenster", "top=100,left=100,width=1000,heigth=800,dependent=yes,resizable=yes,scrollbars=yes");
		win.document.write(str);
		win.document.close();
	}
	
	/**
	*	Craetes and returns a HTML-Code that shows nicely
	*	the Structure and Value(s) of any PHP-Varible, the given Value can be from a simple Integer
	*	to a complex object-structure. This function works recursively.
	*
	*	@param mixed data : the PHP-Varible to look in
	*	@param string start: a title for the created structure-table
	*
	*	@returns a HTML-Code Snippet (e.g. to be Viewed in a Browser)
	*/
	function get(data, start) {
		var result = "";
		var name = "";
		if (typeof(start) == "string") {
			name = start;
			start = true;
		}
		if (typeof(data) == "object" && data != null) {
			var ht = this.forceHashtable(data);
			if (this.isOneDimensional(ht) && name == "") {
				for (key in ht) {
					result+= "<span style='background-color:"+this.keyColor+"'>"+this.decorateValue(key)+"</span>";
					result+= "<span style='background-color:"+this.valueColor+"'>"+this.decorateValue(ht[key])+"</span>";
				}
				if (result == "") result = "[empty-array]";
			}
			else {
				result = "<table style='background-color:"+this.gridColor+"; font-family:arial; vertical-align:top'>\n";
				if (name != "") {
					result+= "   <tr><th colspan='2' style='background-color:"+this.titleColor+"'>"+name+"<th></tr>\n";
				}
				var cnt = 0;
				for (key in ht) {
					result+= "   <tr>\n      <td style='background-color:"+this.keyColor+"'>"+this.decorateValue(key)+"</td>\n";
					result+= "       <td style='background-color:"+this.valueColor+"'>"+this.get(ht[key])+"</td>\n   </tr>\n";
					cnt++;
				}
				if (cnt == 0) result+= "   <tr><th colspan='2' style='background-color:"+this.valueColor+"'>[empty-array]<th></tr>\n";
				result+= "</table>\n";		
			}
		}	
		else {
			value = this.decorateValue(data);
			if (name == "") result = value;
			else result = name+" = "+value;
		}	
		return result;
	}
	
	
	/**
	*	Prepares Values to be used in debug::show / debug::get used to indicate a values type
	*	- Strings will be 
	*		- in double-qutes if they are empty (to see something)
	*		- Normal if not empty
	*		- < and > will be rplaced by "&lt;", "&gt;" to avoid tag-Interpretation by a Browser
	*	- booleans and all numbers will be bold.
	*	- the NULL-Value and UNDEFINED will be bold and italic
	*
	*	@param mixed value: the Value to HMTL-Encode
	*	@returns the HTML-Encoded Value
	*/
	function decorateValue(value) {
		var t = typeof(value);
		
		if (t == "string") {
			decValue = value;
		}
		if (t == "boolean") {
			if (value == true) decValue = "true";
			else decValue = "false";
			decValue = "<b>"+decValue+"</b>";
		}
		if (t == "number") {
			decValue = "<b>"+value+"</b>";
		}
		if (value === undefined) {
			decValue = "<b><i>undefined</i></b>";
		}
		if (value === null) {
			decValue = "<b><i>null</i></b>";
		}

		return decValue;
	}

	/**
	*	Checks if an array is one-dimensional, i.e. if no one of the values is an array or abject again
	*
	*	@param array ht: the array to check
	*
	*	@return boolean if it is one-dimensional
	*/
	function isOneDimensional(ht) {
		if (typeof(ht) != "object") return false;
		for (i in ht) {
			if (typeof(ht[i]) == "object" && ht[i] != null) return false;
		}
		return true;
	}

	/**
	*	converts a numeric array into a "Hashtable" i.e. an JS-Object
	*
	*	@param array anyArray, the aray to convert
	*	@return JS-Object the transformed array
	*/
	function forceHashtable(anyArray) {
		var ht = {};
		var len = 0;
		for (var n in anyArray) {
			len++;
			ht[n] = anyArray[n];  
		}
		try {
			if (len == 0 && typeof(anyArray.length) == "number") {
				for (var m = 0; m < anyArray.length; m++) {
					ht[m] = anyArray[m];			
				}
			}
		}
		catch (e) {		}
		return ht;	
	}

	/**
	*	Creates a String-Representation from an Object or an array
	*	
	*	@param mixed data, the data to rebuild
	*	@param string start the title for the whole thing
	*	
	*	@return the created String representation
	*/
	function getConsoleString(data, start) {
		/**
		*	START FRICKEL (Weitermachen falls das Teil keine Funktion oder DOM-Objekt (Ausnahme: Event) ist.
		*    ======================================================================================================
		*/
		var showOutput = true;
		
		if (data == undefined) showOutput = false;
		if (showOutput == true) {
			var strValue = data.toString();
			if (typeof(data) == "function") showOutput = false;		// Keine Funktionen ausgeben
			if (strValue.startsWith("[object")) {				// KÃ¶nnete DOM-Objekt sein
				showOutput = false;
				if (strValue == "[object Object]") showOutput = true;	// Ist eine eigenes Objekt
				if (strValue.endsWith("Event]")) showOutput = true;	// Ist ein Event
			}
		}
		/**
		*	END FRICKEL
		*    =================
		*/
		

		var result = "";
		if (showOutput == true) {
	
			var name = "";
			if (typeof(start) == "string") {
				name = start;
				start = true;
			}
			if (typeof(data) == "object" && data != null) {
				if (data.tagName == undefined) {

					var ht = this.forceHashtable(data);
					if (this.isOneDimensional(ht) && name == "") {
						for (key in ht) {
							result+= key+":"+ht[key]+", ";
						}
						if (result == "") result = "[empty-array]";
						else result = result.substring(result.lenght - 2);
					}
					else {
						result = "";
						if (name != "") {
							result = "   "+name+"   \n";
							for (var n = 0; n < name.length + 6; n++) {
								result+= "=";
							}
							result+= "\n";
						}
						var cnt = 0;
						for (key in ht) {
							result+= key+":"+debug.getConsoleString(ht[key])+"\n";
							cnt++;
						}
						if (cnt == 0) result+= "   [empty-array]\n";
						result+= "\n";		
					}
				}
			}	
			else {
				if (name == "") result = data;
				else result = name+" = "+data;
			}	
		}
		return result;
	}	
	
	/**
	*	Prints the String representation of an aobject / array to the console (if available)
	*	
	*	@param mixed str, the value to print
	*	@param string name, the title for the value
	*	@uses getConsoleString
	*/
	function print(str, name) {
		var logStr = debug.getConsoleString(str, name);
		try {
			console.log(logStr);
		}
		catch (e) {
		}
	}
}


var debug = new debug();

function std() {

	this.absoluteLeft = absoluteLeft;
	this.absoluteTop = absoluteTop;
	
	this.tableGroup = tableGroup;
	this.tableSort = tableSort;
	this.selectorCase2camelCase = selectorCase2camelCase;
	
	this.sqlDate2euroDate = sqlDate2euroDate;
	this.sqlDateTime2euroDateTime = sqlDateTime2euroDateTime;	
	this.euroDate2sqlDate = euroDate2sqlDate;
	
	this.number_format = number_format; // wie PHP-Funktion
	this.array_keys = array_keys;       // wie PHP-Funktion
	this.in_array = in_array;           // wie PHP-Funktion, aber ohne Argument strict
	this.count = count;                 // wie PHP-Funktion (zählt Elemente eines Arrays)
	
	this.addLeadingZeros = addLeadingZeros;
	
	this.getElementById = getElementById;
	this.getChildNodes = getChildNodes;
	
	this.toClipboard = toClipboard;
	this.disableSelection = disableSelection;
	this.enableSelection = enableSelection;
	this.showHtmlInWindow = showHtmlInWindow;
	this.printHTML = printHTML;

	this.getTheIframe = getTheIframe;
	
	this.uploadFile = uploadFile;
	this.getUploadedFiles = getUploadedFiles;
		
	this.showDivOverBody = showDivOverBody;

	this.showWaitCursor = showWaitCursor;
	this.removeWaitCursor = removeWaitCursor;
	
	this.openWindow = openWindow;
	this.getType = getType;
	
	this.noBubbling = noBubbling;
	this.getBrowser = getBrowser;
	this.isTableElement = isTableElement;
	this.setInnerHTML = setInnerHTML;
	
	this.NS = 1;
	this.IE = 2;
	this.SAFARI = 3;
	this.OPERA = 4;
	
	this.debugMode = false;


	/**
	*	Determins the Type of an object
	*	we liked the way mootool did it, but in our case it is extremely slow so, we used a very short way...
	*	
	*	@returns the type of the obj.
	*
	*/
	function getType(object) {
		var type = typeof(object);
		if (object === null) type = "null";
		if (type == "object") {
			if (object.$typeName != undefined) type = object.$typeName;
		}
		return type;
	}
	
	/**
	*	Detrmines the Browser
	*
	*	@returns a code for the Browser
	*	
	*	Note:	"knows" only IE, Safari and Netscape (Mozilla Firefox etc..) until now, to be extended..
	*/
	function getBrowser() {
		var browser = "";
		if (window.clipboardData) browser = this.IE;
		if (window.netscape) browser = this.NS;
		if (navigator.userAgent.indexOf('Safari') >= 0) browser = this.SAFARI;
		if (navigator.appName == "Opera") browser = this.OPERA;
				
		return browser;
	}
	
	/**
	*	Sets the inner HTML value of am element, the Prperty [element].innerHTML is not Browsersafe 
	*	this function is. 
	*
	*	@param DOM-Object targetObj, the element where the innerHTML is to be set
	*	@param string string, the string tu set as innerHTML
	*	@param string where, OPTIONAL, undefined by default, existing content of targeObj will be replaced
	*			- "afterbegin" => inserts the HTML-String before existing elements
	*			- "beforeend" => inserts the HTML-String after existing elements
	*/
	function setInnerHTML(targetObj, string, where) {
		var browserType = std.getBrowser();
		
		if (browserType == std.IE && this.isTableElement(targetObj)) {
			var tag = targetObj.tagName.toLowerCase();
			
			var childCount = targetObj.childNodes.length;
			//alert(childCount);
			if (where == undefined) {
				for (var n = childCount - 1; n >= 0; n--) {
					targetObj.removeChild(targetObj.childNodes[n]);
				}
			}
			
			var div = document.createElement("DIV");
			if (tag == 'table') string = "<table>"+string+"</table>";
			if (tag == 'thead') string = "<table><thead>"+string+"</thead></table>";
			if (tag == 'tbody') string = "<table><tbody>"+string+"</tbody></table>"; 
			if (tag == 'tfoot') string = "<table><tfoot>"+string+"</tfoot></table>";
			if (tag == 'tr') string = "<table><tbody><tr>"+string+"</tr></tbody><table>";
			
			div.innerHTML = string;
			var element = div.firstChild;
			if (tag != 'table') element = element.firstChild;
			if (tag == 'tr') element = element.firstChild;

			childCount = element.childNodes.length;
			
			
			//alert(childCount+"\n"+element.tagName+"\n\n"+element.innerHTML);
			if (where == "afterbegin") {
				for (var n = childCount - 1; n >= 0; n--) {
					targetObj.insertBefore(element.childNodes[n], targetObj.firstChild);

				}
			}
			else {
				for (var n = 0; n < childCount; n++) {
					var index = n;
					if (browserType == std.IE) index = 0;
					targetObj.appendChild(element.childNodes[index]);
				}
			}
		}
		
		else if (browserType == std.IE && targetObj.tagName.toLowerCase() == "select") {
			targetObj.outerHTML = "<select>"+string+"</select>";
		}
		
		else if (browserType == std.SAFARI) {
			if (where == undefined) {
				targetObj.innerHTML = string;
			}
			else {
				safariInsertAdjacentHTML(targetObj, where, string);
			}
		}
		
		else {
			if (where == undefined) {
				targetObj.innerHTML = string;
			}
			else {
				targetObj.insertAdjacentHTML(where, string);
			}
		}
	}

	/**
	*	Checks if a DOM-Object is an element of a Table
	*	Needed for setInnerHTML, IE cant set innerHTML into table elements
	*
	*	@param DOM-Object object, the object to check
	*	@return boolean, if it is a table Element
	*/
	function isTableElement(object) {
		var result = false;
		var tn = object.tagName.toLowerCase();
		if (tn == "table" || tn == "thead" || tn == "tbody" || tn == "tfoot" || tn == "tr") result = true;
		return result;
	}

	/**
	*	Returns the absloute left position of a DOM-Object
	*
	*	@param DOM-Object obj, the object form which the absolute Left should be calculated
	*	@return int the absolute left
	*/
	function absoluteLeft(obj) {
		return (obj.offsetParent)? obj.offsetLeft+this.absoluteLeft(obj.offsetParent) : obj.offsetLeft;
	}

	function absoluteTop(obj) {
		return (obj.offsetParent)? obj.offsetTop+this.absoluteTop(obj.offsetParent) : obj.offsetTop;
	}

	function selectorCase2camelCase(str) { 		// converts to camelCase
	  	str = str.split('-');
	  	var outstr = str[0];
	  	for(var i = 1; i < str.length; i++) {
	   		outstr = outstr + str[i].charAt(0).toUpperCase() + str[i].substring(1);
	  	}
		return outstr;
	}

	function sqlDate2euroDate(sqldate) {
		if (typeof(sqldate) == "string") {
			var arr = sqldate.substr(0,10).split("-");
			arr.reverse();
			return arr.join(".");
		}
		return "";
	}

	function sqlDateTime2euroDateTime(sqldate, inclSecs) {
		if (typeof(sqldate) == "string") {
			var arr = sqldate.substr(0,10).split("-");
			time = sqldate.substr(11,5);
			if (inclSecs == true) time = sqldate.substr(11,8);
			arr.reverse();
			return arr.join(".")+" "+time ;
		}
		return "";
	}
	
	function euroDate2sqlDate(eurodate) {
		if (typeof(eurodate) == "string") {
			var arr = eurodate.substr(0,10).split(".");
			if(arr[0].length == 1) arr[0] = "0"+arr[0];
			if(arr[1].length == 1) arr[1] = "0"+arr[1];
			if(arr[2].length == 2) arr[2] = "20"+arr[2];
			arr.reverse();
			return arr.join("-");
		}
		return "";
	}
	
	function tableGroup(data, criteria) {
		groupedArr = {};
	
		if (std.getType(data) == "array") {
			for (var idx = 0; idx < data.length; idx++) {
				if (typeof(groupedArr[data[idx][criteria]]) == "undefined") groupedArr[data[idx][criteria]] = {};
				groupedArr[data[idx][criteria]][idx] = data[idx];			
			}
		}
		else {
			for (idx in data) {
				if (typeof(groupedArr[data[idx][criteria]]) == "undefined") groupedArr[data[idx][criteria]] = {};
				groupedArr[data[idx][criteria]][idx] = data[idx];			
			}
		}
		return groupedArr;
	}
	
	function ascCompare(a, b) {
		var retval = 0;
		if (a > b) retval = 1;
		if (a < b) retval = -1;
		return retval;
	}
	
	function numberCompare(a, b) {
		return a - b;
	}
	
	function tableSort(data, col, numeric, holdIndices) {		
		var result = [];
		if (holdIndices === true) result = {};
		
		var colValue = [];
		if (std.getType(data) == "array") {
			for (var i = 0; i < data.length; i++) {
				colValue[colValue.length] = data[i][col];
			}
		}
		else {
			for (i in data) {
				colValue[colValue.length] = data[i][col];
			}
		}
		var groupedData = this.tableGroup(data, col);
		
		if (numeric == true) colValue.sort(numberCompare);
		else colValue.sort();
		
		for (var n = 0; n < colValue.length; n++) {
			for (i in groupedData[colValue[n]]) {
				if (holdIndices === true) {
					result[i] = groupedData[colValue[n]][i];
				}
				else {
					result[result.length] = groupedData[colValue[n]][i];				
				}
			}	
			groupedData[colValue[n]] = {};  // damit sich nicht eindeutige Werte in "col" nicht vervielfachen im resulat, schÃ¶ner wÃ¤re colValue.unique();
		}	
		return result;
		
	}
	
	
	/*******
	 * verhält sich gleich wie entsprechende PHP-Funktion
	 * gefunden auf www.fobit.com, genaueres unter:
	 * http://www.fobit.com/index.php?article=JavaScript%3A%20number_format
	 ***/
	function number_format (number, decimals, dec_point, thousands_sep) {
		var formatted = ""
		if (number != undefined && ! isNaN(number)) {
			var exponent = "";
			numberstr = number.toString ();
			var eindex = numberstr.indexOf ("e");
			if (eindex > -1) {
				    exponent = numberstr.substring (eindex);
				    number = parseFloat (numberstr.substring (0, eindex));
			}

			if (decimals != null) {
				    var temp = Math.pow (10, decimals);
				    number = Math.round (number * temp) / temp;
			}
			var sign = number < 0 ? "-" : "";
			var integer = (number > 0 ? 
			      Math.floor (number) : Math.abs (Math.ceil (number))).toString ();

			var fractional = number.toString ().substring (integer.length + sign.length);
			dec_point = dec_point != null ? dec_point : ".";
			fractional = decimals != null && decimals > 0 || fractional.length > 1 ? 
				       (dec_point + fractional.substring (1)) : "";
			if (decimals != null && decimals > 0) {
			    for (i = fractional.length - 1, z = decimals; i < z; ++i)
			      fractional += "0";
			}

			thousands_sep = (thousands_sep != dec_point || fractional.length == 0) ? 
					  thousands_sep : null;
			if (thousands_sep != null && thousands_sep != "") {
				for (i = integer.length - 3; i > 0; i -= 3)
					integer = integer.substring (0 , i) + thousands_sep + integer.substring (i);
			}
			formatted = sign + integer + fractional + exponent;
		}

		return formatted;
	}
	
	function addLeadingZeros(number, desiredDigits, base) {
		if (base == undefined) base = 10;
		
		var isNegative = false;
		if (number < 0) {	
			number = -number;
			isNegative = true;
		}
		
		var result = number.toString(base);
		for (var n = desiredDigits - 1; n > 0; n--) {
			if (number < Math.pow(base, n)) result = "0"+result;
		}
		if (isNegative == true) result = "-"+result;

		return result;
	}
	
	// wie PHP-Funktion
	function array_keys(arr) {
		var keyArr = [];
		for(n in arr) {
			keyArr.push(n);
		}
		return keyArr;
	}
	
	// wie PHP-Funktion, aber ohne Argument strict
	function in_array(value, arr) {
		for(n in arr) {
			if(arr[n] == value) return true;
		}
	}
	
	// wie PHP-Funktion
	function count(arr) {
		var counter = 0;
		for(n in arr) {
			counter++;
		}
		return counter;
	}
	
	/**
	*	To use the clipboard from Mozilla / NS / Firefox:
	*	
	*	In "about:config" : 
	*		set signed.applets.codebase_principal_support = true!
	*/

	function toClipboard(text) {
		var success = false;
		if (window.clipboardData)    {
			   // the IE-manier
			window.clipboardData.setData("Text", text);
			success = true;
		}
		else if (window.netscape)  {  
			netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');

			var clip = Components.classes['@mozilla.org/widget/clipboard;1'].getService(Components.interfaces.nsIClipboard);
			var trans = Components.classes['@mozilla.org/widget/transferable;1'].createInstance(Components.interfaces.nsITransferable);
			
			if(typeof(clip) == "object" && typeof(trans) == "object") {
				trans.addDataFlavor('text/unicode');

				var stingSupporter = Components.classes["@mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString);

				stingSupporter.data = text;
				trans.setTransferData("text/unicode", stingSupporter, text.length * 2);
				var clipid = Components.interfaces.nsIClipboard;
				clip.setData(trans, null, clipid.kGlobalClipboard);

				success = true;
			}
		}
		return success;
	}
	
	
	function getElementById(parent, id) {
		var ELEMENT_NODE_TYPE = 1; 
		
		var result = null;
		var childs = parent.childNodes;
				
		for (var n = 0; n < childs.length && result == null; n++) {
			if (childs[n].nodeType == ELEMENT_NODE_TYPE) {
				var idNode = childs[n].getAttributeNode("id");
				if (idNode != undefined && idNode.nodeValue == id) result = childs[n];

				if (result == null && childs[n].hasChildNodes()) result = this.getElementById(childs[n], id);
			}
		}
		return result;
	}
	
	/**
	*	Ermittelt alle "echten" Childnodes (noteType == ELEMENT_NODE_TYPE)
	*
	*/
	function getChildNodes(parent) {	
		var ELEMENT_NODE_TYPE = 1; 

		var chNodes = [];
		var childs = parent.childNodes;
		for (var n = 0; n < childs.length; n++) {
			if (childs[n].nodeType == ELEMENT_NODE_TYPE) {
				chNodes[chNodes.length] = childs[n];
			}
		}
		return chNodes;
	}

	function disableSelection(target){
		if (typeof target.onselectstart!="undefined") //IE route
			target.onselectstart=function() { return false; }
		
		else if (typeof target.style.MozUserSelect != "undefined") //Firefox route
			target.style.MozUserSelect = "none";
		
		else 		//All other route (ie: Opera)
			target.onmousedown = function()  { return false; }
	}
	
	function enableSelection(target) {
		if (typeof(target.onselectstart) != "undefined") { //IE route
			target.onselectstart = function() { };
		}
		
		else if (typeof(target.style.MozUserSelect) != "undefined") { //Firefox route
			target.style.MozUserSelect = "";
		}
		
		else 	{	//All other route (ie: Opera)
			target.onmousedown = false;
		}	
	} 	


	function showHtmlInWindow(body, title) {
		if (title == undefined) title = "";
		var html = "<html>\n<head>\n<title>" + title + "</title>\n</head>\n\n<body>\n" + body + "\n</body>\n</html>";

		//var html = "<html>\n<head>\n\n</head>\n\n<body>\n" + body + "\n</body>\n</html>";
		
		var win = window.open('', "");
		win.document.write(html);
		win.document.close();
		return win;
	}
	
	this.theIframeIndex = undefined;
	
	function getTheIframe() {
		if (this.theIframeIndex == undefined) {
			iFrame = document.createElement('iframe');		
			iFrame.style.border = "none";
			iFrame.setAttribute("width", "0px");
			iFrame.setAttribute("height", "0px");
			document.body.appendChild(iFrame);
			
			this.theIframeIndex = parent.frames.length - 1
		}
		return parent.frames[this.theIframeIndex];
	}
	
	function printHTML(body, title) {
		if (this.debugMode == true) {
			this.showHtmlInWindow(body, title);
		}
		else {
			if (title == undefined) title = "";
			var html = "<html>\n<head>\n<title>" + title + "</title>\n</head>\n\n<body>\n" + body + "\n</body>\n</html>";

			var iFrame = this.getTheIframe();
			iFrame.document.write(html);
			iFrame.document.close();
			iFrame.print();	
		}
	}
	
	this.PHP_FILE_RECEIVER = "file_receiver.php"

	function uploadFile(fileInputElement, path) {
		var inputCode = "<input type='hidden' name='path' value='"+path+"'>";
		var formCode = "<form id='upload_form' method='post' enctype='multipart/form-data' action='"+this.PHP_FILE_RECEIVER+"'>"+inputCode+"</form>";
		var html = "<html>\n<head>\n<title>Uploader</title>\n</head>\n\n<body>\n" + formCode + "\n</body>\n</html>";

		var iFrame = this.getTheIframe();
		iFrame.document.write(html);
		
		var theForm = iFrame.document.getElementById('upload_form');
		theForm.appendChild(fileInputElement.cloneNode(true));
		theForm.submit();
	}
	
	function getUploadedFiles() {
		var uploadedFiles = false;
		try {
			var iFrame = this.getTheIframe();
			var code = iFrame.document.body.innerHTML;
			var uploadedFiles = eval(code);
		}
		catch (e) {
			uploadedFiles = false;
		}
		return uploadedFiles;
	}
	
	function alertUploaded() {
		alert("alertUploaded");
	}

	/**
	*	opacity: 
	*		- NS:0 - 1
	*		- IE: 0 - 100 (Der Funktion Ã¼bergeben: 0 - 1)
	*/
	this.waitingDiv;

	function showDivOverBody(opacity, color, cursorOnDiv) {
		if (opacity == undefined) opacity = 0;
		if (color == undefined) color = "#888888";
		if (cursorOnDiv == undefined) cursorOnDiv = "default";

		var div = document.createElement('div');				

		div.style.backgroundColor = color;
		div.style.cursor = cursorOnDiv;
		div.style.position = "absolute";
		
		if (this.getBrowser() == this.IE) {
			var opacityForIE = Math.round(opacity * 100);
			div.style.filter = "Alpha(opacity="+opacityForIE+")";

			var bodyHeight = document.body.offsetHeight;
			var bodyWidth = document.body.offsetWidth;	

			bodyHeight = Math.max(bodyHeight, document.documentElement.clientHeight);
			bodyWidth = Math.max(bodyWidth, document.documentElement.clientWidth);
		}
		else {
			div.style.opacity = opacity;

			var bodyHeight = document.defaultView.getComputedStyle(document.body, '').getPropertyValue("height");
			var bodyWidth = document.defaultView.getComputedStyle(document.body, '').getPropertyValue("width");

			bodyHeight = bodyHeight.substr(0, bodyHeight.length - 2);
			bodyWidth = bodyWidth.substr(0, bodyWidth.length - 2);
			
			bodyHeight = Math.max(bodyHeight, window.innerHeight);
			bodyWidth = Math.max(bodyWidth, window.innerWidth);
		}

		div.style.top = "0px";
		div.style.left = "0px";
		div.style.width = bodyWidth+"px";
		div.style.height = bodyHeight+"px";		

		document.body.appendChild(div);
		
		return div;
	}		

	
	function showWaitCursor(cursorType) {
		if (cursorType == undefined) cursorType = "wait";
		
		if (this.waitingDiv == undefined) {
			this.waitingDiv = this.showDivOverBody(0, "", cursorType);
		}
	}
	
	function removeWaitCursor() {
		if (this.waitingDiv != undefined) {
		 	document.body.removeChild(this.waitingDiv);			
		 	this.waitingDiv = undefined;
		 }
	}

	function openWindow(module, closeOnOutClick, closingEvents, title, left, top, width, height, moverId) {		
		if (left == undefined) left = 30;
		if (top == undefined) top = 30;
		
		var overlay = this.showDivOverBody(0.5, "#808080");

		win = new js_window(null, overlay, closeOnOutClick, closingEvents, title);
		document.body.appendChild(win.element);
		win.element.style.top = top+"px";
		win.element.style.left = left+"px";
		win.element.style.overflow = "auto";
		if (width != undefined) win.element.style.width = width+"px";
		if (height != undefined) win.element.style.height = height+"px";

		win.setModule(module);
		debug.print("openWindow()");
		if (moverId != undefined) {
			debug.print("adding Mover : "+moverId);
			win.addMover(module.getObj(moverId));
		}
		return win;
	}

	function noBubbling(e){
		if (document.all) {		
			window.event.cancelBubble = true;
			window.event.returnValue = false;
		}
		if(e.preventDefault){ e.preventDefault(); }
		if(e.stopPropagation){ e.stopPropagation(); }
		return false;
		
	}	
}

var std = new std();


/**
*	Der Timer: neu auch in dte stdfuncs.js
*	=> 1 Datei weniger zu laden (da praktisch nur die Anzahl der zu ladenden Dateine einen einfluss auf
*		die Performance hat
*	=> Wie im PHP
*/

var timer = new Object();

timer.timerCount = 0;
timer.timerArray = new Array();

timer.setTimer = function(time, object, method, argument){
	var tID = timer.timerCount++;
	timer.timerArray[tID] = new Array();
	timer.timerArray[tID]['type'] = 'timer';
	timer.timerArray[tID]['object'] = object;
	timer.timerArray[tID]['method'] = method;
	timer.timerArray[tID]['argument'] = argument;
	timer.timerArray[tID]['id'] = setTimeout('timer.timerEvent('+tID+')', time);
	return tID;
}

timer.setInterval = function(time, object, method, argument){
	var tID = timer.timerCount++;
	timer.timerArray[tID] = new Array();
	timer.timerArray[tID]['type'] = 'interval';
	timer.timerArray[tID]['object'] = object;
	timer.timerArray[tID]['method'] = method;
	timer.timerArray[tID]['argument'] = argument;
	timer.timerArray[tID]['id'] = setInterval('timer.timerEvent('+tID+')', time);
	return tID;
}

timer.delTimer = function(tID) {
	if(timer.timerArray[tID]['type'] == 'timer')
		clearTimeout(timer.timerArray[tID]['id']);
	else
		clearInterval(timer.timerArray[tID]['id']);

	var tmp = new Array();
	for(var i in timer.timerArray)
		if(i != tID) tmp[i] = timer.timerArray[i];
	timer.timerArray = tmp;
}

timer.timerEvent = function(tID) {
	var obj = timer.timerArray[tID]['object'];
	if (obj != undefined) {
		obj[timer.timerArray[tID]['method']](timer.timerArray[tID]['argument']);
	}
	else {
		timer.timerArray[tID]['method'](timer.timerArray[tID]['argument']);
	}

	if (timer.timerArray[tID] != undefined && timer.timerArray[tID]['type'] == 'timer') {
		var tmp = new Array();
		for(var i in timer.timerArray)	{
			if(i != tID) tmp[i] = timer.timerArray[i];
		}
		timer.timerArray = tmp;
	}
}


timer.laufzeit = {};
timer.laufzeitStack = {};
timer.stackName = {};
timer.stackLen = 0;

timer.startMessung = function(name) {
	var prtLaufzeit = this.laufzeit;
	if (this.stackLen > 0) prtLaufzeit = this.laufzeitStack[this.stackLen - 1];
	
	if (typeof(prtLaufzeit['childs']) == "undefined") prtLaufzeit['childs'] = {};
	if (typeof(prtLaufzeit['childs'][name]) == "undefined") prtLaufzeit['childs'][name] = {'count':0, 'time':0};
	prtLaufzeit['childs'][name]['start'] = new Date().getTime();
	
	this.laufzeitStack[this.stackLen] = prtLaufzeit['childs'][name];
	this.stackName[this.stackLen] = name;
	
	this.stackLen++;
}

timer.stopMessung = function(name) {
	var tiefe = 0;
	for (var n = this.stackLen-1; n >= 0; n--) {
		if (this.stackName[n] == name) tiefe = Math.max(tiefe,n);
	}
	var cnt = this.stackLen;
	for (var n = tiefe; n < cnt; n++) {
		var aktLz = this.laufzeitStack[n];
		aktLz['time']+= new Date().getTime() - aktLz['start']; 
		if (n == tiefe) {
			aktLz['count']++;
		}
		else {
			aktLz['count'] = "FEHLER, Messung "+this.stackName[n]+" nicht abgeschlossen";
		}
	}
	this.stackLen = tiefe;
}

timer.createLaufzeitResult = function(laufzeit) {
	var result = {};
	if (typeof(laufzeit['childs']) == "object") {
		var childTime = 0;
		if (typeof(laufzeit['time']) != "undefined") result['Aufrufe'] = laufzeit['count'];
		for (var name in laufzeit['childs']) {
			result[name] = this.createLaufzeitResult(laufzeit['childs'][name]);
			childTime+= laufzeit['childs'][name]['time'];
		}
		if (typeof(laufzeit['time']) != "undefined") {
			result['Differenz'] = laufzeit['time'] - childTime;
			result['TOTAL'] = laufzeit['time'];
		}
	}
	else {
		result = {'Aufrufe':laufzeit['count'], 'zeit': laufzeit['time']};
	}
	return result;
}

timer.showLaufzeit = function() {
	var lz_nice = this.createLaufzeitResult(this.laufzeit);
	debug.show(lz_nice, "Laufzeit");
}


