;(function($) {
	/**
	* @name jToolTip
	* @class
	* @version 0.5
	* @requires jQuery Version
	* @param {Object} oOptions The Plugin options for this collection of elements
	*/
$.fn.jToolTip = function(oOptions) {
  var opts = $.extend({}, $.fn.jToolTip.defaults, oOptions);
	var self = $(this);
	var o = opts;
	var b = $(o.box);
	var p = $(o.root);
	var c = $(o.content);
	var w = $(o.contentWrapper);
	var bWidth = b.innerWidth();
	var bHeight = b.innerHeight();
	var xMax = 0;
	var xMin = 0;
	var yMin = 0;
	var yMax = 0;
	
	var getMaximumPositions = function () {
		var xMax = p.width() - bWidth + p.scrollLeft();
		var yMax = p.height() - bHeight + p.scrollTop();
		var max = {x: (xMax < 0)?0:xMax, y: (yMax < 0)?0:yMax};
		if (arguments.length) {
			if (arguments[0] == "x") {
				return max.x;
			} else if (arguments[0] == "y") {
				return max.y;
			}
		}
		return {x: (xMax < 0)?0:xMax, y: (yMax < 0)?0:yMax};
	};
	
	// handle the align and offset options
	var setOffset = function (elm) {
		var offset = {};
		switch (o.align.x) {
			case 'center':
			offset.x = -(b.innerWidth() / 2 - elm.innerWidth() / 2) + o.offset.x;
			break;
			
			case 'right':
			offset.x = -(b.innerWidth() - elm.innerWidth()) + o.offset.x;
			break;
			
			case 'toright':
			offset.x = elm.innerWidth() + o.offset.x;
			break;
			
			case 'toleft':
			offset.x = -b.innerWidth() - o.offset.x;
			break;
			
			default: // left
			offset.x = -o.offset.x;
			break;
		}
		
		switch (o.align.y) {
			case 'middle':
			offset.y = -(bHeight/2 - elm.innerHeight()/2) + o.offset.y;
			break;
			
			case 'top':
			offset.y = -o.offset.y;
			break;
			
			case 'over':
			offset.y = -bHeight - o.offset.y;
			break;
			
			case 'below':
			offset.y = elm.innerHeight() + o.offset.y;
			break;
			
			default: // bottom
			offset.y = -(bHeight - elm.innerHeight()) + o.offset.y;
			break;
		}
		return offset;
	};
	
  return this.each(function(iIndex, oElement) {
		var wDim = null;
		var bDim = null;
    var $this = $(this);
		var src = $($this.attr("rel"));
		var offset = 0;
		
	  // calculate if the bubble is within the bounds of our root element
		var setPosition = function (dim) {
			var x = dim.left + offset.x;
			var y = dim.top + offset.y;
			var pos_x = Math.floor((x < xMax) ? ((x > p.scrollLeft()) ? x : p.scrollLeft()) : xMax);
			var pos_y = Math.floor((y < yMax) ? ((y > p.scrollTop()) ? y : p.scrollTop()): yMax);
			return {left: pos_x, top: pos_y};
		};
		
		var guessDimensions = function () {
			var dim = {width: 0, height: 0};
			wDim = {};
			bDim = {};

			b.css({"visibility":"hidden", top: 0, left: 0}).show();
			dim.height = b.outerHeight();
			dim.width = b.outerWidth();
			wDim.outerHeight = w.outerHeight();
			wDim.outerWidth = w.outerWidth();
			wDim.innerHeight = w.innerHeight();
			wDim.innerWidth = w.innerWidth();
			wDim.height = w.height();
			wDim.width = w.width();
			bDim.outerHeight = b.outerHeight();
			bDim.outerWidth = b.outerWidth();
			bDim.innerHeight = b.innerHeight();
			bDim.innerWidth = b.innerWidth();
			bDim.height = b.height();
			bDim.width = b.width();
			b.css({"visibility": "", top: "", left: ""}).hide();
			return dim;
		};
		
		var setScroll = function () {
			// reset height
			w.css({height: "", overflowY: "visible"});
			if (bDim.outerHeight > o.maxHeight) {
				w.css({height: o.maxHeight - (bDim.outerHeight - bDim.height), overflowY: "scroll"});
				return true;
			} else {
				return false;
			}
		};
		
		var intersects = function (pos) {
			var pos_a = $this.offset();
      var pos_b = pos;

      var top1 = pos_a.top;
      var left1 = pos_a.left;
      var right1 = left1 + $this.outerWidth();
      var bottom1 = top1 + $this.outerHeight();
      var top2 = pos_b.top;
      var left2 = pos_b.left;
      var right2 = left2 + bDim.outerWidth;
      var bottom2 = top2 + bDim.outerHeight;
      var getSign = function(v) {
          if(v > 0) return "1";
          else if(v < 0) return "-1";
          else return 0;
      }

      if ((getSign(top1 - bottom2) != getSign(bottom1 - top2)) &&
              (getSign(left1 - right2) != getSign(right1 - left2)))
          return true;
      return false;
		}
		
		var handleMouseOver = function () {
			var pos = {};
			// first set the content
			
			c.html(src.html());
			// if no hight was defined yet, define it now
			guessDimensions();
            
			var hasScroll = setScroll();
			bHeight = guessDimensions().height;
			offset = setOffset($this);
			// set the maximum positions for this tooltip
			xMax = getMaximumPositions("x");
			yMax = getMaximumPositions("y");
			
			pos = setPosition($this.offset());
			if (hasScroll || intersects(pos))  {
				b.bind("mouseleave", handleMouseOut);
			}	else {
				$this.bind("mouseleave", handleMouseOut);
			}
			
			
			b.stop(true, true).css(pos).fadeIn();
		};

		var handleMouseOut = function (evt) {
			b.fadeOut();
			$(evt.target).unbind("mouseleave", handleMouseOut);
		};
		
		$this.bind("mouseenter", handleMouseOver);
		
  });
	// end instance members
};
// end jToolTip

/**
 * default options
 */
$.fn.jToolTip.defaults = {
  align: { x: "center", y: "middle" },
	box: "#toolTip",
	content: "#toolTipContent",
	contentWrapper: "#innerToolTip",
	continous: false,
	maxHeight: 200,
	offset: { x: 0, y: 0 },
	root: $(window)
};

})(jQuery);
