
(function($) {
    $.fn.tip = function(options) {
        var settings = $.extend({}, $.fn.tip.defaults, options); if (settings.onHover) {
            if (settings.stickIfCurrent) {
                this.filter('.' + settings.currentClass).each(function(i)
                { $(this).createTip(settings); });
            }
            if (settings.reverseHover) {
                $(this).createTip(settings); this.hover(function() {
                    if (!settings.stickIfCurrent || !$(this).hasClass(settings.currentClass))
                    { $(this).hideTip(); } 
                }, function()
                { $(this).showTip(settings); });
            }
            else {
                this.hover(function()
                { $(this).showTip(settings); }, function() {
                    if (!settings.stickIfCurrent || !$(this).hasClass(settings.currentClass))
                    { $(this).hideTip(); } 
                });
            } 
        }
        else
        { this.createTip(settings); }
        return this;
    }; 
    $.fn.tip.defaults = { content: false, onHover: true, reverseHover: false, stickIfCurrent: false, currentClass: 'current', offset: 4, position: 'top', animationOffset: 4, delay: 0 }; 
    $.fn.showTip = function(options) {
        var settings = $.extend({}, $.fn.tip.defaults, options); this.each(function(i) {
            var element = $(this); var oldIE = ($.browser.msie && $.browser.version < 9); var tip = element.data('tip'); if (!tip)
            { element.createTip(settings, oldIE ? false : true); tip = element.data('tip'); }
            else if (settings.content !== element.data('settings').content)
            { element.updateTipContent(options.content); }
            if (!oldIE)
            { var position = getTipPosition(element, tip, settings, false); tip.stop(true).delay(settings.delay).animate({ opacity: 1, top: position.top, left: position.left }, 'fast'); } 
        }); return this;
    }; $.fn.hideTip = function() {
        this.each(function(i) {
            var element = $(this); var tip = element.data('tip'); if (tip) {
                var settings = element.data('settings'); if ($.browser.msie && $.browser.version < 9)
                { tip.children('.arrow').remove(); this.title = tip.html(); element.data('tip', false); tip.remove(); }
                else {
                    var position = getFinalPosition(tip, settings); var offset = tip.offset(); switch (position)
                    { case 'right': offset.left += settings.animationOffset + settings.offset; break; case 'bottom': offset.top += settings.animationOffset + settings.offset; break; case 'left': offset.left -= settings.animationOffset + settings.offset; break; default: offset.top -= settings.animationOffset + settings.offset; break; }
                    tip.animate({ opacity: 0, top: offset.top, left: offset.left }, { complete: function() {
                        var tip = $(this); var node = tip.data('node'); if (node)
                        { tip.children('.arrow').remove(); node.attr('title', tip.html()); node.data('tip', false); }
                        tip.remove();
                    } 
                    });
                } 
            } 
        }); return this;
    }; $.fn.createTip = function(settings, hide) {
        this.each(function(i) {
            var element = $(this); var tips = getTipDiv(); tips.append('<div></div>'); var tip = tips.children(':last-child'); if (settings.position == 'right' || element.hasClass('tip-right') || element.parent().hasClass('children-tip-right'))
            { tip.addClass('tip-right'); }
            else if (settings.position == 'bottom' || element.hasClass('tip-bottom') || element.parent().hasClass('children-tip-bottom'))
            { tip.addClass('tip-bottom'); }
            else if (settings.position == 'left' || element.hasClass('tip-left') || element.parent().hasClass('children-tip-left'))
            { tip.addClass('tip-left'); }
            tip.data('node', element); element.data('tip', tip); element.data('settings', settings); element.updateTipContent(settings.content, hide); if (hide)
            { tip.css({ opacity: 0 }); } 
        }); return this;
    }; $.fn.updateTipContent = function(content, hide) {
        this.each(function(i) {
            var element = $(this); var tip = element.data('tip'); var settings = element.data('settings'); if (!content) {
                if (this.title && this.title.length > 0)
                { var finalContent = this.title; this.title = ''; }
                else {
                    var subTitle = element.find('[title]:first'); if (subTitle.length > 0)
                    { var finalContent = subTitle.attr('title'); subTitle.attr('title', ''); }
                    else
                    { var finalContent = element.text(); } 
                } 
            }
            else
            { var finalContent = content; }
            if (!finalContent || $.trim(finalContent).length == 0)
            { finalContent = '<em>No tip</em>'; }
            tip.html(finalContent + '<span class="arrow"><span></span></span>'); tip.stop(true, true); var position = getTipPosition(element, tip, settings, hide); tip.offset(position);
        }); return this;
    }; $.fn.refreshTip = function() {
        this.each(function(i) {
            var settings = $(this).data('settings'); if (settings && settings.stickIfCurrent) {
                var element = $(this); if (element.hasClass(settings.currentClass))
                { element.showTip(settings); }
                else
                { element.hideTip(settings); } 
            } 
        }); return this;
    }; function getFinalPosition(tip, settings) {
        var position = settings.position; if (tip.hasClass('tip-right'))
        { position = 'right'; }
        else if (tip.hasClass('tip-bottom'))
        { position = 'bottom'; }
        else if (tip.hasClass('tip-left'))
        { position = 'left'; }
        return position;
    }
    function getTipPosition(element, tip, settings, animStart) {
        var offset = element.offset(); var position = getFinalPosition(tip, settings); switch (position)
        { case 'right': return { top: Math.round(offset.top + (element.outerHeight() / 2) - (tip.outerHeight() / 2)), left: Math.round(offset.left + element.outerWidth() + (animStart ? settings.animationOffset + settings.offset : settings.offset)) }; break; case 'bottom': return { top: Math.round(offset.top + element.outerHeight() + (animStart ? settings.animationOffset + settings.offset : settings.offset)), left: Math.round(offset.left + (element.outerWidth() / 2) - (tip.outerWidth() / 2)) }; break; case 'left': return { top: Math.round(offset.top + (element.outerHeight() / 2) - (tip.outerHeight() / 2)), left: Math.round(offset.left - tip.outerWidth() - (animStart ? settings.animationOffset + settings.offset : settings.offset)) }; break; default: return { top: Math.round(offset.top - tip.outerHeight() - (animStart ? settings.animationOffset + settings.offset : settings.offset)), left: Math.round(offset.left + (element.outerWidth() / 2) - (tip.outerWidth() / 2)) }; break; } 
    }
    if ($.fn.addTemplateSetup) {
        $.fn.addTemplateSetup(function()
        { this.find('.with-tip, .with-children-tip > *').tip(); });
    }
    else {
        $(document).ready(function()
        { $('.with-tip, .with-children-tip > *').tip(); });
    }
    function getTipDiv() {
        var tips = $('#tips'); if (tips.length == 0)
        { $(document.body).append('<div id="tips"></div>'); tips = $('#tips'); }
        return tips;
    }
    $(window).resize(function() {
        getTipDiv().children().each(function(i)
        { var tip = $(this); var element = tip.data('node'); var settings = element.data('settings'); var isCurrent = settings.stickIfCurrent && element.hasClass(settings.currentClass); var animate = (settings.onHover && !isCurrent); tip.stop(true, true); var position = getTipPosition(element, tip, settings, animate); tip.offset(position); });
    });
})(jQuery);
