function Bubble(theParent) {

	this.DELAY_SHOW = 350;
	this.DELAY_HIDE = 100;
	this.YOFFSET_STD = 0;
	this.XOFFSET_STD = -350;//-25;
	this.XOFFSET_MIRROR = -222;

	// path to images
	this.imagePath = '/img/';

	// construction part...
	var _bubDiv = document.createElement("div");
	_bubDiv.id = "bub";
	_bubDiv.onmouseover = "bub.show()";
	_bubDiv.onmouseout = "bub.off()";
	_bubDiv.innerHTML = '<div id="btop"></div><div id="bbody"><div class="bdata" id="bdata"></div></div><div id="bbot"></div><!--[if lte IE 6.5]><iframe style="width:0px;height:0px;"></iframe><![endif]-->';
	var _allBubDivs = _bubDiv.getElementsByTagName('div');
	for (var i=_allBubDivs.length-1; i>=0; i--) {
		_allBubDivs[i].onmouseover = function() {bub.startShowTimer()};
		_allBubDivs[i].onmouseout = function() {bub.off()};
	}
	if (theParent)
		document.getElementById(theParent).appendChild(_bubDiv);
	else
		document.body.appendChild(_bubDiv);

	
	this.yoffset = this.YOFFSET_STD;
	this.xoffset = this.XOFFSET_STD;
	
	this.container = document.getElementById("bub");
	this.bdata = document.getElementById("bdata");
	this.bbot = document.getElementById("bbot");

	this.dataID = "";
	this.aTag = null;
	this.timer = null;
	
	// trivial on/off
	this.off = function(immed) {
		if (immed!=null) {
			if (this.timer!=null) this.resetTimer();
			this.container.style.display = "none";
			selects = document.getElementsByTagName("select");
			for (i = 0; i != selects.length; i++) {
					selects[i].style.visibility = "visible";
			}
		} else {
			this.resetTimer();
			this.timer = setTimeout("bub.off(true)",this.DELAY_HIDE);
		}
	}

	// resets the timeout
	this.resetTimer = function() {
		if (this.timer!=null) {
			clearTimeout(this.timer);
			this.timer = null;
		}
	}

	this.startHideTimer = function () {
		this.resetTimer();
		this.timer = setTimeout("bub.off(true)",this.DELAY_HIDE);
	}

	this.startShowTimer = function() {
		this.resetTimer();
		this.timer = setTimeout("bub.show(bub.dataID,bub.aTag,true)",this.DELAY_SHOW);
	}

	// dataSrc = id of container to pick data from
	// aTag = a object to position bubble at
	this.show = function (dataSrc,aTag,doit) {

		// kill a running hiding-timeout to avoid flicker
		if (this.container.style.visibility == 'visible' && this.container.style.display == 'block' ) {
			this.resetTimer();
			return;
		}

		if (doit==null) {
			this.dataID = dataSrc;
			this.aTag = document.getElementById(aTag);
			this.startShowTimer();
			return;
		}
		this.leechData(dataSrc);
		this.resetContainer();
		this.container.style.visibility = 'hidden';
		
		var bubbleHeight = this.getPosOf(this.bbot).y;
		
		//var _pos = getAllOffsets(aTag);
		//var newX = _pos.x + this.xoffset;
		//var newY = _pos.y  + this.yoffset - bubbleHeight;
		
		var newX = tempX + this.xoffset;
		var newY = tempY  + this.yoffset - bubbleHeight;

		this.container.style.left = newX+"px";
		this.container.style.top = newY+"px";
		this.container.style.visibility = 'visible';
		
		selects = document.getElementsByTagName("select");
			for (i = 0; i != selects.length; i++) {
					selects[i].style.visibility = "hidden";
			}

	}

	// puts the container to (0;0)
	this.resetContainer = function() {
		// if (parseInt(this.container.style.left)<0) this.container.style.left = "0px";
		// if (parseInt(this.container.style.top)<0) this.container.style.top = "0px";
		if (this.container.style.display!="block") this.container.style.display="block";
	}
	
	// returns the coordinate of object obj as TPosition object
	this.getPosOf = function(obj) {
		var pos = new TPosition(0,0);
		if (obj!=false) {
			var tmp = document.createElement("SPAN");
			tmp.style.position = "absolute";
			obj.parentNode.appendChild(tmp);
			pos.y = tmp.offsetTop;
			pos.x = tmp.offsetLeft;
			obj.parentNode.removeChild(tmp);
		}
		return pos;			
	}
		
	// copies html from object defined by srcID  into bdata
	this.leechData = function(srcID) {
		var s = document.getElementById(srcID);
		if (s!=false) {
			s.innerHTML = s.innerHTML.replace(/^\r\n/,"");
		if (s==null) {
			this.bdata.innerHTML = "invalid srcID";
		} else if (this.bdata.innerHTML!=s.innerHTML) {
			this.bdata.innerHTML = s.innerHTML;
		}
		}
	}

	// mirrors the lower part of the keys on true
	this.mirror = function(doit) {
		if (doit) {
			this.xoffset = this.XOFFSET_MIRROR;
			if (this.bbot.className.length==0) this.bbot.className = "mir";
		} else {
			this.xoffset = this.XOFFSET_STD;
			if (this.bbot.className.length!=0) this.bbot.className = "";
		}
	}
	
	// if container unavailable (document.write failed), set off() + show() back to prototype status
	if (this.container==null) {
		this.mirror = function(){};
		this.off = function(){};
		this.show = function(){};
	}
	
	// JD: preload images
	this.images = ['bg_bubble.gif', 'bg_bubble_bot.gif', 'bg_bubble_bot_mirror.gif', 'bg_bubble_top.gif'];

	for (var _i = this.images.length-1; _i>=0; _i--) {
		var _image = new Image();
		_image.src = this.imagePath+this.images[_i];
	}

	function getAllOffsets(obj) {
		var _left = obj.offsetLeft;
		var _top = obj.offsetTop;
		var _parent = obj.offsetParent;
		
		while (_parent) {
			_left += _parent.offsetLeft;
			_top += _parent.offsetTop;
			_parent = _parent.offsetParent;
		}
		
		return new TPosition(_left, _top);
	}

	function TPosition(xx,yy) {
		this.x = xx;
		this.y = yy;
	}

} // end class

// JD: multiple onload events
function addOnload(func) {

	// IE knows attachEvent...
	if (window.attachEvent)
		window.attachEvent("onload", func);
	// others don't
	else {
		// check for existing onloads
		if (window.onload) {
			var _existingOnload = window.onload;
			window.onload = function() {
				_existingOnload();
				func();
			}
		} else
			window.onload = func;
	}
}

// JD: take getElementsByClassName from prototype.js
document.getElementsByClassName = function(className, parentElement) {
  var children = (document.getElementById(parentElement) || document.body).getElementsByTagName('*');
  var matchingChilds = [];
  for (var i=children.length-1; i>=0; i--) {
  	if (children[i].className.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) {
      matchingChilds.push(children[i]);
    }
  }
  return matchingChilds;
}

// JD: setup help bubbles for loaded document
function initBubble() {

	
	bub = new Bubble();
	// find all help button icons and attach the handlers if a bubble div can be found
	var _helpButtons = document.getElementsByClassName('hilfe');
 	for (var i=_helpButtons.length-1; i>=0; i--) {
 		try {
			// if button has no id, assign to "hilfe_alle"
 			if (!_helpButtons[i].id) {
 				 
 				//_helpButtons[i].id = "hilfe_button_"+i;
 				//_bubbleName = "hilfe_alle";
 			} else {
 				// strip numbers from end of id
 				if (/^(.*)_[0-9]+$/.exec(_helpButtons[i].id))
 					_bubbleName = RegExp.$1+"_bubble";
 				else
 					_bubbleName = _helpButtons[i].id+"_bubble";
 			}

 			_helpBubble = document.getElementById(_bubbleName);
 			if (!_helpBubble) throw new Error("no bubble div '"+_bubbleName+"' found");
 			
 			eval("_mouseOver = function(element) { bub.mirror(0); bub.show('"+_bubbleName+"','"+_helpButtons[i].id+"') }");
	 		_helpButtons[i].onmouseover = _mouseOver;
 			_helpButtons[i].onmouseout = function() { bub.off() };
 			
 		} catch(error) {
 			_helpButtons[i].style.border = "1px solid red";

		}
	}
}

// JD initialize globals
var bub;
// addOnload(function() {alert("got onload event")});
addOnload(initBubble);
