function PopupInfo() 
{
	this.html = '';             // text/html content
	this.css = '';              // stylesheet url/path
	this.lifetime = 0;          // auto-hide after duration [ms] (0 = infinite)
	this.opacity = 100;         // opacity percentage level (0 - 100 [opaque])
	this.showDelay = 500;       // delay in showing popup [ms]
	this.hideDelay = 0;         // delay in hiding popup [ms] (neg. = infinite)
	this.fadeInInterval = 50;   // delay between fade-in steps [ms]
	this.fadeInDuration = 0;    // fade-in duration [ms]
	this.fadeOutInterval = 50;  // delay between fade-out steps [ms]
	this.fadeOutDuration = 0;   // fade-out duration [ms]
	this.keepInView = false;    // auto-adjust to remain within viewport
	this.track = false;         // track mouse around
	this.refresh = 50;          // refresh rate [ms] (0 = none)
	this.zIndex = 5000;         // z-index level
	this.offset = [0,0];        // offset from origin [dx,dy]
	this.classPrefix = null;    // class prefix on popup body reflecting position
	this.position = 'any';      // position relative to origin
	this.origin = 'cursor';     // position anchor / reference point:
	                            //   cursor | element | viewport
}

function Popup( globalCSS, globalTarget ) 
{
	var oDiv = null;
	var oInfo = null;
	var oCSS = globalCSS;
	var oElement = null;
	var timers = { show: null, hide: null, fade: null };


	function load() 
	{
		oDiv = document.createElement('div');
		oDiv.style.position = 'absolute';
		oDiv.allowTransparency = true;
		oDiv.style.visibility = 'hidden';
		oDiv.style.display = 'none';
		document.body.appendChild( oDiv );
	}

	function GetMousePos(e) 
	{
		if (typeof(e.pageX) == 'number') 
		{
			return( {x: e.pageX, y: e.pageY} );
		} 
		var pos = getScrollPos();
		return( {x: e.clientX + pos.x, y: e.clientY + pos.y} );
	}

	function getScrollPos() {
		var body = document.body;
		var html = document.documentElement;
		var x = (body && body.scrollLeft) || 0;
		var y = (body && body.scrollTop) || 0;
		if (html && typeof(html.scrollTop) == 'number') {
			x = Math.max(x, html.scrollLeft);
			y = Math.max(y, html.scrollTop);
		} else if (typeof(window.pageYOffset) == 'number') {
			x = window.pageXOffset;
			y = window.pageYOffset;
		}
		return {x: x, y: y};
	}

	this.create = function(el, evt, inf, force) 
	{
		if( !el ) // as of right now, element is required
			return;

		oInfo = inf;
		if( !oInfo.css )
			oInfo.css = oCSS;
		oElement = el;
		timers.show = setTimeout( show, oInfo.showDelay );
		addEvent( el, 'mouseout', removeShow );
	}

	function removeShow()
	{
		if( timers.show )
		{
			clearTimeout( timers.show );
			timers.show = null;
		}
		delEvent( oElement, 'mouseout', removeShow );
	}

	function delEvent(el, evt, handler) {
		if (el.removeEventListener) {
			el.removeEventListener(evt, handler, false);
		} else if (el.detachEvent) {
			el.detachEvent('on' + evt, handler);
		}
	}

	function show()
	{
		removeShow(); // clear up this event
		Hide();
		oDiv.innerHTML = oInfo.html;
		oDiv.style.zIndex = oInfo.zIndex;
		if( oInfo.css && !document.getElementById( "divpopupcss" ) ) 
		{
			var lnk = document.createElement('link');
			lnk.rel = 'stylesheet';
			lnk.type = 'text/css';
			lnk.href = oInfo.css;
			lnk.id = "divpopupcss";
			document.getElementsByTagName('head')[0].appendChild(lnk);
		}
		var dX = 0;
		var dY = 0;
		var oElTmp = oElement;
		if( oInfo.origin == 'element' )
		{
			for( dX = 0, dY = 0; oElTmp; oElTmp = oElTmp.offsetParent) 
			{
					dX += oElTmp.offsetLeft;
					dY += oElTmp.offsetTop;
			}
		}
		else
		{
			// cursor ... I don't think this is working correctly in IE
			// TODO this is probably wrong
			var pos = GetMousePos( windows.event );
			dX = pos.x;
			dY = pos.y;
		}

		if( oInfo.position == "top-right" )
		{
			// I don't know how else to do this, flashing this forces it to render so i can get the size
			Display();
			var size = GetSize( oDiv );
			dX += 5;
			dY -= size.cy;
			dY -= 2;
			// hide it again
			Hide();
		}


		// this is currently rop-right and needs to be extended
		oDiv.style.left = dX + "px";
		oDiv.style.top = dY + "px";
		Display();
	}

	this.destroy = function()
	{
		removeShow();
		Hide();
	}

	function Display()
	{
		oDiv.style.visibility = 'visible';
		oDiv.style.display = '';
	}

	function Hide()
	{
		oDiv.style.visibility = 'hidden';
		oDiv.style.display = 'none';
	}



	function GetSize( el ) 
	{
		return {
			cx: Math.max(el.offsetWidth || 0, el.scrollWidth || 0),
			cy: Math.max(el.offsetHeight || 0, el.scrollHeight || 0)
		};
	}

	function addEvent(el, evt, handler) 
	{
		if (el.addEventListener) 
		{
			el.addEventListener(evt, handler, false);
		} 
		else if (el.attachEvent) 
		{
			el.detachEvent('on' + evt, handler);
			el.attachEvent('on' + evt, handler);
		}
	}

	addEvent(window, 'load', load);
}
