var g_BubbleRect = null; //[x,y,x2,y2] of item with bubble attribute under cursor.
var g_BubbleLink = null; //URL of script returning bubble contents.
var g_BubbleItem = null;
var g_BubbleDiv = null;

function MouseInBubbleRect() {
	if(g_BubbleRect == null)
		return false;
	return (MouseX > g_BubbleRect[0]-3 && MouseX < g_BubbleRect[2]+3 && MouseY > g_BubbleRect[1]-3 && MouseY < g_BubbleRect[3]+3);
}

//If mouse is inside g_BubbleHoverRect, then show g_BubbleLink.
function TryShowBubble(x,y,x2,y2) {
	if(g_BubbleRect == null)
		return;
	if(x != g_BubbleRect[0] || y != g_BubbleRect[1] || x2 != g_BubbleRect[2] || y2 != g_BubbleRect[3])
		return;
	
	if(MouseInBubbleRect())
		ShowBubble(g_BubbleLink);
}

function KillBubble() {
	if(g_BubbleDiv != null) {
		g_BubbleDiv.parentNode.removeChild(g_BubbleDiv);
		g_BubbleDiv = null;
	}
}

$(function() {
	SetBubbleEvents('body');
	
	$(window).mousemove(function() {
		if(g_BubbleRect == null)
			return;
		if(!MouseInBubbleRect())
			KillBubble();
	});
});


function SetBubbleEvents(RootFilter) {
	$(RootFilter+' *[bubble]').mouseover(function() {
		KillBubble();
	
		g_BubbleItem = this;
		g_BubbleLink = this.getAttribute('bubble');
		
		var pos = FindPos(this);
		g_BubbleRect = [pos[0], pos[1], pos[0]+this.offsetWidth, pos[1]+this.offsetHeight];
	
		if(this.getAttribute('nodelay'))
			setTimeout('TryShowBubble('+g_BubbleRect+');', 1);
		else
			setTimeout('TryShowBubble('+g_BubbleRect+');', 500);
	}).mouseout(function() {
		KillBubble();
	});
}

/*************************************/

var g_BubbleRequest;
function ShowBubble(url) {
	g_BubbleRequest = CreateRequester();
	if(g_BubbleRequest == null)
		return;
	
	g_BubbleItem.style.cursor = 'wait';
	
	g_BubbleRequest.open("GET", url);
	g_BubbleRequest.onreadystatechange = BubbleRequestDone;
	g_BubbleRequest.send(null);
}

function BubbleRequestDone(e) {
	if(g_BubbleRequest.readyState == 4) {
		if(g_BubbleRequest.status == 200 || g_BubbleRequest.status == 304) {
			KillBubble();
			var div = document.createElement('div');
			div.className = 'bubble';
			div.innerHTML = g_BubbleRequest.responseText;
			div.style.display='none';
			
			document.body.appendChild(div);
			
			g_BubbleDiv = div;
			
			//If the response includes a WaitDisplay comment, then the loaded div
			//will call FinalDisplayBubble() itself (e.g. after loading an image).
			if(g_BubbleRequest.responseText.indexOf('<!--WaitDisplay-->') == -1)
				FinalDisplayBubble();
		}
		else {
			//Failure.
			if(g_BubbleItem != null)
				g_BubbleItem.style.cursor = '';
		}
	}
}

function FinalDisplayBubble() {
	if(g_BubbleItem != null)
		g_BubbleItem.style.cursor = '';

	if(!MouseInBubbleRect()) {
		KillBubble();
		return;
	}
	
	var div = g_BubbleDiv;
	if(div == null)
		return;
	
	div.style.left='-10000px';
	div.style.top='-10000px';
	div.style.display='block';
	
	//Automatically set the width of the div to match its
	//widest contents.
	div.style.width='45em';
	var widest = div.offsetWidth;
	
	var maxwidth = 0;
	for(var i = 0; i < div.childNodes.length; i++) {
		if(div.childNodes[i].offsetWidth > maxwidth)
			maxwidth = div.childNodes[i].offsetWidth;
	}
	if(maxwidth > widest)
		maxwidth = widest;
	if(maxwidth > 0)
		div.style.width=maxwidth+'px';
	
	//Put it in a position where it is completely visible, if possible.
	var pos = [MouseX, MouseY];
	var size = GetFrameSize();
	var bottom = size[1] + GetScrollTop();
	var right = size[0] + GetScrollLeft();
	
	if(MouseX > right - div.clientWidth-40 && MouseX > div.clientWidth)
		div.style.left = (pos[0]-div.clientWidth-20)+"px";
	else
		div.style.left = (pos[0]+20)+"px";
	
	if(MouseY > bottom - div.clientHeight-40 && MouseY > div.clientHeight)
		div.style.top = (pos[1]-div.clientHeight-20)+"px";
	else
		div.style.top = (pos[1]+20)+"px";
}