/**
 * jQuery tooltip plugin
 *
 * Author: Johannes Wüller
 * Created On: 07.05.2010
 *
 * Usage:
 *    // If the title option is omitted, the plugin determines the title using
 *    // the title attribute of the given element. To omit any title, pass an
 *    // empty string to the title option.
 *    $("a[title!='']").tooltip(); 
 *
 *    // This adds the given title to all selected elements. You can pass a
 *    // function to determine a custom title. The function is called with the
 *    // context of the selected element and it should return a string to be
 *    // used as a title. The same thing is possible for the content-option.
 *    $("a").tooltip({
 *       title: "some title"
 *    });
 *    $("a").tooltip({
 *       title: function() {
 *          return $(this).find(".tooltip-content").html();
 *       }
 *    });
 *
 * Options (all optional):
 *    title          Title to be displayed in the tooltip. This can be a simple
 *                   html string, a dom-object, a jquery-object or a function
 *                   which returns one of the possibilities listed above (the
 *                   function gets called in the current element context). If
 *                   this option is omitted, the value is determined by the
 *                   content of the title-attribute of the current element.
 *    content        Content to be displayed in the tooltip. Works like the
 *                   title option but has no default value if its not set.
 *    classBase      Css-class to be prepended to every tooltip. Default:
 *                   "__cb-tooltip"
 *    fadeInSpeed    Speed (in milliseconds) at which the tooltip should fade in
 *                   after being triggered. Default: 200
 *    fadeInDelay    How long the cursor has to remain above the current element
 *                   before triggering the tooltip. Default: 500
 *    fadeOutSpeed   Speed (in milliseconds) at which the tooltip should fade
 *                   out after the cursor has moved. Default: 200
 *    wrapOffset     Minimum distance between the tooltip and the window border
 *                   that should be maintained before flipping the tooltip over
 *                   to the other side (horizontally as well as vertically).
 *                   Default: 20
 *    zIndex         Explicit z-index for the tooltip. Default: 1337
 */
(function() {

   jQuery.fn.tooltip = function(options) {
      // merge with default options
      options = jQuery.extend({
         title:        null,
         content:      null,
         classBase:    "__cb-tooltip",
         fadeInSpeed:  200,
         fadeInDelay:  500,
         fadeOutSpeed: 200,
         wrapOffset:   10,
         zIndex:       1337
      }, options || {});

      jQuery(this).each(function() {
         // use title tag value if nothing else is specified
         if (options.title === null) {
            options.title = function() {
               return jQuery(this).attr("title");
            };
         }
         
         // check if title or content attribute contains a function
         if (jQuery.isFunction(options.title)) {
            options.title = options.title.call(this);
         }
         if (jQuery.isFunction(options.content)) {
            options.content = options.content.call(this);
         }

         // make sure that we have null in case of an empty value
         if (options.title == "") {
            options.title = null;
         }
         if (options.content == "") {
            options.content = null;
         }

         // create tooltip div
         var tooltip = jQuery("<div></div>").addClass(options.classBase).css({
            position: "absolute",
            zIndex:   options.zIndex,
            opacity:  0
         }).hide();

         if (options.title !== null) {
            jQuery("<div></div>").addClass(options.classBase+"-title").html(options.title).appendTo(tooltip);
         }
         if (options.content !== null) {
            jQuery("<div></div>").addClass(options.classBase+"-content").html(options.content).appendTo(tooltip);
         }

         var fadeInTimeout = null;
         var isVisible = false;

         var removeTooltip = function() {
            if (isVisible) {
               isVisible = false;
               tooltip.stop().animate({
                  opacity: 0
               }, options.fadeOutSpeed, function() {
                  tooltip = tooltip.hide().detach();
               });
            }
            if (fadeInTimeout !== null) {
               window.clearTimeout(fadeInTimeout);
               fadeInTimeout = null;
            }
         };

         jQuery(this).mousemove(function(e) {
            removeTooltip();
            fadeInTimeout = window.setTimeout(function() {
               isVisible = true;
               var offsetTop = e.pageY + 1;
               var offsetLeft = e.pageX + 1;
               tooltip.stop().appendTo("body").show();
               if (offsetTop + tooltip.outerHeight(true) + options.wrapOffset > $(window).height() + jQuery("html, body")[0].scrollTop) {
                  offsetTop -= tooltip.outerHeight(true);
               }
               if (offsetLeft + tooltip.outerWidth(true) + options.wrapOffset > $(window).width() + jQuery("html, body")[0].scrollLeft) {
                  offsetLeft -= tooltip.outerWidth(true);
               }
               tooltip.css({
                  top:  offsetTop+"px",
                  left: offsetLeft+"px"
               }).animate({
                  opacity: 1
               }, options.fadeInSpeed);
            }, options.fadeInDelay);
         }).mouseleave(removeTooltip);
      });
   };
   
}());
