/*
 * http://0x00ff00.com
 * 30-12-2009	v0.9	initial release
 */

var MARGIN = 20;
var PAD = 10;
var TOP_PAD = 5;
var BORDER_RADIUS = 8;
var DEFAULT_POINTER_SIZE = 10;
var IMAGE_PADDING_SIZE = 7;
var ANIMATION_SPEED = 200;
var ANIMATION_SPEED1 = 3500;
var CLASS_NAME = "infoBubble";
var zIndex = 90;
	

$.fn.makeInfoBubble = function(options) {
	// initialize options
	var defaults = { 
		imageSrc: "",
		preLoad: false,
		text: "",
		bgColor: "gray",
		fgColor: "white"
	};
	var options = $.extend(defaults, options);

	return this.each(function() {
		// image preload
		var image = new Image();
		if (options.imageSrc == "") {
			options.preLoad = false;
		}
		
		if (options.preLoad) {
			image.src = options.imageSrc;
		}
			
		
		// click behavior
		var clickedItem = $(this);
		clickedItem.mouseover(function() {	
			if (!clickedItem.next().hasClass(CLASS_NAME)) {  
				loadContent(clickedItem, options, image);  // called once
			} 			
				toggleShow(clickedItem, options, image);
			return true;
		});
		
			$(document).mouseover(function() {  // if showing, a click anywhere will close it
			if (clickedItem.next().hasClass(CLASS_NAME) && clickedItem.next().is(":visible")) {
				toggleShow(clickedItem, options, image);
			}
		});
	
	});
};


//create bubble and pointer elements, image is loaded later
function loadContent(clickedItem, options, image) {
	var isPreloaded = options.preLoad;
	var html = "<div><img/><span>"+options.text+"</span></div><div></div>";	
	clickedItem.after(html);
	
	if (isPreloaded) {
		clickedItem.next().children("img").attr("src", image.src);
	}
	
	var styleBubble = getStyleBubble(clickedItem, options);
	clickedItem.next().css(styleBubble);
	clickedItem.next().click(function() {
		toggleShow(clickedItem, options, image);
		return false;
	});
	
	var stylePointer = getStylePointer(clickedItem, options);
	clickedItem.next().next().css(stylePointer);
	clickedItem.next().next().click(function() {
		toggleShow(clickedItem, options, image);
		return false;
	});
	
	var styleImage = getStyleImage(options, isPreloaded);
	clickedItem.next().children("img").css(styleImage);
	
	clickedItem.next().addClass(CLASS_NAME);  // for style and acts as a content loaded flag
}


// show/hide bubble
function toggleShow(clickedItem, options, image) {
	if (clickedItem.next().is(":animated") || clickedItem.next().next().is(":animated")) {  // let current animation finish
		return;
	}
		
	if (clickedItem.next().is(":visible")) {  // hide it
		clickedItem.next().next().animate({"left" : "+="+(DEFAULT_POINTER_SIZE - 1)}, ANIMATION_SPEED1/3, 
			function() {
				clickedItem.next().next().css("display", "none");
				clickedItem.next().fadeOut(ANIMATION_SPEED1);
			}
		);
	} else {  // show it
		zIndex++;  // update zIndex so that it opens over already open popups
		clickedItem.next().css("zIndex", zIndex+1);
		clickedItem.next().next().css("zIndex", zIndex);
		
		var pos = clickedItem.position();
		var height = clickedItem.outerHeight(true);
		clickedItem.next().css("top", (pos.top + (height / 2))+"px");
		clickedItem.next().show(ANIMATION_SPEED, 
			function() {
				var bubbleHeight = clickedItem.next().outerHeight();
				var bubbleTop = clickedItem.next().position().top;
				var bubbleTopDelta = Math.min(bubbleTop - TOP_PAD, bubbleHeight / 2);  // don't go past top of page
				var pointerTop = parseInt(clickedItem.next().next().css("top").replace("px", ""));
				var bubbleDestinationTop = bubbleTop - bubbleTopDelta;

				if ((pointerTop - bubbleDestinationTop) < TOP_PAD) {
					bubbleTopDelta = bubbleHeight / 2;
				}
				
				clickedItem.next().animate({"top" : "-="+bubbleTopDelta}, ANIMATION_SPEED,
					function() {
						clickedItem.next().next().css("display", "block");
						clickedItem.next().next().animate({"left" : "-="+(DEFAULT_POINTER_SIZE - 1)}, ANIMATION_SPEED/3);
						loadImage(clickedItem, options, image);
					}
				);
			}
		);
	}
}



// image is loaded after bubble is displayed (gives smoother animation when image is not preloaded)
function loadImage(clickedItem, options, image) {
	if ((options.imageSrc != "") && !image.src) {
		image.onload = function() { 
			showImage(clickedItem, options, image);
		};
		image.src = options.imageSrc;
	}
}


// after image is loaded, show it
function showImage(clickedItem, options, image) {
	var styleImage = getStyleImage(options, false);
	var paddingSize = IMAGE_PADDING_SIZE;
	if (options.text == "") {
		paddingSize = 0;
	}
	
	clickedItem.next().children("img").css(styleImage);
	clickedItem.next().children("img").attr("src", image.src);
	clickedItem.next().children("img").animate( 
		{"height" : image.height+"px", 
		"paddingBottom" : paddingSize+"px", 
		"paddingTop" : "0",
		"paddingRight" : "0",
		"paddingLeft" : "0"}, 
		ANIMATION_SPEED);
	
	var bubbleTop = clickedItem.next().position().top;
	var bubbleTopDelta = Math.min(bubbleTop - TOP_PAD, image.height / 2);  // don't go past top of page
	clickedItem.next().animate({"top" : "-="+bubbleTopDelta}, ANIMATION_SPEED);
}


function getStyleBubble(clickedItem, options) {
	var pos = clickedItem.position();
	var width = clickedItem.outerWidth();
	var styleBubble = {
		"position" : "absolute",
		"left" : (pos.left + width + MARGIN),
		"display" : "none",
		"padding" : PAD+"px",
		"margin" : "0px",
		"-moz-border-radius" : BORDER_RADIUS+"px",
	    "-webkit-border-radius" : BORDER_RADIUS+"px",
		"backgroundColor" : options.bgColor,
		"color" : options.fgColor
	};
	return styleBubble;
}


function getStylePointer(clickedItem, options) {
	var pos = clickedItem.position();
	var width = clickedItem.outerWidth();
	var height = clickedItem.outerHeight(true);
	var pointerSize = DEFAULT_POINTER_SIZE;
	var bgColor = "rgba(0, 0, 0, 0)";

	if ($.browser.msie) {  // IE does not support rgba, in this case, no transparent pointer background
		bgColor = $("body").css("backgroundColor");
	}
	
	var stylePointer = {
		"position" : "absolute",
		"top" : pos.top - pointerSize + (height / 2),
		"left" : (pos.left + width + MARGIN),
		"width" : 0,
		"height" : 0,
		"display" : "none",
		"borderWidth" : pointerSize + "px",
		"borderLeftWidth" : 0,
		"borderStyle" : "solid",
		"borderColor" : bgColor,
		"borderRightColor" : options.bgColor
	};
	return stylePointer;
}


function getStyleImage(options, isPreloaded) {
	var styleImage = {
		"display" : "block",
		"padding" : "0 0 "+IMAGE_PADDING_SIZE+"px 0",
		"margin" : "0"
	};
	
	if (isPreloaded) {
		if (options.text == "") {
			styleImage.padding = "0";
		}
	} else {
		styleImage.height = "0px";
		if (options.text == "") {
			styleImage.padding = PAD+"px";
		} else {
			styleImage.padding = "0";
		}
	}
	
	return styleImage;
}
