/*
 * Tooltip - jQuery plugin  for styled tooltips
 *
 * Copyright (c) 2006 Jörn Zaefferer, Stefan Petre
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 */

/*
 * adapted by Dieter Raber <raber@h2a.lu>
 * adapted by Claudia Kosny <kosny@h2a.lu>
 * changed tooltip structure
 * changed class depending on position
 * changed background image for alphafilter, this now needs a default pic
 *
 */

/**
 * Display a customized tooltip instead of the default one
 * for every selected element. The tooltip behaviour mimics
 * the default one, but lets you style the tooltip and
 * specify the delay before displaying it.
 *
 * In addition, it displays the href value, if it is available.
 *
 * To style the tooltip, use these selectors in your stylesheet:
 *
 * #tooltip - The tooltip container
 *
 * #tooltip div.tooltip_body - The tooltip body
 *
 * @example $('a, input, img').Tooltip();
 * @desc Shows tooltips for anchors, inputs and images, if they have a title
 *
 * @example $('label').Tooltip({
 *   delay: 0,
 *   track: true,
 *   event: "click"
 * });
 * @desc Shows tooltips for labels with no delay, tracking mousemovement, displaying the tooltip when the label is clicked.
 *
 * @example // modify global settings
 * $.extend($.fn.Tooltip.defaults, {
 * 	track: true,
 * 	delay: 0,
 *  fixPNG: true
 * });
 * // setup fancy tooltips
 * $('a.pretty').Tooltip({
 * 	 extraClass: "fancy"
 * });
 $('img.pretty').Tooltip({
 * 	 extraClass: "fancy-img",
 * });
 * @desc This example starts with modifying the global settings, applying them to all following Tooltips;
 * Afterwards, Tooltips for anchors with class pretty are created with an extra class for the
 * Tooltip: "fancy" for anchors, "fancy-img" for images
 *
 * @param Object settings (optional) Customize your Tooltips
 * @option Number delay The number of milliseconds before a tooltip is display, default is 250
 * @option String event The event on which the tooltip is displayed, default is "mouseover", "click" works fine, too
 * @option Boolean track If true, let the tooltip track the mousemovement, default is false
 * @option String extraClass If specified, adds the class to the tooltip helper, default is null
 * @option Boolean fixPNG If true, fixes transparent PNGs in IE, default is false
 *
 * @name Tooltip
 * @type jQuery
 * @cat Plugins/Tooltip
 * @author Jörn Zaefferer (http://bassistance.de)
 */
(function($) {

	// the tooltip element
	var helper,
		// it's body part, the text is shown in here
		tContent,
		// the current tooltipped element
		current,
		// the title of the current element, used for restoring
		oldTitle,
		// timeout id for delayed tooltips
		tID;

	// the public plugin method
	$.fn.Tooltip = function(settings) {
		// setup configuration
		// TODO: allow multiple arguments to extend, see bug #344
		settings = $.extend($.extend({}, arguments.callee.defaults), settings || {});

		// there can be only one tooltip helper
		if( !helper ) {
			// create the helper, h3 for title, div for url
			helper = $('<table id="tooltip"><tbody><tr><td class="tooltip_body"></td></tr></tbody></table>')
				// hide it at first
				.hide()
				// move to top and position absolute, to let it follow the mouse
				.css({ position: 'absolute', zIndex: 3000 })
				// add to document
				.appendTo('body');
			// save references
			tContent  = $('td.tooltip_body', helper);
		}

		// bind events for every selected element with a title attribute
		$(this).filter('[@title]')
			// save settings into each element
			// TODO: pass settings via event system, not yet possible
			.each(function() {
				this.tSettings = settings;
			})
			// bind events
			.bind("mouseover", save)
			.bind(settings.event, handle);
			
	  //store default backgroundImage path for Alpha in IE
	  helper.imagePath = '';
		if($.browser.msie){
			var image = helper.css('backgroundImage');
			if(image && image != 'none') {
			  image = image.substring(5, image.length - 2);
			  var pos = image.lastIndexOf('/');
			  if(pos > 0) {
			    image = image.substring(0, pos);
			  }
			  helper.imagePath = image;			  
			}
		}
		
		return this;
	};

	// main event handler to start showing tooltips
	function handle(event) {
		// show helper, either with timeout or on instant
		if( this.tSettings.delay )
			tID = setTimeout(show, this.tSettings.delay);
		else
			show();

		// if selected, update the helper position when the mouse moves
		if(this.tSettings.track)
			$('body').bind('mousemove', update);

		// update at least once
		update(event);

		// hide the helper when the mouse moves out of the element
		$(this).bind('mouseout', hide);
	}

	// save elements title before the tooltip is displayed
	function save() {
		// if this is the current source, or it has no title (occurs with click event), stop
		if(this == current || !this.title)
			return;
		// save current
		current = this;

		var source = $(this),
			settings = this.tSettings;

		// save title, remove from element and set to helper
		oldTitle = title = source.attr('title');
		source.attr('title','');
		tContent.html(title);

		// add an optional class for this tip
		if( settings.extraClass ) {
			helper.addClass(settings.extraClass);
		}
	}

	// delete timeout and show helper
	function show() {
		tID = null;
		//display invisible tooltip to compute the position
		//update will then set the visibility to visible
		helper.css('visibility', 'hidden').show();
		update();
	}

	/**
	 * callback for mousemove
	 * updates the helper position
	 * removes itself when no current element
	 */
	function update(event)	{
		// if no current element is available, remove this listener
		if( current == null ) {
			$('body').unbind('mousemove', update);
			return;
		}

		var left = helper[0].offsetLeft;
		var top = helper[0].offsetTop;
		
		if(event) {
			// get the current mouse position		
			function pos(c) {
				var p = c == 'X' ? 'Left' : 'Top';
				return event['page' + c] || (event['client' + c] + (document.documentElement['scroll' + p] || document.body['scroll' + p])) || 0;
			}
			// position the helper 15 pixel to bottom right, starting from mouse position
			left = pos('X') + 5;
			top = pos('Y') + 5;
						
			helper.css({
				left: left + 'px',
				top: top + 'px'
			});
		}

		var v = viewport(),
			  h = helper[0],
			  hDir = 'r',
			  vDir = 't';
		// check horizontal position
		if(v.x + v.cx < h.offsetLeft + h.offsetWidth) {
			left -= h.offsetWidth + 20;
			helper.css({left: left + 'px'});
			// bild nach links
			hDir = 'l';
		}

		// check vertical position
		if(v.y + v.cy < h.offsetTop + h.offsetHeight) {
			top -= h.offsetHeight + 20;
			helper.css({top: top + 'px'});
		}
		else{
			// bild nach unten
			vDir = 'b';
		}
	
		helper.removeClass('br tr bl tl').addClass(vDir + hDir);
		
		if($.browser.msie) {
		  //fetch image path to add alpha filter
		  var imagePath = '';
		  if(helper.imagePath) {
		    imagePath = helper.imagePath + '/' + vDir + hDir + '.png';
		    helper.css({
					  'backgroundImage': 'none',
					  'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + imagePath + "')"
		    });
		  }
		}
		helper.css('visibility', 'visible');
	}

	function viewport() {
		var e = document.documentElement || {},
			b = document.body || {},
			w = window;

		return {
			x: w.pageXOffset || e.scrollLeft || b.scrollLeft || 0,
			y: w.pageYOffset || e.scrollTop || b.scrollTop || 0,
			cx: min( e.clientWidth, b.clientWidth, w.innerWidth ),
			cy: min( e.clientHeight, b.clientHeight, w.innerHeight )
		};

		function min() {
			var v = Infinity;
			for( var i = 0;  i < arguments.length;  i++ ) {
				var n = arguments[i];
				if( n && n < v ) v = n;
			}
			return v;
		}
	}

	// hide helper and restore added classes and the title
	function hide() {
		// clear timeout if possible
		if(tID)
			clearTimeout(tID);
		// no more current element
		current = null;
		helper.hide();
		// remove optional class
		if( this.tSettings.extraClass ) {
			helper.removeClass( this.tSettings.extraClass);
		}

		// restore title and remove this listener
		$(this)
			.attr('title', oldTitle)
			.unbind('mouseout', hide);

		// remove PNG background fix for IE
		if( this.tSettings.fixPNG && $.browser.msie ) {
			helper.each(function () {
				$(this).css({'filter': '', backgroundImage: ''});
			});
		}
	}

	// define global defaults, editable by client
	$.fn.Tooltip.defaults = {
		delay: 250,
		event: "mouseover",
		track: false,
		extraClass: null,
		fixPNG: false
	};

})(jQuery);