/* 
    
08-Jun-2011     SVL     Added option autoshow=false that allows tooltip to auto fade in
08-Jun-2011     SVL     Added options 'icon' and 'bgcolor' for more customization

*/

(function($) {
    $.fn.tipsy = function(options) {

        options = $.extend({}, $.fn.tipsy.defaults, options);

        return this.each(function() {

            var opts = $.fn.tipsy.elementOptions(this, options);
            if (opts.autoshow) {

                $.data(this, 'cancel.tipsy', true);

                var tip = $.data(this, 'active.tipsy');
                if (!tip) {
                    tip = $('<div class="tipsy"><div class="tipsy-close"></div><div class="tipsy-inner"/></div>');
                    tip.css({ position: 'absolute', zIndex: 100000 });
                    $.data(this, 'active.tipsy', tip);
                }

                if ($(this).attr('title') || typeof ($(this).attr('original-title')) != 'string') {
                    $(this).attr('original-title', $(this).attr('title') || '').removeAttr('title');
                }

                var title;
                if (typeof opts.title == 'string') {
                    title = $(this).attr(opts.title == 'title' ? 'original-title' : opts.title);
                } else if (typeof opts.title == 'function') {
                    title = opts.title.call(this);
                }

                tip.find('.tipsy-inner')[opts.html ? 'html' : 'text'](title || opts.fallback);
                if (opts.icon.length) {
                    tip.find('.tipsy-inner').css({ 'padding': '10px 13px 9px 36px', 'background': opts.bgcolor + ' url(Icons/' + opts.icon + ') no-repeat 2px center' });
                }
                else {
                    tip.find('.tipsy-inner').css({ 'padding': '5px', 'background': opts.bgcolor });
                }
                tip.css({ 'width': opts.maxwidth + 'px' });

                var pos = $.extend({}, $(this).offset(), { width: this.offsetWidth, height: this.offsetHeight });
                tip.get(0).className = 'tipsy'; // reset classname in case of dynamic gravity
                tip.remove().css({ top: 0, left: 0, visibility: 'hidden', display: 'block' }).appendTo(document.body);
                var actualWidth = tip[0].offsetWidth, actualHeight = tip[0].offsetHeight;
                var gravity = (typeof opts.gravity == 'function') ? opts.gravity.call(this) : opts.gravity;

                switch (gravity.charAt(0)) {
                    case 'n':
                        tip.css({ top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 }).addClass('tipsy-north');
                        break;
                    case 's':
                        tip.css({ top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 }).addClass('tipsy-south');
                        break;
                    case 'e':
                        tip.css({ top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth }).addClass('tipsy-east');
                        break;
                    case 'w':
                        tip.css({ top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }).addClass('tipsy-west');
                        break;
                }

                if (opts.fade) {
                    tip.css({ opacity: 0, display: 'block', visibility: 'visible' }).animate({ opacity: 0.8 });
                } else {
                    tip.css({ visibility: 'visible' });
                }

                tip.find(".tipsy-close").click(function() {
                    $(this).parent().fadeOut();
                });

            }
            else {

                $(this).hover(function() {

                    $.data(this, 'cancel.tipsy', true);

                    var tip = $.data(this, 'active.tipsy');
                    if (!tip) {
                        tip = $('<div class="tipsy"><div class="tipsy-inner"/></div>');
                        tip.css({ position: 'absolute', zIndex: 100000 });
                        $.data(this, 'active.tipsy', tip);
                    }

                    if ($(this).attr('title') || typeof ($(this).attr('original-title')) != 'string') {
                        $(this).attr('original-title', $(this).attr('title') || '').removeAttr('title');
                    }

                    var title;
                    if (typeof opts.title == 'string') {
                        title = $(this).attr(opts.title == 'title' ? 'original-title' : opts.title);
                    } else if (typeof opts.title == 'function') {
                        title = opts.title.call(this);
                    }

                    tip.find('.tipsy-inner')[opts.html ? 'html' : 'text'](title || opts.fallback);
                    if (opts.icon.length) {
                        tip.find('.tipsy-inner').css({ 'padding': '10px 13px 9px 36px', 'background': opts.bgcolor + ' url(Icons/' + opts.icon + ') no-repeat 2px center' });
                    }
                    else {
                        tip.find('.tipsy-inner').css({ 'padding': '5px', 'background': opts.bgcolor });
                    }
                    tip.css({ 'width': opts.maxwidth + 'px' });

                    var pos = $.extend({}, $(this).offset(), { width: this.offsetWidth, height: this.offsetHeight });
                    tip.get(0).className = 'tipsy'; // reset classname in case of dynamic gravity
                    tip.remove().css({ top: 0, left: 0, visibility: 'hidden', display: 'block' }).appendTo(document.body);
                    var actualWidth = tip[0].offsetWidth, actualHeight = tip[0].offsetHeight;
                    var gravity = (typeof opts.gravity == 'function') ? opts.gravity.call(this) : opts.gravity;

                    switch (gravity.charAt(0)) {
                        case 'n':
                            tip.css({ top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 }).addClass('tipsy-north');
                            break;
                        case 's':
                            tip.css({ top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 }).addClass('tipsy-south');
                            break;
                        case 'e':
                            tip.css({ top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth }).addClass('tipsy-east');
                            break;
                        case 'w':
                            tip.css({ top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }).addClass('tipsy-west');
                            break;
                    }

                    if (opts.fade) {
                        tip.css({ opacity: 0, display: 'block', visibility: 'visible' }).animate({ opacity: 0.8 });
                    } else {
                        tip.css({ visibility: 'visible' });
                    }

                }, function() {
                    $.data(this, 'cancel.tipsy', false);
                    var self = this;
                    setTimeout(function() {
                        if ($.data(this, 'cancel.tipsy')) return;
                        var tip = $.data(self, 'active.tipsy');
                        if (opts.fade) {
                            tip.stop().fadeOut(function() { $(this).remove(); });
                        } else {
                            tip.remove();
                        }
                    }, 100);

                });

            }            

        });

    };

    // Overwrite this method to provide options on a per-element basis.
    // For example, you could store the gravity in a 'tipsy-gravity' attribute:
    // return $.extend({}, options, {gravity: $(ele).attr('tipsy-gravity') || 'n' });
    // (remember - do not modify 'options' in place!)
    $.fn.tipsy.elementOptions = function(ele, options) {
        return $.metadata ? $.extend({}, options, $(ele).metadata()) : options;
    };

    $.fn.tipsy.defaults = {
        fade: false,
        fallback: '',
        gravity: 'n',
        html: false,
        title: 'title',
        autoshow: false,
        icon: '',
        bgcolor: '#000',
        maxwidth: 'auto'
    };

    $.fn.tipsy.autoNS = function() {
        return $(this).offset().top > ($(document).scrollTop() + $(window).height() / 2) ? 's' : 'n';
    };

    $.fn.tipsy.autoWE = function() {
        return $(this).offset().left > ($(document).scrollLeft() + $(window).width() / 2) ? 'e' : 'w';
    };

})(jQuery);

