/**
 * HelpBalloon
 * Prototype based help balloons
 * @copyright 2006 Beau D. Scott
 * modified by Fabian Lange 2007
 *  - removed Effect as this collides with PNG transparency fixes
 *  - removed direct rendering of icon, now passed as first param
 *  - removed unneded methods, which are part of prototype by now
 *  - added clobal array to keep track of helps. Not nice but works
 */
var HelpBalloon = Class.create();
var HelpBalloons = [];
HelpBalloon.prototype = {

	/**
	 * Instantiates the object
	 * @param {Object} options
	 */
	initialize: function(anchorElement,options)
	{
		/**
		 * Establish default options and apply specified values
		 */
		this.options = Object.extend({
			dataURL: null,										//URL to pull the title/content XML
			title: 'Hilfe',										//Title of the balloon topic
			content: 'Keine Hilfe definiert',	//Static content of the help balloon
			useEvent: ['click'],					//Events to trigger the balloon
			imagePath: '/images/help/',
			method: 'get'											//Method to retrieve the AJAX content
		}, options||{});

		/**
		 * collection of object elements
		 */
		this._elements = {
			container: null,				//Containing element of the balloon
			inner: null,						//Inner content container
			icon: null,							//Triggering icon
			content: null,					//Body Content container
			button: null,						//Closing 'X' button
			title: null							//Title Content Container
		};

		/**
		 * Properties and Attributes
		 */
		this._properties = {
			balloons : [										//Path to 4 bubble images
				this.options.imagePath + 'balloon-tl.png',	//Top Left
				this.options.imagePath + 'balloon-tr.png',	//Top Right
				this.options.imagePath + 'balloon-bl.png',	//Bottom Left
				this.options.imagePath + 'balloon-br.png'		//Bottom Right
			],
			balloonStyle: {							//Balloon styling
				position: 'absolute',
				border: 'none',
				background: 'white',
				width: '300px',
				height: '240px',
				display: 'none',
				zIndex: '100'
			},
			button: this.options.imagePath + 'button.png',
			visible: false,							//Status of Balloon's visibility
			balloonCoords: null,				//Stores the balloon coordinates
			innerDims: [230,170],				//Inner dimensions of the balloon, available for content
			outerDims: [300,240],				//Outer dimensions of the balloon
			pointerDims: [20,20],				//Balloon tail dimensions
			innerMargin: 15,						//Inner margin
			buttonHeight: 20,						//Size of 'X' image
			drawn: false,								//Rendering status
			renderXY: [0,0]							//X/Y coordinate of icon at time of render
		};
		
		HelpBalloons.push(this);
		/**
		 * Preload the balloon images
		 */
		this._properties.balloons.each(function(imgSrc)
		{
			var timg = document.createElement('img');
			timg.src = imgSrc;
		});

		this._elements.icon = $(anchorElement);
		if(!this._elements.icon) return false;
		this._elements.icon._HelpBalloon = this;

		/**
		 * Attach rendering events
		 */
		for(i = 0; i < this.options.useEvent.length; i++)
		{
			Event.observe(this._elements.icon, this.options.useEvent[i], this.toggle.bindAsEventListener(this));
		}
		this._elements.icon.style.cursor = 'pointer';
		this._elements.container = document.createElement('div');
		this._elements.container._HelpBalloon = this;
	},

	/**
	 * Toggles the help balloon
	 * @param {Object} e Event
	 */
	toggle: function(e)
	{
		
		if(!e) e = window.event || {type: this.options.useEvent[0], target: this._elements.icon};
		
		var icon = Event.element(e);
		if(this.options.useEvent.indexOf(e.type)!=-1 && !this._properties.visible && icon == this._elements.icon){
			this.show();
		}else{
			this.hide();
		}
	},

	show: function()
	{
		if(!this._properties.drawn) this._draw();
		this._reposition();
		this._hideOtherHelps();
		$(this._elements.container).show();
		this._hideLowerElements();
		this._properties.visible = true;
		Event.observe(window, 'resize', this._reposition.bindAsEventListener(this));
	},

	/**
	 * Hides the balloon
	 */
	hide: function()
	{
		this._showLowerElements();
		$(this._elements.container).hide();
		this._properties.visible = false;
		Event.stopObserving(window, 'resize', this._reposition.bindAsEventListener(this));
		return;
	},

	/**
	 * Redraws the balloon based on the current coordinates of the icon.
	 */
	_reposition: function()
	{
		this._properties.balloonCoords = this._getXY(this._elements.icon);
		this._properties.balloonCoords.x += Math.round(this._elements.icon.width / 2);
		this._properties.balloonCoords.y += Math.round(this._elements.icon.height / 2);

		var pos = 0;

		var oh = this._properties.balloonCoords.x + parseInt(this._elements.container.style.width);
		var ov = this._properties.balloonCoords.y - parseInt(this._elements.container.style.height);

		if(ov > 0)
			pos += 2;

		var ww = window.outerWidth ? window.outerWidth : document.body.clientWidth;
		if(oh > ww)
			pos += 1;
		
		this._elements.container.style.backgroundImage = 'url(' + this._properties.balloons[pos] + ')';

		this._elements.container.style.backgroundRepeat = 'no-repeat';
		this._elements.container.style.backgroundColor = 'transparent';
		if(this.isMSIE()) this._elements.container.style.backgroundAttachment = 'fixed';
		this._elements.container.style.backgroundPosition = 'top left';

		var cx = 0;
		var cy = 0;
		var zx = 0;
		var zy = 0;
		switch(pos)
		{
			case 1:
				cx = this._properties.pointerDims[0];
				cy = this._properties.pointerDims[1];

				zx = this._properties.balloonCoords.x - parseInt(this._elements.container.style.width);
				zy = this._properties.balloonCoords.y;
			break;

			case 2:
				cx = this._properties.pointerDims[0];
				cy = this._properties.pointerDims[1];

				zx = this._properties.balloonCoords.x;
				zy = this._properties.balloonCoords.y - parseInt(this._elements.container.style.height);
			break;

			case 3:
				cx = this._properties.pointerDims[0];
				cy = this._properties.pointerDims[1];

				zx = this._properties.balloonCoords.x - parseInt(this._elements.container.style.width);
				zy = this._properties.balloonCoords.y - parseInt(this._elements.container.style.height);
			break;

			default:
			case 0:
				cx = this._properties.pointerDims[0];
				cy = this._properties.pointerDims[1];

				zx = this._properties.balloonCoords.x;
				zy = this._properties.balloonCoords.y;
			break;
		}

		this._elements.container.style.left = zx + "px";
		this._elements.container.style.top = zy + "px";
		if(this._elements.inner) this._elements.inner.style.left = (cx + this._properties.innerMargin) + 'px';
		if(this._elements.inner) this._elements.inner.style.top = (cy + this._properties.innerMargin) + 'px';
	},

	/**
	 * Render's the Balloon
	 */
	_draw: function()
	{
		Element.setStyle(this._elements.container, this._properties.balloonStyle);
		if(this.options.dataURL && !this._properties.drawn)
		{
			var cont = new Ajax.Request(this.options.dataURL, {asynchronous: false, method: this.options.method});
			/**
			 * Expects the following XML format:
			 * <HelpBalloon>
			 * 		<title>My Title</title>
			 * 		<content>My content</content>
			 * </HelpBaloon>
			 */
			if(cont.success()){
				var doHTML = false;
				if(cont.transport.responseXML)
				{
					var xml = cont.transport.responseXML.getElementsByTagName('HelpBalloon')[0];
					if(xml)
					{
						xmlTitle = xml.getElementsByTagName('title')[0];
						if(xmlTitle) this.options.title = xmlTitle.firstChild.nodeValue;

						xmlContent = xml.getElementsByTagName('content')[0];
						if(xmlContent) this.options.content = xmlContent.firstChild.nodeValue;
					}
					else
						doHTML = true;
				}
				else
					doHTML = true;

				if(doHTML)
				{
					// Attempt to get the title from a <title/> HTML tag
					var htmlTitle = cont.transport.responseText.match(/\<title\>([^\<]+)\<\/title\>/gi);
					if(htmlTitle)
					{
						htmlTitle = htmlTitle.toString().replace(/\<title\>|\<\/title\>/gi, '');
						this.options.title = htmlTitle;
					}
					this.options.content = cont.transport.responseText;
				}
			}
			else
			{
				this.options.content = "Hilfe konnte nicht geladen werden";
				this.options.title = "Fehler";
			}
		}


		this._elements.inner = document.createElement('div');
		this._elements.inner.style.position = 'absolute';
		this._elements.inner.style.width = this._properties.innerDims[0] + 'px';
		this._elements.inner.style.height = this._properties.innerDims[1] + 'px';

		var title = document.createElement('div');
		title.appendChild(document.createTextNode(this.options.title));
		title.style.fontFamily = 'verdana';
		title.style.fontSize = '14px';
		title.style.fontWeight = 'bold';
		title.style.color = 'black';
		title.style.width = (this._properties.innerDims[0] - this._properties.buttonHeight) + 'px';
		title.style.height = this._properties.buttonHeight + 'px'
		title.style.position = 'absolute';
		title.style.overflow = 'hidden';
		title.style.top = '0px';
		title.style.left = '0px';
		this._elements.inner.appendChild(title);

		var closer = document.createElement('img');
		closer.width = this._properties.buttonHeight;
		closer.height= this._properties.buttonHeight;
		closer.src = this._properties.button;

		Event.observe(closer, 'click', this.toggle.bindAsEventListener(this));
		closer.style.cursor = 'pointer';
		closer.title = 'Hilfe schließen';
		closer.style.position = 'absolute';
		closer.style.top = '0px';
		closer.style.left = parseInt(title.style.width) + 'px';
		this._elements.inner.appendChild(closer);

		var contents = document.createElement('div');
		contents.style.width = this._properties.innerDims[0] + 'px';
		contents.style.height = (this._properties.innerDims[1] - parseInt(title.style.height)) + 'px';
		contents.style.overflow = 'auto';
		contents.style.position = 'absolute';
		contents.style.top = parseInt(title.style.height) + 'px';
		contents.style.left = "0px";
		contents.style.fontFamily = 'verdana';
		contents.style.fontSize = '11px';
		contents.style.fontWeight = 'normal';
		contents.style.color = 'black';
		contents.innerHTML = this.options.content;
		this._elements.inner.appendChild(contents);
		this._elements.container.appendChild(this._elements.inner);
		document.getElementsByTagName('body')[0].appendChild(this._elements.container);
		this._properties.drawn = true;
	},

	/**
	 * Gets the current position of the obj
	 * @param {Object} obj
	 */
	_getXY: function(obj)
	{
		var x;
  		var y;
		if(navigator.appName.search("Microsoft") > -1)
                {
			var pos = obj.viewportOffset();

			y = pos[1];
			x = pos[0];
		} else {
			y = obj.y; //pos[1];
			x = obj.x; //pos[0];
		}

		var x2 = x + parseInt(obj.offsetWidth);
		var y2 = y + parseInt(obj.offsetHeight);
		return {'x':x, 'y':y, 'x2':x2, 'y2':y2};

	},

	/**
	 * Determines if the balloon is over this_obj object
	 * @param {Object} this_obj
	 */
	_isOver: function(this_obj)
	{
		if(!this._properties.visible) return false;
		if(this_obj == this._elements.container || $(this_obj).descendantOf(this._elements.container)) return false;
		var this_coords = this._getXY(this_obj);
		var that_coords = this._getXY(this._elements.container);
		if(
			(
			 (
			  (this_coords.x >= that_coords.x && this_coords.x <= that_coords.x2)
			   ||
			  (this_coords.x2 >= that_coords.x &&  this_coords.x2 <= that_coords.x2)
			 )
			 &&
			 (
			  (this_coords.y >= that_coords.y && this_coords.y <= that_coords.y2)
			   ||
			  (this_coords.y2 >= that_coords.y && this_coords.y2 <= that_coords.y2)
			 )
			)

		  ){
			return true;
		}
		else
			return false;
	},

	/**
	 * Restores visibility of elements under the balloon
	 * (For IE)
	 */
	_showLowerElements: function()
	{
		var elements = this._getWeirdAPIElements();
		for(var i = 0; i < elements.length; i++)
		{
			if(this._isOver(elements[i]))
			{
				if(elements[i].style.visibility != 'visible' && elements[i].hiddenBy == this)
				{
					elements[i].style.visibility = 'visible';
					elements[i].hiddenBy = null;
				}
			}
		}
	},

	/**
	 * Hides elements below the balloon
	 * (For IE)
	 */
	_hideLowerElements: function()
	{
		var elements = this._getWeirdAPIElements();
		for(var i = 0; i < elements.length; i++)
		{
			if(this._isOver(elements[i]))
			{
				if(elements[i].style.visibility != 'hidden')
				{
					elements[i].style.visibility = 'hidden';
					elements[i].hiddenBy = this;
				}
			}
		}
	},

	/**
	 * Determines which elements need to be hidden
	 * (For IE)
	 */
	_getWeirdAPIElements: function()
	{
		if(!document.all) return [];
		var objs = ['select', 'input', 'object'];
		var elements = [];
		for(var i = 0; i < objs.length; i++)
		{
			var e = document.getElementsByTagName(objs[i]);
			for(var j = 0; j < e.length; j++)
			{
				elements.push(e[j]);
			}
		}
		return elements;
	},

	/**
	 * Hides the other visible help balloons
	 * @param {Object} e
	 */
	_hideOtherHelps: function(e)
	{
		for(var i = 0; i < HelpBalloons.length; i++)
		{
			if(HelpBalloons[i] != this){
				HelpBalloons[i].hide();
			}
		}
	},
	
	isMSIE: function(){
		return (/MSIE ((6)|(5\.5))/gi.test(navigator.userAgent) && /windows/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent));
	}
};
