/**
 * AJAX api
 *
 * $URL: svn://localhost/RBL-dev/tags/rbl_2010_02_15-1/js/ajax_container.js $
 * $Rev: 1056 $
 * $Author: jk $
 * $Date: 2010-02-15 15:20:28 +0100 (Mo, 15 Feb 2010) $
 * 
 */

var ajax_event;

/**
 * Ajax-Basisobjekt ajax_obj
 * @super Object
 * @type constructor
 * @memberOf ajax_obj
 * @param objid variablename
 */
ajax_obj.prototype = new Object();
function ajax_obj(objid) {
	this.id        = objid;
	this.container = null;        // DIV-Container
	this.titel     = null;        // Überschrift H4
	this.content   = null;        // Inhalt im Container-Fenster
	this.target    = null;        // Inhalt im Document-Element <target>
	this.target_mode = 'replace'; // raplace/add
	/**
	 * XMLHttpRequest Objekt
	 * @property ajax
	 * @type XMLHttpRequest
	 */
	this.ajax      = null;       // XMLHttpRequest-Objekt
	this.abstandX  =   10;        // horizontaler und ...
	this.abstandY  =   10;        // vertikaler Abstand vom Mauszeiger
	this.width     =  300;        // Breite und ...
	this.height    =    0;        // Höhe des Containers
	this.minheight =  150;        // Höhe des Containers
	this.pos_x     =    0;        // Position des
	this.pos_y     =    0;        // Containers
	this.xmlresult =   '';        // Rückgabewert xml: <value>resulttext</value>
	this.onLoad    = null;        // callback funktion wenn daten geladen
	this.onNoAjax  = ajax_not_avail; // callback funktion wenn Ajax nicht verfügbar
	this.movable   = true;        // kann man den Container verschieben
	this.pendingImg= null;			// "Sanduhr"
	//this.create_container = create_container;
	/**
	 * erzeugt Div-Container (Fenster)
	 * @method create_container  
	 * @param {Int} X x-Koordinate
	 * @param {Int} Y y-Koordinate
	 */
	this.create_container = function (X, Y) {
		if (this.container) this.close();

		this.container = document.createElement("div");
		this.container.id = this.id;
		this.container.className = "ajax";
		this.container.style.width  = this.width + "px";
		if (this.height) {
			this.container.style.height = this.height + "px";
		}
		if ((X >= 0) && (Y >= 0)) {
			// Positionieren, abhängig von Mauszeiger und Browserfenster
			// Der Kasten soll rechts vom Mauszeiger erscheinen, wenn dort
			// noch Platz ist oder links kein Platz ist
			var scroll = new ajax_get_scrollpos();
			this.pos_x = ((X + this.abstandX + this.width + 30 < window.innerWidth) || (this.width + this.abstandX > X)) ?
					X + this.abstandX : // rechts von Mauszeiger
					X - (this.width + this.abstandX); // links
			// Der Kasten soll über dem Mauszeiger erschein, wenn Platz ist
			if (this.height > 0) {
				this.pos_y = (this.height + this.abstandY < Y - scroll.Y) ?
						Y - this.height - this.abstandY :  // unter Mauszeiger
						Y + this.abstandY; // darüber
			} else {
				this.pos_y = (Y - this.minheight + this.abstandY < scroll.Y) ?
						scroll.Y + this.abstandY :          // am oberen Rand
						Y - this.minheight - this.abstandY; // über Mauszeiger
			}
			//alert('roll: '+scroll.X + ' ' + scroll.Y);// + "\npos: "+ pos_x + ' ' + pos_y + "\nmaus: "+ FN.mausX + ' ' + FN.mausY);
		}
		this.container.style.left = this.pos_x + "px";
		this.container.style.top  = this.pos_y + "px";
		// Überschrift
		this.titel = document.createElement("h4");
		this.titel.icon = document.createElement('img');
		this.titel.icon.src = '/pic/pix.gif';
		this.titel.icon.className = 'icon';
		this.titel.appendChild(this.titel.icon);
		this.titel.txt = document.createTextNode('Titel');
		this.titel.appendChild(this.titel.txt);
		// Link zum Schließen
		var sp_link = document.createElement("a");
		sp_link.ajaxobj = this;
		sp_link.onclick = function () {
			this.ajaxobj.close();
		};
		sp_link.setAttribute("title", "schließen");
		sp_link_txt = document.createTextNode(' ');
		sp_link.appendChild(sp_link_txt);

		if (this.movable) {
			this.titel.onmousedown = ajax_obj_drag_start;
			this.titel.style.cursor = "move";
		}

		// zusammensetzen
		this.titel.appendChild(sp_link);
		this.container.appendChild(this.titel);

		this.content = document.createElement("div");
		this.content.className = "ajax_content";
		if (this.height) {
			this.content.style.height = this.height - 20 + "px";
		}
		
		this.pendingImg = document.createElement('img');
		this.pendingImg.src = '/pic/wait.gif';
		this.pendingImg.className = 'pending';
		this.content.appendChild(this.pendingImg);
		
		this.container.appendChild(this.content);

		document.getElementsByTagName("body")[0].appendChild(this.container);
	};
	this.close     = function() {
		// schließt und löscht den Container
		if (this.container) {
			document.getElementsByTagName('body')[0].removeChild(this.container);
			this.container = null;
		}
	};
	this.load      = load_container;
	
	/**
	 * setzt den Textknoten eines DOM-Nodes
	 * @param parent
	 * @param {string} text
	 */
	this.setTextNode = function (parent, text) {
		//alert(OP);
		if (parent) {
			//alert('['+parent.firstChild.nodeValue+']');
			if (typeof text == 'undefined') text = '';
			if (parent.firstChild) {
				if (OP) {
					parent.replaceChild(document.createTextNode(text), parent.firstChild);
				} else {
					parent.firstChild.nodeValue = text;
				}
			} else if (text) {
				parent.appendChild(document.createTextNode(text));
			}
		}
	};

	/**
	 * setzt den Textknoten eines Element durch seine ID
	 * @param {string} id
	 * @param {string} text
	 * @return (node) 
	 */
	this.setTextNodeById = function (id, text) {
		var el = document.getElementById(id);
		if (el) this.setTextNode(el, text);
		return el;
	};

	/**
	 * setzt den Wert eines Formular-Elements ermittelt durch seine ID
	 * @param {string} id
	 * @param {string} value
	 * @return (node) 
	 */
	this.setNodeValueById = function (id, value) {
		var el = document.getElementById(id);
		if (el) el.value = value;
		return el;
	};

	/**
	 * fügt die Werte des Rückgabe-Arrays in das Dokument ein
	 * die Zielknoten für die einzelnen Werte müssen das
	 * ID-Attribut in der Form "[name]_[id]_[feldname]" haben
	 * 
	 * {Boolean} Function( {String} name ); 
	 */
	this.setXmlResult = function(name) {
		if ((typeof(this.xmlresult) == 'object') && (this.xmlresult['id'])) {
			var id = this.xmlresult['id'];
			for (var key in this.xmlresult) {
				// Ziel suchen
				var node = document.getElementById(name + '_' + id + '_' + key);
				this.setTextNode(node, this.xmlresult[key]);
			}
			return true;
		}
		return false;
	};
}

function noXMLHttpRequest(parent_obj) {
	this.parent_obj = parent_obj;
	window._ifr_buf_count |= 0;
	this.iframe = null;
	this.iframeID = 'iframebuffer' + window._ifr_buf_count++;
	this.url = '';
	this.open = noXMLHttpRequest_open;
	this.setRequestHeader = noXMLHttpRequest_setRequestHeader;
	this.send = noXMLHttpRequest_send;
	this.onreadystatechange = null;
	this.onready = noXMLHttpRequest_onready;
	this.readyState = 1;
	this.status = 1;
	this.responseXML;
	this.win;
}

function noXMLHttpRequest_open(method, url, dummy) {
	this.url = url;
}

function noXMLHttpRequest_setRequestHeader(key, value) {
	// IE5.0 doesn't like createElement'd frames (won't script them) and IE4 just plain
	// doesn't support it. Luckily, this will fix them both:
	document.body.insertAdjacentHTML('beforeEnd', '<iframe name="' + this.iframeID +
			'" id="' + this.iframeID + '" style="display: none;"></iframe>');// style="position: absolute;"

	// This helps most IE versions regardless of the creation method:
	if (window.frames && window.frames[this.iframeID]) this.iframe = window.frames[this.iframeID];
}

function noXMLHttpRequest_send(dummy) {
	this.iframe.document.location.replace(this.url);
}

function noXMLHttpRequest_onready() {
	var responseXML;

	if (this.iframe.contentDocument) {
		// For NS6
		responseXML = this.iframe.contentDocument;
	} else if (this.iframe.contentWindow) {
		// For IE5.5 and IE6
		responseXML = this.iframe.contentWindow.document;
	} else if (this.iframe.document) {
		// For IE5
		responseXML = this.iframe.document;
	}

	if (responseXML) {
		// schreibe titel
		if (this.parent_obj.titel) {
			var fns = responseXML.getElementById("xmlrsp_titel");
			if ((fns) && (fns.firstChild)) {
				this.parent_obj.titel.txt.nodeValue = fns.firstChild.nodeValue;
				//alert(fns.firstChild.nodeValue);
			}
		}

		// schreibe content in fns
		if (this.parent_obj.content) {
			var fns = responseXML.all.xmlrsp_content;
			if (fns) { 
				this.parent_obj.content.insertAdjacentHTML("AfterBegin",fns.innerHTML);
			}
		}

		// schreibe target in fns
		if (this.parent_obj.target) {
			var fns = responseXML.all.xmlrsp_target;
			if (fns) {
				// @todo (jk) replace/add
				while(child = this.parent_obj.target.firstChild) {
					this.parent_obj.target.removeChild(child);
				}
				this.parent_obj.target.insertAdjacentHTML("AfterBegin",fns.innerHTML);
			}
		}

		if (this.iframe.getvalue) {
			this.parent_obj.xmlresult = this.iframe.getvalue();
		}

		// Pending Image ausschalten
		if (this.pendingImg) {
			this.pendingImg.style.display = 'none';
		}
		if (this.parent_obj.onLoad) {
			this.parent_obj.onLoad();
		}
		document.body.style.cursor = 'auto';
		return true;
	}
	return false;
}

function ajax_obj_drag_start() {
	// this ist hier das H4 Element => der container ist this.parentNode

	return drag_start(this.parentNode);
}

function ajax_not_avail() {
	alert("Ihr Browser kann leider keine Ajax-Inhalte anzeigen.");
}

function createXMLHttp() {

	if (typeof XMLHttpRequest != "undefined") {
		//alert('XMLHttpRequest' + (typeof XMLHttpRequest));
		return new XMLHttpRequest();
	} else if (window.ActiveXObject) {
		var aVersions = [ "MSXML2.XMLHttp.5.0",
		                  "MSXML2.XMLHttp.4.0","MSXML2.XMLHttp.3.0",
		                  "MSXML2.XMLHttp","Microsoft.XMLHttp"
		                  ];

		for (var i = 0; i < aVersions.length; i++) {
			try {
				var oXmlHttp = new ActiveXObject(aVersions[i]);
				//alert(aVersions[i]);
				return oXmlHttp;
			} catch (oError) {
				//Do nothing
			}
		}
	}
	//alert('no XMLHttp');
	throw new Error("XMLHttp object could be created.");
}

function load_container(url) {
	// evtl eine PHP Sessionid anhängen
	if (SESSID) {
		if (url.indexOf(SESSID) == -1) {
			if (url.search(/\?/) >= 0) {
				url = url.concat('&'+SESSID);
			} else {
				url = url.concat('?'+SESSID);
			}
		}
	}

	// Pending Image einschalten
	if (this.pendingImg) {
		this.pendingImg.style.display = 'block';
	}

	// Ajax-Verbindung herstellen
	try {           
		// W3C-Standard
		this.ajax = createXMLHttp();
	} catch(err) {
		this.ajax = new noXMLHttpRequest(this);
		if (url.search(/\?/) >= 0) {
			url = url.concat('&noxmode=iframe');
		} else {
			url = url.concat('?noxmode=iframe');
		}
	}

	if (url.length < 2000) {
		// Datei mit GET anfordern (asynchron)
		this.ajax.open('GET', url, true);//encodeURI(url)
		this.ajax.setRequestHeader('Content-Type', 'text/xml');
		// umgeht Internet Explorers Caching von GET-Anfragen
		this.ajax.setRequestHeader('If-Modified-Since', 'Sat, 1 Jan 2000 00:00:00 GMT');

		this.ajax.send(null);
	} else {
		var p = url.indexOf('?');
		var param = url.substr(p+1);
		url = url.slice(0,p);
		this.ajax.open("POST", url, true);

		this.ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
		this.ajax.setRequestHeader("Content-length", param.length);
		this.ajax.setRequestHeader("Connection", "close");

		// make the server request
		this.ajax.send(param);
	}
	// nach Status-Änderungen der Verbindung
	// werden die empfangenen Inhalte geparst

	this.ajax.onreadystatechange = function(axobj) {
		return function() {	
			// wenn Datei komplett empfangen ist ...
			if (axobj.ajax.readyState == 4) {
				// Dokument nicht gefunden (Code 0 für lokale Tests):
				if (axobj.ajax.status != 200 && axobj.ajax.status != 0) {
					alert('XML-Fehler: Datei konnte nicht gefunden werden!'+axobj.ajax.status);
					var er_text = document.createTextNode("XML-Datei konnte nicht gefunden werden!");
					var absatz = document.createElement("p");
					absatz.appendChild(er_text);
					axobj.container.appendChild(absatz);
					document.body.style.cursor = 'auto';
					return false;
				}

				if (!axobj.ajax.responseXML) {
					alert('XML-Fehler: \n'+axobj.ajax.responseText.replace(/<[^>]*>/g, ''));
					document.body.style.cursor = 'auto';
					return false;
				}

				//alert('onreadystatechange:' + axobj.id);

				// schreibe titel in fns
				if (axobj.titel) {
					var fns = axobj.ajax.responseXML.getElementsByTagName("titel");
					if ((fns.length > 0) && (fns[0].firstChild)) {
						axobj.titel.txt.nodeValue = fns[0].firstChild.nodeValue;
						//alert(fns[0].firstChild.nodeValue);
					}
					// schreibe icon in fns
					var fns = axobj.ajax.responseXML.getElementsByTagName("icon");
					if (fns.length > 0) {
						axobj.titel.icon.src = fns[0].firstChild.nodeValue;
						//alert(fns[0].firstChild.nodeValue);
					}
				}

				// schreibe content in fns
				if (axobj.content) {
					var fns = axobj.ajax.responseXML.getElementsByTagName("content");
					if (fns.length > 0) {
						klonen(fns[0].cloneNode(true), axobj.content);
					}
				}

				// schreibe target in fns
				if (axobj.target) {
					var fns = axobj.ajax.responseXML.getElementsByTagName("target");
					if (fns.length > 0) {
						if (axobj.target_mode == 'replace') {
							while(child = axobj.target.firstChild) {
								axobj.target.removeChild(child);
							}
						}
						klonen(fns[0].cloneNode(true), axobj.target);
					}
				}

				// schreibe value in fns
				var fns = axobj.ajax.responseXML.getElementsByTagName("value");
				if ((fns.length > 0) && (fns[0].firstChild)) {
					//alert("nodeType = " + fns[0].firstChild.nodeType);
					if (fns[0].firstChild.nodeType == 3) {
						// textknoten
						axobj.xmlresult = fns[0].firstChild.nodeValue;
					} else {
						axobj.xmlresult = new Object;
						var vnode = fns[0].firstChild;
						while (vnode != null) {
							if (vnode.firstChild) {
								axobj.xmlresult[vnode.nodeName] = vnode.firstChild.nodeValue;
//								alert(vnode.nodeName + " = " + vnode.firstChild.nodeValue);
//								else
//								axobj.xmlresult[vnode.nodeName] = '';
//								alert(vnode.nodeName + " = #");
							}
							vnode = vnode.nextSibling;
						}
					}
				} else {
					axobj.xmlresult = '';
				}
				
				// Pending Image ausschalten
				if (axobj.pendingImg) {
					axobj.pendingImg.style.display = 'none';
				}
				//alert(axobj.onLoad);
				if (axobj.onLoad) {
					axobj.onLoad();
				}
				document.body.style.cursor = 'auto';
				return true;
			}
		};
	}(this);

}

function klonen(quelle, ziel) {
	// Hilfsfunktion für Darstellung im DOM
	// Einfaches cloneNode() funktioniert nicht bei komplexen
	// Gebilden; eine Schleife baut den Teilbaum nach.
	for(var i = 0; i < quelle.childNodes.length; i++) {
		var knoten = quelle.childNodes[i];
		switch (knoten.nodeType) {
		case 1:   // Elementknoten
//				alert('Quelle: Nodename = '+knoten.nodeName);
			if (BROWSER.IE && (BROWSER.Version < 8)) {
				// IE fix
				var attribs = '';
				if ((knoten.outerHTML) && (knoten.nodeName.toLowerCase() == 'img')) {
					newNode = document.createElement(knoten.outerHTML);
				} else {
					var newNode = document.createElement(knoten.nodeName);
					for (var j = 0; j < knoten.attributes.length; j++) {
						switch (knoten.attributes[j].nodeName.toLowerCase()) {
						case "class":
							newNode.className = knoten.attributes[j].nodeValue;
							break;
						case "cellpadding":
							newNode.cellPadding = knoten.attributes[j].nodeValue;
							break;
						case "cellspacing":
							newNode.cellSpacing = knoten.attributes[j].nodeValue;
							break;
						case "width":
							if (knoten.attributes[j].nodeValue)
								newNode.width = knoten.attributes[j].nodeValue;
							break;
						case "height":
							if (knoten.nodeName.toLowerCase() != 'input')
//								alert('height:'+knoten.attributes[j].nodeValue);
								if (knoten.attributes[j].nodeValue)
									newNode.height = knoten.attributes[j].nodeValue;
							break;
						case "align":
							newNode.align = knoten.attributes[j].nodeValue;
							break;
						case "bgcolor":
							newNode.bgColor = knoten.attributes[j].nodeValue;
							break;
						case "id":
							newNode.id = knoten.attributes[j].nodeValue;
							break;
						case "size":
							newNode.size = knoten.attributes[j].nodeValue;
							break;
						case "maxlength":
							newNode.maxLength = knoten.attributes[j].nodeValue;
							break;
						case "type":
							// ausser <button type="button" ...>
							if ((knoten.nodeName.toLowerCase() != 'button') || (knoten.attributes[j].nodeValue.toLowerCase() != 'button'))
								newNode.type = knoten.attributes[j].nodeValue;
							break;
						case "value":
							newNode.value = knoten.attributes[j].nodeValue;
							break;
						case "href":
							newNode.href = knoten.attributes[j].nodeValue;
							break;
						case "name":
							newNode.name = knoten.attributes[j].nodeValue;
							break;
						case "colspan":
							newNode.colSpan = knoten.attributes[j].nodeValue;
							break;
						case "rowspan":
							newNode.rowSpan = knoten.attributes[j].nodeValue;
							break;
						case "onclick":
						case "ondblclick":
						case "onkeyup":
						case "onchange":
						case "onsubmit":
						case "onmouseover":
						case "onmouseout":
							newNode[knoten.attributes[j].nodeName.toLowerCase()] = new Function(knoten.attributes[j].nodeValue);
							break;
						case "style":
							var styles = knoten.attributes[j].firstChild.nodeValue.split(';');
							if (styles.length > 1)
								for (var i = 0; i < styles.length - 1; i++)
								{
									var style = styles[i].split(':');
									newNode.style[style[0]] = style[1];
								}
							else
								alert(knoten.attributes[j].firstChild.nodeValue);
							break;
							// geprüfte Attribute, die mit setattribute funktionieren
						case "checked":
						case "selected":
						case "method":
						case "action":
						case "title":
						case "alt":
						case "src":
							newNode.setAttribute(knoten.attributes[j].nodeName, knoten.attributes[j].nodeValue);
							break;
						default: // noch nicht geprüfte Attribute
						newNode.setAttribute(knoten.attributes[j].nodeName, knoten.attributes[j].nodeValue);
						//alert('Attribut: '+knoten.attributes[j].nodeName+' = "'+knoten.attributes[j].nodeValue+'"');
						}
						attribs += ' ' + knoten.attributes[j].nodeName.toLowerCase() + '="' + knoten.attributes[j].nodeValue + '"';
					}
				}
			} else {
				// correct DOM (firefox/opera)
				var newNode = document.createElement(knoten.nodeName);
				for (var j = 0; j < knoten.attributes.length; j++) {
					newNode.setAttribute(knoten.attributes[j].nodeName, knoten.attributes[j].nodeValue);
				}
			}

			// IE input width bugfix
			if ((MS) && (knoten.nodeName.toLowerCase() == 'input') && (newNode.width == 0)) {
				newNode.removeAttribute("width");
//				alert(newNode.type);
			}

			if ((MS) && (knoten.nodeName.toLowerCase() == 'input') && (newNode.type == 'radio')) {
				// IE radio button bugfix
				//alert(knoten.outerHTML);
				if (knoten.outerHTML) {
					newNode = document.createElement(knoten.outerHTML);
				} else {
					var add = '';
					if (newNode.checked)   add += ' checked';
					if (newNode.className) add += ' class="'+newNode.className+'IE"';
					newNode = document.createElement('<input type="radio" name="'+newNode.name+'" value="'+newNode.value+'"'+add+'>');
				}
			} else if ((MS) && (knoten.nodeName.toLowerCase() == 'input') && (newNode.type == 'checkbox')) {
				// IE checkbox bugfix
				//alert(knoten.outerHTML);
				if (knoten.outerHTML) {
					newNode = document.createElement(knoten.outerHTML);
				} else {
					newNode = document.createElement('<input' + attribs + '>');
				}
			} else {
				// rekursion
				klonen(knoten, newNode);

				if ((MS) && (knoten.outerHTML) && (knoten.nodeName.toLowerCase() == 'select')) {
					alert("selectedIndex: "+knoten.options.selectedIndex);
				}
			}

			var neu = ziel.appendChild(newNode);
			break;
		case 3:   // Textknoten
			subknoten = document.createTextNode(knoten.nodeValue);
			ziel.appendChild(subknoten);

			// andere Knotentypen sind nicht relevant
		}
	}
}

function ajax_get_event(e) {
	ajax_event = new ajax_set_event(e);
}

function ajax_set_event(e) {
	if (!e) {
		this.type = window.event.type;
		this.target=window.event.srcElement;
		this.clientX = window.event.clientX;
		this.clientY = window.event.clientY;
		if (document.documentElement && document.documentElement.scrollTop) { 
			// Explorer 6 Strict
			this.pageX = window.event.clientX + document.documentElement.scrollLeft;
			this.pageY = window.event.clientY + document.documentElement.scrollTop;
		} else if (document.body) {
			// all other Explorers
			this.pageX = window.event.clientX + document.body.scrollLeft;
			this.pageY = window.event.clientY + document.body.scrollTop;
		}
	} else {
		this.type = e.type;
		this.target = e.currentTarget;
		this.clientX = e.clientX;
		this.clientY = e.clientY;
		this.pageX = e.clientX + self.pageXOffset;
		this.pageY = e.clientY + self.pageYOffset;
	}

	// drag and drop
	if (drag_object) {
		drag_move();
	} else if (jkMouseMoveCallback) {
		jkMouseMoveCallback();
	}

	return false;
}

/**
 * Enthält die horizontale oder vertikale Scroll-Verschiebung
 * @constructor
 */
function ajax_get_scrollpos() {
	if (isFinite(self.pageYOffset)) {
		// DOM
		this.X = self.pageXOffset;
		this.Y = self.pageYOffset;
		//alert('pageYOffset = ' + this.Y);
	} else if (document.documentElement && document.documentElement.scrollTop) {
		this.X = document.documentElement.scrollLeft;
		this.Y = document.documentElement.scrollTop;
		//alert('documentElement.scrollTop = ' + this.Y);
	} else if (document.body) {
		// all other Explorers
		this.X = document.body.scrollLeft;
		this.Y = document.body.scrollTop;
		//alert('body.scrollTop = ' + this.Y);
	}
}

/**
 * liefert das Rechteck (x,y,w,h) eines Elements mit absoluten Koordinaten
 * 
 * @param {Object} o HTML-Element
 * @return rect {x,y,w,h}
 */
function jkAbsoluteRect(o) {

    var r = { x:0, y:0, w:0, h:0 };

    if(!o) {
    	return r;
    } else if(typeof o == 'string' ) {
    	o = document.getElementById(o);
    } 

    if( typeof o != 'object' ) return r;

    if(typeof o.offsetTop != 'undefined') {

         r.h = o.offsetHeight;
         r.w = o.offsetWidth;
         r.x = r.y = 0;

         while (o && o.tagName != 'BODY')         {

              r.y += parseInt( o.offsetTop );
              r.x += parseInt( o.offsetLeft );
              o = o.offsetParent;

         }
    }

    return r;
}


// drag and drop

var jkMouseMoveCallback = null;

jkDragDropObject.prototype = new Object();
function jkDragDropObject() {
	/**
	 * div-Element (mit Klasse "__drag"), das eine Kopie der drag-Quelle enthält
	 * @private
	 */
	this.container = null;
	
	/**
	 * drag-Quelle
	 * @private
	 */
	this.source = null;
	
	/**
	 * drop-Ziel
	 * @private
	 */
	this.target = null;
	
	/**
	 * registrierte drop-Ziele
	 * @private
	 */
	this.drop_targets = new Array();
	
	/**
	 * callback: fn(source,target) wird aufgerufen, wenn das drag-Objekt
	 * auf einem drop-target losgelassen wird
	 */
	this.onDragDrop = null;
	
	/**
	 * Startet die Drag-Aktion mit drag_source als zu ziehenes Objekt
	 * (auslösen mit onmousedown)
	 * 
	 * @param drag_source HTML-Element
	 */
	this.start = function(drag_source) {
		
		this.source = drag_source;
		
		// Container erstellen
		var r = jkAbsoluteRect(drag_source);
		this.drag_x_rel = r.x - ajax_event.pageX;
		this.drag_y_rel = r.y - ajax_event.pageY;
		this.container = document.createElement('div');
		this.container.appendChild(drag_source.cloneNode(true));
		this.container.className = '__drag';
		this.container.style.position = 'absolute';
		this.container.style.left = r.x + "px";
		this.container.style.top  = r.y + "px";
		this.container.style.width  = r.w + "px";
		this.container.style.height  = r.h + "px";
		document.getElementsByTagName("body")[0].appendChild(this.container);
		
		jkMouseMoveCallback = function (_this) {
			return function() {
				var mx = ajax_event.pageX;
				var my = ajax_event.pageY;
				var can_drop;

				_this.container.style.left  = ajax_event.pageX + _this.drag_x_rel + "px";
				_this.container.style.top   = ajax_event.pageY + _this.drag_y_rel + "px";
				
				_this.target = null;

				for (var i = 0; i < _this.drop_targets.length; ++i) {

					var dt = _this.drop_targets[i];
					var r = dt.absoluteR;

					if ((mx > r.x) && (mx < r.x + r.w) && (my > r.y) && (my < r.y + r.h)) {
						if ((_this.target) && (_this.target.onDragOut)) {
							_this.target.onDragOut();
						}
						if (dt.onDragOver) {
							can_drop = dt.onDragOver(_this.source);
						} else {
							can_drop = true;
						}

						if (can_drop) {
							_this.target = dt;
						}
					} else {
						if (dt.onDragOut) dt.onDragOut();
					}
				}
			};
		}(this);
		
		// Zwischenspeicher für document events
		this.temp_document_onmouseup   = document.onmouseup;

		document.onmouseup   = this.dragDrop;
	};
	
	/**
	 * behandelt den document.onmouseup-Event, um die Drag-Aktion zu beenden
	 * 
	 * @private
	 */
	this.dragDrop = function(_this) {
		return function() {
			if (_this.target) {
				if (_this.target.onDragOut) _this.target.onDragOut();
				
				if (_this.onDragDrop) _this.onDragDrop(_this.source, _this.target);
			}
			
			if (_this.container) {
				document.getElementsByTagName("body")[0].removeChild(_this.container);
			}

			document.onmouseup   = _this.temp_document_onmouseup;
			_this.container = null;
			_this.target = null;
			jkMouseMoveCallback = null;

		};
	}(this);
	
	/**
	 * registriert ein HTML-Element als gültiges Ziel
	 * das HTML-Element kann die Event-Handler 
	 * bool onDragOver(source) Ergebnis: darf source abgelegt werden?
	 * und
	 * onDragOut()
	 * enthalten, um z.B. ein highlighting zu realisieren
	 * 
	 * @param drop_target HTML-Element
	 */
	this.register_drop_target = function(drop_target) {
		this.drop_targets.push(drop_target);
		drop_target.absoluteR = jkAbsoluteRect(drop_target);
	};
	
	// Zwischenspeicher für document events
	this.temp_document_onmouseup   = null;
	// Abstand des drag-Objekts zur Mausposition
	this.drag_x_rel;
	this.drag_y_rel;
}


// Zwischenspeicher für document events
var document_onmouseup   = null;
var document_onmousedown = null;
// Abstand des drag-Objekts zur Mausposition
var drag_x_rel;
var drag_y_rel;
var drag_object = null;
var drag_callback = null;

function drag_start(obj) {
	if (drag_object) {
		drag_drop();
		//alert('drag_start drag_drop');
	} else {
		// aktuelle Position ermitteln
		if (obj.style.left) {
			var objX = parseInt(obj.style.left.slice(0,-2));
			drag_x_rel = objX - ajax_event.pageX;
		} else if (obj.style.right) {
			var objX = parseInt(obj.style.right.slice(0,-2));
			drag_x_rel = objX + ajax_event.pageX;
		}
		if (obj.style.top) {
			var objY = parseInt(obj.style.top.slice(0,-2));
			drag_y_rel = objY - ajax_event.pageY;
		} else if (obj.style.bottom) {
			var objY = parseInt(obj.style.bottom.slice(0,-2));
			drag_y_rel = objY + ajax_event.pageY;
		}

		//alert(obj.style.left+':'+obj.style.top+':'+obj.style.right);
		//alert(objX+':'+objY);
		//alert(drag_x_rel+':'+drag_y_rel);
		//return;

		drag_object = obj;
		// Zwischenspeicher für document events
		document_onmouseup   = document.onmouseup;
		document_onmousedown = document.onmousedown;

		document.onmouseup   = drag_drop;
		// Sicherheitsmaßnahme: manche Browser kommen mit den Ereignissen
		// durcheinander, z.B. beim Scrollen in Überlangen Inhalten
		// (Safari) oder bei Maus-Hektik (IE); in diesem Fall läst ein
		// Mausklick den am Zeiger klebenden Container.
		//document.onmousedown = drag_drop;
		//alert(drag_object);
	}
	return false;
}

function drag_move() {
	// verschiebt den Container parallel zu Mausbewegungen
	if (drag_object.style.left) {
		drag_object.style.left  = ajax_event.pageX + drag_x_rel + "px";
	} else if (drag_object.style.right) {
		drag_object.style.right = drag_x_rel - ajax_event.pageX + "px";
	}

	if (drag_object.style.top) {
		drag_object.style.top    = ajax_event.pageY + drag_y_rel + "px";
	} else if (drag_object.style.bottom) {
		drag_object.style.bottom = drag_y_rel - ajax_event.pageY + "px";
	}

	if (drag_callback) drag_callback();
}

function drag_drop() {
	// löscht Event-Handler, lässt Container los
	document.onmouseup   = document_onmouseup;
	drag_object = null;
	drag_callback = null;
}

document.onmousemove = ajax_get_event;

/* String URL encodieren */

function urlencode_string( estring ) {
	hex = '0123456789ABCDEF';

	var c;
	encString = '';
	e_char = '';
	e_len = estring.length;

	for( e_i = 0; e_i < e_len; e_i++ ) {
		c = estring.charAt( e_i );
		if (c.match(/[a-z0-9_,-.()]/i)) {
			encString += c;
		} else {
			e_char = parseInt( estring.charCodeAt( e_i ) );

			encString += '%' + hex.charAt( (e_char >> 4) % 16 ) + hex.charAt( e_char % 16 );
		}
	}

	return encString;
}

// Hilfsfunktion zum auswerten der formulardaten
function ajax_form2url(form) {
	if (form) {
		var params = '';
		var el;
		var value;
		// Werte der input Elemente übernehmen
		var n = form.getElementsByTagName("input").length;
		for (i = 0; i < n; i++) {
			el = form.getElementsByTagName("input")[i];
			// alles übernehmen ausser buttons, unselektierte radio buttons und checkboxen
			if (((el.type != 'submit') && (el.type != 'button') && (el.type != 'radio') && (el.type != 'checkbox')) || (el.checked == true)) {
				value = urlencode_string(el.value);
				//if (console) console.log("%s",el.name+'='+value);
				params = params.concat('&'+el.name+'='+value);
			}
		}
		// Werte der select Elemente übernehmen
		var n = form.getElementsByTagName("select").length;
		for (i = 0; i < n; i++) {
			el = form.getElementsByTagName("select")[i];
			if (el.selectedIndex >= 0) {
				value = urlencode_string(el.options[el.selectedIndex].value);
				//if (console) console.log("%s",el.name+'='+value);
				params = params.concat('&'+el.name+'='+value);
			}
		}
		// Werte der textarea Elemente übernehmen
		var n = form.getElementsByTagName("textarea").length;
		for (i = 0; i < n; i++) {
			el = form.getElementsByTagName("textarea")[i];
			value = urlencode_string(el.value);
			//if (console) console.log("%s",el.name+'='+value);
			params = params.concat('&'+el.name+'='+value);
		}

		return params.replace(/^&/, '');
	}
	return '';
}

function ajax_SetTextNode(parent, text) {
	//alert(OP);
	if (parent) {
		//alert('['+parent.firstChild.nodeValue+']');
		if (typeof text == 'undefined') text = '';
		if (parent.firstChild) {
			if (OP) {
				parent.replaceChild(document.createTextNode(text), parent.firstChild);
			} else {
				parent.firstChild.nodeValue = text;
			}
		} else if (text) {
			parent.appendChild(document.createTextNode(text));
		}
	}
}

function ajax_SetTextNodeById(id, text) {
	var el = document.getElementById(id);
	if (el) ajax_SetTextNode(el, text);
}

function ajax_GetTextNode(parent) {
	//alert(OP);
	if (parent) {
		//alert('['+parent.firstChild.nodeValue+']');
		if (parent.firstChild) {
			return parent.firstChild.nodeValue;
		} else {
			return '';
		}
	} else {
		return '';
	}
}

function ajax_GetTextNodeById(id) {
	var el = document.getElementById(id);
	if (el) {
		return ajax_GetTextNode(el);
	} else {
		return '';
	}
}