/*
 * Copyright (c) 2006 Jonathan Weiss <jw@innerewut.de>
 * Modified by InterFriendship GmbH
 *
 * 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.
 */

/* Based on tooltip-0.1.js - Small tooltip library on top of Prototype 
 * by Jonathan Weiss <jw@innerewut.de> distributed under the BSD license. 
 *
 * ========================================================================
 * 
 * Usage in InterFriendship-Templates:
 * {toolTipBoxStart id="tt_myTip" title="Test"}Test-Text{toolTipBoxEnd} 
 * <img src="info.gif" class="tooltip" id="i_myTip" />
 * 
 * Auto-initialization! 
 * (Requires identical ids with prefixes "i_" and "tt_" and class "tooltip")
 * 
 * ========================================================================
 * 
 * Original usage:
 *   <script src="/javascripts/prototype.js" type="text/javascript"></script>
 *   <script src="/javascripts/tooltip.js" type="text/javascript"></script>
 *   <script type="text/javascript">
 *     var my_tooltip = new Tooltip('id_of_trigger_element', 'id_of_tooltip_to_show_element')
 *   </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 ToolTipZIndexCounter = 0;

var Tooltip = Class.create();
Tooltip.prototype = {
  initialize: function(element, tool_tip) {
    var options = Object.extend({
      space: 10,
      paddingBottom: 20,
      paddingRight: 20,
      zIndex: 1000      
    }, arguments[1] || {});

    this.element      = $(element);
    this.tool_tip     = $(tool_tip);

    this.options      = options;
    this.ttisvisible  = false;
    this.fadeOutTimer = null;
    this.fadeInTimer = null;
    
	bodyElem = document.getElementsByTagName("body");
	bodyElem[0].appendChild( this.tool_tip.parentNode.removeChild(this.tool_tip) );
    
    // hide the tool-tip by default
    this.tool_tip.hide();
   
    $(element)._toolTipObj = this;
    $(element).repositionToolTip = function() { $(element)._toolTipObj.reposition(); };
    $(element).showToolTip = function(hideOthers) { $(element)._toolTipObj.showTooltip(hideOthers); };
    $(element).hideToolTip = function(quickMode) { $(element)._toolTipObj.doHideTooltip(quickMode); };
    $(element).alwaysHideOtherToolTips = false;
    $(element).noAutoHideToolTip = false;

    this.eventMouseOver 	= function() { $(element).showToolTip() };
    this.eventMouseOut  	= function() { $(element)._toolTipObj.hideTooltip() };
    this.eventMouseOverTT   = function() { $(element).showToolTip() };
    this.eventMouseOutTT   	= function() { $(element)._toolTipObj.hideTooltip() };
    
    this.registerEvents();
  },

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

  registerEvents: function() {
    Event.observe(this.element, "mouseover", this.eventMouseOver);
    Event.observe(this.element, "mouseout", this.eventMouseOut);
  },
  
  reposition: function() {
	 if (this.ttisvisible) this.doShowTooltip(false, true);
  },

  showTooltip: function(hideOthers) {		
    if (this.fadeOutTimer != null) {
    	window.clearTimeout(this.fadeOutTimer);
    	this.fadeOutTimer = null;
    }
    
    if (this.ttisvisible) this.doShowTooltip(hideOthers);
    else if ( this.fadeInTimer == null ) {
    	// Tooltip wird noch nicht angezeigt und Timer läuft noch nicht
    	this.fadeInTimer = window.setTimeout("$('" + this.element.id + "')._toolTipObj.doShowTooltip("
    		+ (hideOthers ? 'true' : 'false')
    		+ ")", 750);
    }
    
  },
  
  doShowTooltip: function(hideOthers, forceReposition) {
	if ( this.fadeInTimer != null ) {
    	window.clearTimeout(this.fadeInTimer);
    	this.fadeInTimer = null;		
	}
    
    // Andere verstecken?
    if ( (hideOthers != undefined && hideOthers == true) 
    	|| (this.element.alwaysHideOtherToolTips != undefined && this.element.alwaysHideOtherToolTips == true) 
    ) {
    	elemID = this.tool_tip.id;
    	$$(".tooltip").each( function(e) {
    		if ( e.hideToolTip && (e._toolTipObj.tool_tip.id != elemID) ) e.hideToolTip(true);
    		}
    	);
    }
    
    ToolTipZIndexCounter++;
    this.tool_tip.setStyle({'zIndex' : (this.options.zIndex+ToolTipZIndexCounter)});

    if (this.ttisvisible && (forceReposition == undefined || forceReposition != true)) return;
    this.ttisvisible = true;
	
	var ttDimensions = Element.getDimensions( this.tool_tip );
	var tt_width = ttDimensions.width;
	var tt_height = ttDimensions.height;
    var elemPos = this.element.cumulativeOffset();
    var elemDimensions = Element.getDimensions( this.element );
	var element_width = elemDimensions.width;
	var element_height = elemDimensions.height;
	
	// ****** Decide where to place the tooltip *****
    
    // Default: Right of Box
    var mouse_x = elemPos.left + element_width + this.options.space;
	var mouse_y = elemPos.top - 6;
	
	// Layout column near current position?
	if ( mouse_x % 200 > 175 ||  mouse_x % 200 < 25) mouse_x = Math.round( mouse_x / 200 ) * 200 + 10;
	
	var offset_y = 0;
	var offset_x = 0;
	
	// Check window height
	if ( mouse_y + tt_height > this.getScrollY() + this.getWindowHeight() - this.options.paddingBottom ) {
		offset_y = this.getScrollY() + this.getWindowHeight() - tt_height - mouse_y - this.options.paddingBottom;
	}
	if (mouse_y + offset_y < 0 ) offset_y = 0-mouse_y;
	
	// Check window width
	var xOffset = 0;
	if (navigator.appVersion.indexOf('MSIE')>0) xOffset=10;
	if ( mouse_x + tt_width > this.getScrollX() + this.getWindowWidth() - this.options.paddingRight + xOffset) {
		offset_x = this.getScrollX() + this.getWindowWidth() - tt_width - mouse_x - this.options.paddingRight + xOffset;
	}
	if (mouse_x + offset_x < 0 ) offset_x = 0-mouse_x;
	
	// Overlap?
	if (this.overLapping(mouse_x + offset_x, mouse_y + offset_y, elemPos.left, elemPos.top)) {		
		var solved=false;
		
		// Try to put it left from the element
		if (! solved) {		
			tmp = elemPos.left - tt_width - this.options.space - mouse_x;
			if (mouse_x + tmp < 0) tmp = 0-mouse_x;
			if ( mouse_x + tmp < this.getScrollX() ) tmp = this.getScrollX(); 
			if (! this.overLapping(mouse_x + tmp, mouse_y + offset_y, elemPos.left, elemPos.top)) {
				offset_x = tmp;
				solved=true;
			}
		}
		
		// Try to put it Top of the element
		if (! solved) {		
			tmp = elemPos.top - tt_height - this.options.space - mouse_y;
			if (offset_y + tmp < 0) tmp = 0-offset_y;
			if ( offset_y + tmp < this.getScrollY() ) tmp = this.getScrollY();
			if (! this.overLapping(mouse_x + offset_x, mouse_y + tmp, elemPos.left, elemPos.top)) {
				offset_y = tmp;
				solved=true;
			}
		}
		
	}
	
	// now set the right styles
	mouse_x = mouse_x + offset_x;
	mouse_y = mouse_y + offset_y;
	this.setStyles(mouse_x, mouse_y);
	
    Event.observe(this.tool_tip, "mouseover", this.eventMouseOverTT);
    Event.observe(this.tool_tip, "mouseout", this.eventMouseOutTT);
		
	// finally show the Tooltip
	new Effect.Appear(this.tool_tip, { duration: 0.4 } );	
  },
  
  overLapping: function(x1, y1, x2, y2) {
	var ttDimensions = Element.getDimensions( this.tool_tip );
	var w1 = ttDimensions.width;
	var h1 = ttDimensions.height;
    var elemDimensions = Element.getDimensions( this.element );
	var w2 = elemDimensions.width;
	var h2 = elemDimensions.height;

	  if ( y2 + h2 < y1 || y1 + h1 < y2 ||  x2 + w2 < x1 || x1 + w1 < x2 ) return false;   
	  else return true;
  },
  
  setStyles: function(x, y){
    // set the right styles to position the tool tip
	Element.setStyle(this.tool_tip, { position:'absolute',
	 								  top:y + "px",
	 								  left:x + "px",
									  zindex:this.options.zindex
	 								});
	
  },

  hideTooltip: function(event){
	if ( this.fadeInTimer != null ) {
    	window.clearTimeout(this.fadeInTimer);
    	this.fadeInTimer = null;		
	}    
	if ( this.ttisvisible == false) return;
    if ( this.fadeOutTimer != null) {
    	window.clearTimeout(this.fadeOutTimer);
    	this.fadeOutTimer = null;
    }
    
    if (this.element.noAutoHideToolTip != undefined && this.element.noAutoHideToolTip == true) return;
    
    this.fadeOutTimer = window.setTimeout("$('" + this.element.id + "')._toolTipObj.doHideTooltip()", 1000);
  },
  
  doHideTooltip: function(quickMode){	  
	  this.ttisvisible = false;

	if ( this.fadeInTimer != null ) {
	   	window.clearTimeout(this.fadeInTimer);
	   	this.fadeInTimer = null;		
	}    
	  if ( quickMode != undefined && quickMode == true ) {
		  $(this.tool_tip).hide();
	  } else {
		  new Effect.Fade(this.tool_tip, { duration: 0.4 } );
	  }
	  if (this.fadeOutTimer != null) {
	    	window.clearTimeout(this.fadeOutTimer);
	    	this.fadeOutTimer = null;			  
	  }
	  Event.stopObserving(this.tool_tip, "mouseover", this.eventMouseOverTT);
	  Event.stopObserving(this.tool_tip, "mouseout", this.eventMouseOutTT);	  
  },
  
  getWindowHeight: function(){
    var innerHeight;
	if (navigator.appVersion.indexOf('MSIE')>0) {
		if (document.documentElement && document.documentElement.clientHeight) innerHeight = document.documentElement.clientHeight;  
		else innerHeight = document.body.clientHeight;
    } else {
		innerHeight = window.innerHeight;
    }
    return innerHeight;	
  },
 
  getWindowWidth: function(){
    var innerWidth;
	if (navigator.appVersion.indexOf('MSIE')>0) {
		if (document.documentElement && document.documentElement.clientWidth) innerWidth = document.documentElement.clientWidth;
		else innerWidth = document.body.clientWidth;
    } else {
		innerWidth = window.innerWidth;
    }
    return innerWidth;	
  },
  
  getScrollX: function() {
	  var iebody=(document.compatMode && document.compatMode != "BackCompat")? document.documentElement : document.body;
	  return document.all? iebody.scrollLeft : pageXOffset;
  },
	
  getScrollY: function() {
	  var iebody=(document.compatMode && document.compatMode != "BackCompat")? document.documentElement : document.body;
	  return document.all? iebody.scrollTop : pageYOffset;
  }
}