bubble = {

	followMouse:false,
	offX:16,
	offY:8,
	bubbleID:"bubbleDiv",
	showDelay:100,
	hideDelay:300,
	hideOnMouseOut:true,
	ready:false,
	timer:null,
	viewport:{},
	bWin:null,
	bArrow:null,
	bContent:null,
	iframeShim:null,
	onClose:null,

	init:function() {
		var b = document.createElement('div');
		b.id = this.bubbleID;
		b.innerHTML = '<div id="bubbleContent"><div id="bubbleLoading"><\/div><\/div><div id="bubbleArrow"><\/div>';
		$('body').append(b);
		this.bWin = $("div#" + this.bubbleID).addClass("bubbleTopLeft");
		this.bContent = $("div#bubbleContent");
		this.bArrow = $("div#bubbleArrow");

		/* IE 6 BUG - CREATE IFRAME SHIM TO KEEP SELECT BOXES FROM SHOWING THROUGH THE BUBBLE */
		if (navigator.userAgent.indexOf('MSIE 6') != -1) {
			$('<iframe id="bubbleDivShim" src="Javascript:false;" scrolling="no" frameborder="0"><\/iframe>').appendTo('body');
			this.iframeShim = $('iframe#bubbleDivShim');
		}
	},

	show:function(e, content) {
		/* DON'T LET A PREVIOUS TIMER TIMEOUT THIS NEW WINDOW */
		if (this.timer) { this.clearTimer(); }

		/* POPULATE THE DIV */
		if (content) { this.populate(content); }

		/* GET VIEWPORT */
		this.viewport = this.getViewport();

		/* POSITION THE DIV */
		this.position(e);

		/* HIDE ON MOUSEOUT */
		if (this.hideOnMouseOut) {
			this.clearTimer();
			this.bWin.bind("mouseover", function() { bubble.clearTimer(); }).hover(
				function() { bubble.clearTimer(); }, function() { bubble.hide(); }
			);
		}

		/* MAKE THE DIV VISIBLE AFTER DELAY */
		this.timer = setTimeout(function() {
			bubble.bWin.css('visibility', 'visible');
			if (bubble.iframeShim) { bubble.iframeShim.css('display', 'block'); }
		}, this.showDelay);
	},

	showLoading:function(e) {
		this.populateLoading();
		this.show(e);
	},

	populateLoading:function() {
		var content = '<div id="bubbleLoading"><\/div>';
		this.populate(content);
	},

	hide:function() {
		if (this.timer) { this.clearTimer(); }
		this.timer = setTimeout(function() {
			if (bubble.iframeShim) { bubble.iframeShim.css('display', 'none'); }
			bubble.bWin.css({visibility:'hidden',left:'-1000px'});
		}, this.hideDelay);
	},

	clearTimer:function() {
		if (this.timer) {
			clearTimeout(this.timer);
			this.timer = 0;
		}
	},

	populate:function(c) {
		this.bContent.html(c);

		/* BIND EVENT TO CLOSE BUTTON */
		$('div#bubbleClose').click( function() {
			if (bubble.iframeShim) { bubble.iframeShim.css('display', 'none'); }
			bubble.bWin.css({visibility:'hidden',left:'-1000px'});
			if (typeof(bubble.onClose) == 'function') { bubble.onClose(); }
		} );
	},

	position:function(e) {

		if (!e) { var e = window.event; }

		/* GET THE FLOATING WINDOW ELEMENT */
		var elem = this.bWin.get(0);

		var arrowElem = this.bArrow.get(0);

		/* INITIALLY, SET LEFT AND TOP POSITION TO THE MOUSE CLICK */
		var clickLeft = e.pageX ? e.pageX : e.clientX;
		var clickTop = e.pageY ? e.pageY : e.clientY;
		var left = clickLeft;
		var top = clickTop;

		/* GIVE THE ELEMENT A DEFAULT CLASS SO THE DIMENSIONS WILL BE CORRECT */
		var corner = "TopLeft";

		/* IF CONTENT IS TOO WIDE TO FIT BETWEEN THE MOUSE CLICK AND RIGHT SIDE OF THE BROWSER... */
		if (left + elem.offsetWidth + this.offX > this.viewport.width + this.viewport.scrollLeft) {

			/* POSITION IT TO THE LEFT OF THE CLICK
			if (left - elem.offsetWidth - this.offX > 0) {
				left = left - elem.offsetWidth - this.offX;
				corner = "TopRight";
			} */

			left = left - elem.offsetWidth - this.offX;
			corner = "TopRight";

			/* IF CONTENT IS POSITIONED PASSED THE LEFT EDGE OF THE BROWSER, REPOSITION IT */
			if (left < 0) { left = 0; }

		/* IF CONTENT WILL FIT TO THE RIGHT SIDE OF THE MOUSE CLICK... */
		} else {
			left = left + this.offX;
		}

		/* IF CONTENT IS TOO TALL TO BE POSITIONED BELOW THE MOUSE CLICK */
		if (top + elem.offsetHeight + this.offY > this.viewport.height + this.viewport.scrollTop) {

			/* POSITION IT ABOVE THE CLICK */
			top = top - elem.offsetHeight - this.offY;
			corner = corner.replace("Top", "Bottom");

			/* IF CONTENT IS POSITIONED ABOVE THE TOP EDGE OF THE BROWSER, REPOSITION IT */
			if (top < this.viewport.scrollTop) {
				top = this.viewport.scrollTop + this.offY;
			}

		/* IF THE CONTENT WILL FIT BELOW THE MOUSE CLICK */
		} else {
			top = top + this.offY;
		}

		/* POSITION THE ARROW */
		var clickFromTop = clickTop - top;
		if (clickFromTop < elem.offsetHeight / 2) {
			if (clickFromTop < top) { clickFromTop = 3; }
		} else {
			if (clickFromTop + arrowElem.offsetHeight > elem.offsetHeight) {
				clickFromTop = elem.offsetHeight - arrowElem.offsetHeight - 3;
			} else {
				clickFromTop = clickFromTop - 63;
			}
		}
		this.bArrow.css("top", clickFromTop + "px");

		if (left == 0 && clickLeft < 400) {
			this.bArrow.css("display", "none");
		}

		/* SET THE POSITION */
		elem.className = "bubble" + corner;
		this.bWin.css({
			left: left + "px",
			top: top + "px"
		});

		/* IF THERE IS AN IFRAME (FOR IE BUG) POSITION IT AS WELL */
		if (this.iframeShim) {
			$('iframe#bubbleDivShim').css({ left: left + "px", top: top + "px" });
		}

	},

	getViewport:function(e) {

		/* GET WINDOW WIDTH AND HEIGHT */
		var height, width, scrollTop, scrollLeft, de;
		if (e) {
			width = e.clientWidth;
			height = e.clientHeight;
		} else {
			de = document.documentElement;
			width = window.innerWidth || self.innerWidth || (de&&de.clientWidth) || document.body.clientWidth;
			height = window.innerHeight || self.innerHeight || (de&&de.clientHeight) || document.body.clientHeight;
		}

		/* GET SCROLL X AND Y */
		if (e && e.nodeName.toLowerCase() != 'body') {
			scrollTop = e.scrollTop;
			scrollLeft = e.scrollLeft;
		} else  {
			if (document.documentElement && document.documentElement.scrollTop) {
				scrollTop = document.documentElement.scrollTop;
				scrollLeft = document.documentElement.scrollLeft;
			} else if (document.body) {
				scrollTop = document.body.scrollTop;
				scrollLeft = document.body.scrollLeft;
			}
		}

		return { height:height, width:width, scrollTop:scrollTop, scrollLeft:scrollLeft };
	}

}
