(function (f) {
    function p(a, b, c) {
        var h = c.relative ? a.position().top : a.offset().top,
            e = c.relative ? a.position().left : a.offset().left,
            i = c.position[0];
        h -= b.outerHeight() - c.offset[0];
        e += a.outerWidth() + c.offset[1];
        var j = b.outerHeight() + a.outerHeight();
        if (i == "center") h += j / 2;
        if (i == "bottom") h += j;
        i = c.position[1];
        a = b.outerWidth() + a.outerWidth();
        if (i == "center") e -= a / 2;
        if (i == "left") e -= a;
        return {
            top: h,
            left: e
        }
    }
    function t(a, b) {
        var c = this,
            h = a.add(c),
            e, i = 0,
            j = 0,
            m = a.attr("title"),
            q = n[b.effect],
            k, r = a.is(":input"),
            u = r && a.is(":checkbox, :radio, select, :button"),
            s = a.attr("type"),
            l = b.events[s] || b.events[r ? u ? "widget" : "input" : "def"];
        if (!q) throw 'Nonexistent effect "' + b.effect + '"';
        l = l.split(/,\s*/);
        if (l.length != 2) throw "Tooltip: bad events configuration for " + s;
        a.bind(l[0], function (d) {
            if (b.predelay) {
                clearTimeout(i);
                j = setTimeout(function () {
                    c.show(d)
                }, b.predelay)
            } else c.show(d)
        }).bind(l[1], function (d) {
            if (b.delay) {
                clearTimeout(j);
                i = setTimeout(function () {
                    c.hide(d)
                }, b.delay)
            } else c.hide(d)
        });
        if (m && b.cancelDefault) {
            a.removeAttr("title");
            a.data("title", m)
        }
        f.extend(c, {
            show: function (d) {
                if (!e) {
                    if (m) e = f(b.layout).addClass(b.tipClass).appendTo(document.body).hide().append(m);
                    else if (b.tip) e = f(b.tip).eq(0);
                    else {
                        e = a.next();
                        e.length || (e = a.parent().next())
                    }
                    if (!e.length) throw "Cannot find tooltip for " + a;
                }
                if (c.isShown()) return c;
                e.stop(true, true);
                var g = p(a, e, b);
                d = d || f.Event();
                d.type = "onBeforeShow";
                h.trigger(d, [g]);
                if (d.isDefaultPrevented()) return c;
                g = p(a, e, b);
                e.css({
                    position: "absolute",
                    top: g.top,
                    left: g.left
                });
                k = true;
                q[0].call(c, function () {
                    d.type = "onShow";
                    k = "full";
                    h.trigger(d)
                });
                g = b.events.tooltip.split(/,\s*/);
                e.bind(g[0], function () {
                    clearTimeout(i);
                    clearTimeout(j)
                });
                g[1] && !a.is("input:not(:checkbox, :radio), textarea") && e.bind(g[1], function (o) {
                    o.relatedTarget != a[0] && a.trigger(l[1].split(" ")[0])
                });
                return c
            }, hide: function (d) {
                if (!e || !c.isShown()) return c;
                d = d || f.Event();
                d.type = "onBeforeHide";
                h.trigger(d);
                if (!d.isDefaultPrevented()) {
                    k = false;
                    n[b.effect][1].call(c, function () {
                        d.type = "onHide";
                        k = false;
                        h.trigger(d)
                    });
                    return c
                }
            }, isShown: function (d) {
                return d ? k == "full" : k
            }, getConf: function () {
                return b
            }, getTip: function () {
                return e
            }, getTrigger: function () {
                return a
            }
        });
        f.each("onHide,onBeforeShow,onShow,onBeforeHide".split(","), function (d, g) {
            f.isFunction(b[g]) && f(c).bind(g, b[g]);
            c[g] = function (o) {
                f(c).bind(g, o);
                return c
            }
        })
    }
    f.tools = f.tools || {
        version: "1.2.2"
    };
    f.tools.tooltip = {
        conf: {
            effect: "toggle",
            fadeOutSpeed: "fast",
            predelay: 0,
            delay: 30,
            opacity: 1,
            tip: 0,
            position: ["top", "center"],
            offset: [0, 0],
            relative: false,
            cancelDefault: true,
            events: {
                def: "mouseenter,mouseleave",
                input: "focus,blur",
                widget: "focus mouseenter,blur mouseleave",
                tooltip: "mouseenter,mouseleave"
            }, layout: "<div/>",
            tipClass: "tooltip"
        }, addEffect: function (a, b, c) {
            n[a] = [b, c]
        }
    };
    var n = {
        toggle: [function (a) {
            var b = this.getConf(),
                c = this.getTip();
            b = b.opacity;
            b < 1 && c.css({
                opacity: b
            });
            c.show();
            a.call()
        }, function (a) {
            this.getTip().hide();
            a.call()
        }],
        fade: [function (a) {
            var b = this.getConf();
            this.getTip().fadeTo(b.fadeInSpeed, b.opacity, a)
        }, function (a) {
            this.getTip().fadeOut(this.getConf().fadeOutSpeed, a)
        }]
    };
    f.fn.tooltip = function (a) {
        var b = this.data("tooltip");
        if (b) return b;
        a = f.extend(true, {}, f.tools.tooltip.conf, a);
        if (typeof a.position == "string") a.position = a.position.split(/,?\s/);
        this.each(function () {
            b = new t(f(this), a);
            f(this).data("tooltip", b)
        });
        return a.api ? b : this
    }
})(jQuery);
