/*
 * Copyright (c) 2006 Jonathan Weiss <jw@innerewut.de>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */


/* tooltip-0.2.js - Small tooltip library on top of Prototype 
 * by Jonathan Weiss <jw@innerewut.de> distributed under the BSD license. 
 *
 * This tooltip library works in two modes. If it gets a valid DOM element 
 * or DOM id as an argument it uses this element as the tooltip. This 
 * element will be placed (and shown) near the mouse pointer when a trigger-
 * element is moused-over.
 * If it gets only a text as an argument instead of a DOM id or DOM element
 * it will create a div with the classname 'tooltip' that holds the given text.
 * This newly created div will be used as the tooltip. This is usefull if you 
 * want to use tooltip.js to create popups out of title attributes.
 * 
 *
 * Usage: 
 *   <script src="/javascripts/prototype.js" type="text/javascript"></script>
 *   <script src="/javascripts/tooltip.js" type="text/javascript"></script>
 *   <script type="text/javascript">
 *     // with valid DOM id
 *     var my_tooltip = new Tooltip('id_of_trigger_element', 'id_of_tooltip_to_show_element')
 *
 *     // with text
 *     var my_other_tooltip = new Tooltip('id_of_trigger_element', 'a nice description')
 *
 *     // create popups for each element with a title attribute
 *    Event.observe(window,"load",function() {
 *      $$("*").findAll(function(node){
 *        return node.getAttribute('title');
 *      }).each(function(node){
 *        new Tooltip(node,node.title);
 *        node.removeAttribute("title");
 *      });
 *    });
 *    
 *   </script>
 * 
 * Now whenever you trigger a mouseOver on the `trigger` element, the tooltip element will
 * be shown. On o mouseOut the tooltip disappears. 
 * 
 * Example:
 * 
 *   <script src="/javascripts/prototype.js" type="text/javascript"></script>
 *   <script src="/javascripts/scriptaculous.js" type="text/javascript"></script>
 *   <script src="/javascripts/tooltip.js" type="text/javascript"></script>
 *
 *   <div id='tooltip' style="display:none; margin: 5px; background-color: red;">
 *     Detail infos on product 1....<br />
 *   </div>
 *
 *   <div id='product_1'>
 *     This is product 1
 *   </div>
 *
 *   <script type="text/javascript">
 *     var my_tooltip = new Tooltip('product_1', 'tooltip')
 *   </script>
 *
 * You can use my_tooltip.destroy() to remove the event observers and thereby the tooltip.
 */

var Tooltip = Class.create();
Tooltip.prototype = {

  initialize: function(element, tooltipElement, options) {
  
    this.element = $(element);
    this.options = {
      offsetX: 5,
      offsetY: 5,
      offsetFromElement: false,
      offsetPosition: 'top left',
      cssClass: 'tooltip',
      zindex: 1500
    };
    
    for (option in options) {
      this.options[option] = options[option];
    }
    
    // use the supplied tooltip element or create our own div
    if($(tooltipElement)) {
      this.tooltipElement = $(tooltipElement);
    } else {
      this.tooltipElement = $(document.createElement("div")); 
      document.body.appendChild(this.tooltipElement);
      this.tooltipElement.addClassName(this.options.cssClass);
      this.tooltipElement.appendChild(document.createTextNode(tooltipElement));
    }

    // hide the tooltip by default
    this.tooltipElement.hide();
    this.tooltipElement.setStyle({overflow:'auto'});
    this.eventMouseOver = this.showTooltip.bindAsEventListener(this);
    this.eventMouseOut   = this.hideTooltip.bindAsEventListener(this);
    this.eventMouseMove  = this.moveTooltip.bindAsEventListener(this);
    this.registerEvents();
  },

  destroy: function() {
    Event.stopObserving(this.element, "mouseover", this.eventMouseOver);
    Event.stopObserving(this.element, "mouseout", this.eventMouseOut);
    Event.stopObserving(this.element, "mousemove", this.eventMouseMove);
  },

  registerEvents: function() {
    Event.observe(this.element, "mouseover", this.eventMouseOver);
    Event.observe(this.element, "mouseout", this.eventMouseOut);
    Event.observe(this.element, "mousemove", this.eventMouseMove);
  },

  moveTooltip: function(event){

	  Event.stop(event);

    var positionX;
    var positionY;
    var dimensions;
    
	  // decide if wee need to switch sides for the tooltip
	  if (this.options.offsetFromElement) {

	    var offset = Element.cumulativeOffset(this.element);
	    positionX = offset.left;
	    positionY = offset.top;
	    var dimensions = Element.getDimensions(this.element);
	    var elementWidth = dimensions.width;
	    var elementHeight = dimensions.height;
	    if (this.options.offsetPosition.search(/right/i) >= 0) positionX += elementWidth;
	    if (this.options.offsetPosition.search(/bottom/i) >= 0) positionY += elementHeight;
	    positionX += this.options.offsetX;
	    positionY += this.options.offsetY;

    }
    else {
    
      positionX = Event.pointerX(event);
	    positionY = Event.pointerY(event);
	    dimensions = Element.getDimensions(this.tooltipElement);
	    var tooltipWidth = dimensions.width;
	    var tooltipHeight = dimensions.height;
  	  	
	    if ((tooltipWidth + positionX) >= (this.getWindowWidth() - this.options.offsetX)) { // too big for X
		    positionX = positionX - tooltipWidth;
		    // apply min_distance to make sure that the mouse is not on the tool-tip
		    positionX = positionX - this.options.offsetX;
	    } else {
		    positionX = positionX + this.options.offsetX;
	    }
  	
	    if ((tooltipHeight + positionY) >= (this.getWindowHeight() - this.options.offsetY)) { // too big for Y
		    positionY = positionY - tooltipHeight;
	      // apply min_distance to make sure that the mouse is not on the tool-tip
		    positionY = positionY - this.options.offsetY;
	    } else {
		    positionY = positionY + this.options.offsetY;
	    } 
  	
	    // move down if above viewport
	    var viewportYOffset = document.viewport.getScrollOffsets()['top'];
	    if (positionY < viewportYOffset) positionY = viewportYOffset + 10;
	  	
	  }

	  // now set the right styles
	  this.setPosition(positionX, positionY);
  },
	
  setPosition: function(x, y) {
    // set the right styles to position the tool tip
	  Element.setStyle(this.tooltipElement, {
	    position: 'absolute',
	    top:y + "px",
	    left:x + "px",
	    zindex: this.options.zindex
	  });
  },

  showTooltip: function(event) {
    Event.stop(event);
    this.moveTooltip(event);
    if (Element.appear)
      new Element.appear(this.tooltipElement, {duration:.5});
    else
      new Element.show(this.tooltipElement);
  },
  
  hideTooltip: function(event){
    if (Element.fade)
      new Element.fade(this.tooltipElement, {duration:.5});
    else
      new Element.hide(this.tooltipElement);
  },

  getWindowHeight: function(){
    var innerHeight;
	  if (navigator.appVersion.indexOf('MSIE')>0) {
		  innerHeight = document.body.clientHeight;
    } else {
		  innerHeight = window.innerHeight;
    }
    return innerHeight;	
  },
 
  getWindowWidth: function(){
    var innerWidth;
	  if (navigator.appVersion.indexOf('MSIE')>0) {
		  innerWidth = document.body.clientWidth;
    } else {
		  innerWidth = window.innerWidth;
    }
    return innerWidth;	
  }

}
  
function createTooltips(options) {
  var elements = $$('*');
  for (e in elements) {
    if (elements[e].hasAttribute('tooltip')) {
      new Tooltip(elements[e], elements[e].readAttribute('tooltip'), options);
    }
  }
}