(function ($) {

    $.fn.hovermenu = function (options) {
        if (this[0].hoverMenu && typeof (options) == "string") {
            if (options == "close") {
                this[0].hoverMenu.close.call(this[0].hoverMenu, arguments.length > 1 ? arguments[1] : false);
            }

            else if (options == "open") {
                this[0].hoverMenu.open.call(this[0].hoverMenu, arguments.length > 1 ? arguments[1] : false);
            }

            else if (options == "disable") {
                this[0].hoverMenu.disable.call(this[0].hoverMenu);
            }

            else if (options == "enable") {
                this[0].hoverMenu.enable.call(this[0].hoverMenu);
            }

            else if (options == "content") {
                if (this[0].hoverMenu.content) this[0].hoverMenu.content.hide();
                this[0].hoverMenu.content = arguments.length > 1 ? arguments[1] : null;
                this[0].hoverMenu.content.remove();
                this[0].hoverMenu.menu.append(this[0].hoverMenu.content);
                this[0].hoverMenu.content.css("display", "inherit");
                this[0].hoverMenu.content.show();
            }

            else if (options == "position") {
                if (arguments.length < 2) return;
                this[0].hoverMenu.options.position = arguments[1];
                this[0].hoverMenu.position.call(this[0].hoverMenu);
            }

            else if (options == "offset") {
                if (arguments.length < 2) return;
                this[0].hoverMenu.options.offset = arguments[1];
                this[0].hoverMenu.position.call(this[0].hoverMenu);
            }

            return;
        }

        var defaults = {
            position: {
                vertical: "top",
                horizontal: "middle"
            },
            offset: 0,
            fadeIn: 250,
            fadeOut: 250,
            openDelay: 0,
            closeDelay: 0,
            allowMenuFocus: true,
            attachTarget: null,
            autoClose: true
        };

        var options = $.extend(defaults, options);
        this[0].hoverMenu = new HoverMenu(this, options);
    };

    function HoverMenu(element, options) {
        // Add to global list
        if (typeof (hoverMenus) == "undefined") hoverMenus = [];
        hoverMenus.push(this);

        this.element = element;
        this.target = $(element);
        this.options = options;
        this.content = options.content;
        this.enabled = true;

        // No content, nothing to do
        if (!this.content) return;

        this.menu = $("<div></div>");
        this.menu.addClass("hovermenu");
        this.menu.css({ position: "absolute", display: "none", opacity: 0 });
        this.carrot = $("<div></div>");
        this.carrot.addClass("hovermenu-carrot");
        this.carrot.css({ position: "absolute", display: "none", opacity: 0 });
        this.content.remove();
        this.menu.append(this.content);
        this.content.css("display", "inherit");
        this.content.show();

        if (!this.options.attachTarget) {
            $(document.body).append(this.menu);
            $(document.body).append(this.carrot);
        }
        else {
            this.options.attachTarget.append(this.menu);
            this.options.attachTarget.append(this.carrot);
        }

        var self = this;

        this.target.mouseenter(function () {
            self.open();
        });

        this.target.mouseup(function () {
            if (self.menu.css("display") == "none" || self.menu.css("opacity") == 0) self.open();
            else self.close();
        });

        this.target.mouseleave(function () {
            self.close();
        });

        this.menu.mouseenter(function () {
            if (self.options.allowMenuFocus) {
                self.open();
            }
        });

        this.menu.mouseleave(function () {
            if (self.options.allowMenuFocus) {
                self.close();
            }
        });

        this.carrot.mouseenter(function () {
            if (self.options.allowMenuFocus) {
                self.open();
            }
        });

        this.carrot.mouseleave(function () {
            if (self.options.allowMenuFocus) {
                self.close();
            }
        });

        $(window).resize(function () {
            self.position();
        });
    }

    HoverMenu.prototype.position = function () {
        if (this.options.position.vertical == "top") {
            this.carrot.css("background-position", "0px 0px");

            if (!this.options.attachTarget) {
                this.menu.css("top", this.target.offset().top - this.menu.height() - this.options.offset);
                this.carrot.css("top", this.menu.offset().top + this.menu.height() + 2);
            }
            else {
                this.menu.css("top", -this.menu.height() - this.options.offset);
                this.carrot.css("top", this.menu.position().top + this.menu.height() + 2);
            }
        }
        else if (this.options.position.vertical == "bottom") {
            this.carrot.css("background-position", "0px -30px");

            if (!this.options.attachTarget) {
                this.menu.css("top", this.target.offset().top + this.target.height() + this.options.offset);
                this.carrot.css("top", this.menu.offset().top - this.carrot.height() / 2 + 2);
            }
            else {
                this.menu.css("top", this.options.attachTarget.height() + this.menu.height() + this.options.offset);
                this.carrot.css("top", this.menu.position().top - this.carrot.height() / 2 + 2);
            }
        }

        if (this.options.position.horizontal == "middle") {
            if (!this.options.attachTarget) {
                this.menu.css("left", this.target.offset().left + this.target.width() / 2 - this.menu.width() / 2);
                this.carrot.css("left", this.menu.offset().left + this.menu.width() / 2 - this.carrot.width() / 2);
            }
            else {
                this.menu.css("left", this.options.attachTarget.width() / 2 - this.menu.width() / 2);
                this.carrot.css("left", this.menu.position().left + this.menu.width() / 2 - this.carrot.width() / 2);
            }
        }

        if (this.menu.offset().left + this.menu.width() > $(document.body).width())
            this.menu.css("left", $(document.body).width() - this.menu.width() - 10);
    }

    HoverMenu.prototype.close = function (immediate) {
        if (!this.enabled) return;

        if (immediate) {
            this.menu.stop(true);
            this.carrot.stop(true);
            this.menu.hide();
            this.carrot.hide();
        }
        else {
            if (this.menu.css("display") == "none" || this.menu.css("opacity") == 0) return;
            this.menu.stop(true);
            this.carrot.stop(true);
            this.menu.delay(this.options.closeDelay).animate({ opacity: 0 }, this.options.fadeOut, 0, function () { $(this).hide() });
            this.carrot.delay(this.options.closeDelay).animate({ opacity: 0 }, this.options.fadeOut, 0, function () { $(this).hide() });
        }
    }

    HoverMenu.prototype.open = function (immediate) {
        if (!this.enabled) return;

        for (var i = 0; i < hoverMenus.length; i++) {
            if (hoverMenus[i] != this && hoverMenus[i].options.autoClose) {
                hoverMenus[i].close(true);
            }
        }

        if (immediate) {
            this.menu.stop(true);
            this.carrot.stop(true);
            this.menu.css("opacity", 1);
            this.menu.show();
            this.carrot.css("opacity", 1);
            this.carrot.show();
            this.position();
        }
        else {
            //if (this.menu.css("display") != "none") return;

            this.menu.show();
            this.carrot.show();
            this.position();

            this.menu.stop(true);
            this.carrot.stop(true);
            this.menu.delay(this.options.openDelay).animate({ opacity: 1 }, this.options.fadeIn);
            this.carrot.delay(this.options.openDelay).animate({ opacity: 1 }, this.options.fadeIn);
        }
    }

    HoverMenu.prototype.disable = function () {
        this.close(true);
        this.enabled = false;
    }

    HoverMenu.prototype.enable = function () {
        this.enabled = true;
    }
})(jQuery);
