/*
 * jQuery New Tooltip plugin 0.1
 * 
 * last modified: 2008-10-19
 *
 * http://jamadam.com/blog/
 *
 * Copyright (c) 2008 Sugama Keita
 * 
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 */
;(function($) {
	
	// the tooltip element
	var div_array   = [];
	// IE 5.5 or 6
	var IE          =
        $.browser.msie && /MSIE\s(5\.5|6\.)/.test(navigator.userAgent);
	var track       = false;
	var status      = null;
    var ajax_cache  = [];
    
	$.tooltip = {
		defaults: {
            in_json     : false,
            auto        : true,
            handler_on  : 'mouseover',
            handler_off : 'mouseout',
            track		: true,
			fade		: 200,
			top			: 15,
			left		: 15,
			id			: "TOOLTIP",
            auto_css    : true,
            css         : {
                'position'        : 'absolute',
                'z-index'         : '3000',
                'padding'         : '5px',
                //'width'           : '30em',
                'padding'         : '10px',
                'font-size'       : '12px',
                'font-family'     : 'monospace, Courier New, "Osaka－等幅"',
                'border'          : '1px solid #678',
                'background'      : '#abc',
                'opacity'         : '0.95',
                'color'           : '#222'
            }
		}
	};
    
	$.extend({
        
		tooltip_setup: function(settings) {
            
            settings = settings ? settings : {};
			
			settings.css =
                $.tooltip.defaults.css =
                    $.extend({}, $.tooltip.defaults.css, settings.css);
            
			settings =
                $.tooltip.defaults = $.extend({}, $.tooltip.defaults, settings);
			
            if (settings.auto) {
                
                return $('[title]').each(function() {
                    
					var local_settings =
						(settings.in_json)
							? $.extend({}, settings, eval('tmp=' + this.title))
							: settings;
					
                    var original_title  = this.title;
                    var original_alt    = this.alt;
                    
                    $(this).bind(local_settings.handler_on, function () {
                        
                        this.title  = null;
                        this.alt    = null;
                        
                        if (local_settings.in_json) {
                            
                            $(this).tooltip_open(
                                $.extend({},
                                    local_settings,
                                    {in_json: false}
                                )
                            );
                        }
                        
                        else {
                            
                            $(this).tooltip_open({text: original_title});
                        }
                    });
                    
                    $(this).bind(local_settings.handler_off, function () {
                        
                        this.title  = original_title;
                        this.alt    = original_alt;
                        
                        $(this).tooltip_close();
                    });
                });
            }
            
			return this;
		}
    });
    
	$.fn.extend({
		
		tooltip_open: function(settings) {
			
            settings = settings ? settings : {};
			settings.css = $.extend({}, $.tooltip.defaults.css, settings.css);
            
			settings =
                $.extend(
                    {}, $.tooltip.defaults,
                    settings
                );
            
            function get_handler() {
                
                return get_handler.caller.caller.arguments;
            }
            
            var handler = get_handler();
            
			return this.each(function() {
				
                text =
                    settings.in_json
                        ? eval('tmp=' + settings.text)
                        : settings.text;
                
                settings = $.extend({}, settings, {text: text});
                
                if (! div_array[settings.id]) {
                    
                    div_array[settings.id] =
                        $('<div id="' + settings.id + '"></div>')
                        .appendTo(document.body)
                        .hide();
                    
                    if (settings.auto_css) {
                        
                        div_array[settings.id].css(settings.css);
                    }
                }
                
                // apply bgiframe if available
                if ($.fn.bgiframe) {
                    
                    div_array[settings.id].bgiframe();
                }
                
    			$.data(this, 'newtooltip', settings);
                
                open(this);
                
                $(this).bind('mousemove', update);
                
                update.apply(this, handler);
            });
		},
		
		tooltip_close: function () {
			
			return this.each(function() {
                
    			if ($.data(this, 'newtooltip')) {
                    
        			close(this);
                }
            });
		},
		
		fixPNG: IE
			? function() {
				
				return this.each(function () {
                    
					var image = $(this).css('backgroundImage');
					if (image.match(/^url\(["']?(.*\.png)["']?\)$/i)) {
						
						image = RegExp.$1;
						$(this).css({
							'backgroundImage': 'none',
							'filter':
								"progid:" +
								"DXImageTransform.Microsoft.AlphaImageLoader" +
								"(enabled=true, sizingMethod=crop, src='" +
								image +
								"')"
						}).each(function () {
							
							var position = $(this).css('position');
							
							if (position != 'absolute'
                                && position != 'relative') {
								
								$(this).css('position', 'relative');
							}
						});
					}
				});
			}
			: function() {
                
                return this;
            },
		
		unfixPNG: IE
			? function() {
                
				return this.each(function () {
                    
					$(this).css({'filter': '', backgroundImage: ''});
				});
			}
			: function() {
                
                return this;
            }
	});
	
	function settings(element) {
		
		return $.data(element, "newtooltip");
	}
	
	function divobj(element) {
		
		return div_array[$.data(element, "newtooltip").id];
	}
	
	// save elements title before the tooltip is displayed
	function open(obj) {
        
        status = true;
        
        if (divobj(obj).is(":animated")) {
            
            divobj(obj).stop().css('opacity', '');
        }
		
        var fix_open = function() {
            
            if (status == true) {
                
                if ((!IE || !$.fn.bgiframe) && settings(obj).fade) {
                    
                    divobj(obj).fadeIn(settings(obj).fade);
                }
                
                else {
                    
                    divobj(obj).show();
                }
            }
        }
		
        // Ajax
		if (settings(obj).url) {
            
            if (settings(obj).url in ajax_cache
                && ! ajax_cache[settings(obj).url]) {
                
                return; // Other proccess exists
            }
            
            if (ajax_cache[settings(obj).url]) {
                
                divobj(obj).html(ajax_cache[settings(obj).url]);
                fix_open();
            }
            
            else {
                
                ajax_cache[settings(obj).url] = '';
                
                // Get outer html file
                divobj(obj).load(settings(obj).url, function () {
                    
                    ajax_cache[settings(obj).url] = divobj(obj).html();
                    
                    fix_open();
                });
            }
		}
		
		else if (settings(obj).text) {
			
			divobj(obj).html(settings(obj).text);
            fix_open();
		}
        
        // fix PNG background for IE
        if (settings(obj).fixPNG) {
            
            divobj(obj).fixPNG();
        }
        
        // if selected, update the div_array position when the mouse moves
        track = !!settings(obj).track;
	}
	
	/**
	 * callback for mousemove
	 * updates the div_array position
	 * removes itself when no current element
	 */
	function update(event)	{
        
		if (event && event.target.tagName == "OPTION") {
            
            return;
		}
		
		// stop updating when tracking is disabled and the tooltip is visible
		if ( !track && divobj(this).is(":visible")) {
			
			$(this).unbind('mousemove', update);
		}
        
		// remove position div_array classes
		divobj(this)
            .removeClass("viewport-right").removeClass("viewport-bottom");
		
		var left    = divobj(this)[0].offsetLeft;
		var top     = divobj(this)[0].offsetTop;
        
		if (event) {
            
            // position the div_array 15 pixel to bottom right,
            // starting from mouse position
            left = event.pageX + settings(this).left;
            top = event.pageY + settings(this).top;
            
            var right = 'auto';
            
            if (settings(this).positionLeft) {
                
                right = $(window).width() - left;
                left = 'auto';
            }
            
            divobj(this).css({
                
                left:  left,
                right: right,
                top:   top
            });
		}
		
		var v = viewport();
		var h = divobj(this)[0];
		
		// check horizontal position
		if (v.x + v.cx < h.offsetLeft + h.offsetWidth) {
			
			left -= h.offsetWidth + 20 + settings(this).left;
            
			divobj(this).css({left: left + 'px'}).addClass("viewport-right");
		}
		
		// check vertical position
		if (v.y + v.cy < h.offsetTop + h.offsetHeight) {
			
			top -= h.offsetHeight + 20 + settings(this).top;
            
			divobj(this).css({top: top + 'px'}).addClass("viewport-bottom");
		}
	}
	
	function viewport() {
		
		return {
			x: $(window).scrollLeft(),
			y: $(window).scrollTop(),
			cx: $(window).width(),
			cy: $(window).height()
		};
	}
	
	// hide div_array and restore added classes and the title
	function close(obj) {
		
        status = false;
		
		var close_fix = function () {
            
            if (status == false) {
                
                divobj(obj)
                    .removeClass(settings(obj).extraClass)
                    .hide()
                    .css("opacity", "")
                    .empty();
                
                if (settings(obj).fixPNG) {
                    
                    divobj(obj).unfixPNG();
                }
            }
		}
		
		if ((!IE || !$.fn.bgiframe) && settings(obj).fade) {
			
			divobj(obj).stop().fadeOut(settings(obj).fade, close_fix);
		}
		
		else {
			
			close_fix();
		}
	}
	
})(jQuery);
