/*
 * jQuery UI Menubar @VERSION
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Menubar
 *
 * Depends:
 *    jquery.ui.core.js
 *    jquery.ui.widget.js
 *    jquery.ui.position.js
 *    jquery.ui.menu.js
 */
(function( $ ) {

    // TODO when mixing clicking menus and keyboard navigation, focus handling is broken
    // there has to be just one item that has tabindex
    $.widget( "ui.menubar", {
        version: "@VERSION",
        options: {
            autoExpand: false,
            buttons: false,
            items: "li",
            menuElement: "ul",
            menuIcon: false,
            position: {
                my: "left top",
                at: "left bottom"
            }
        },
        _create: function() {
            var that = this;
            this.menuItems = this.element.children( this.options.items );
            this.items = this.menuItems.children( "button, a" );

            this.menuItems
                .addClass( "ui-menubar-item" )
                .attr( "role", "presentation" );
            // let only the first item receive focus
            this.items.slice(1).attr( "tabIndex", -1 );

            this.element
                .addClass( "ui-menubar ui-widget-header ui-helper-clearfix" )
                .attr( "role", "menubar" );
            this._focusable( this.items );
            this._hoverable( this.items );
            this.items.siblings( this.options.menuElement )
                .menu({
                    position: {
                        within: this.options.position.within
                    },
                    select: function( event, ui ) {
                        ui.item.parents( "ul.ui-menu:last" ).hide();
                        that._close();
                        // TODO what is this targetting? there's probably a better way to access it
                        $(event.target).prev().focus();
                        that._trigger( "select", event, ui );
                    },
                    menus: that.options.menuElement
                })
                .hide()
                .attr({
                    "aria-hidden": "true",
                    "aria-expanded": "false"
                })
            // TODO use _on
                .bind( "keydown.menubar", function( event ) {
                    var menu = $( this );
                    if ( menu.is( ":hidden" ) ) {
                        return;
                    }
                    switch ( event.keyCode ) {
                    case $.ui.keyCode.LEFT:
                        that.previous( event );
                        event.preventDefault();
                        break;
                    case $.ui.keyCode.RIGHT:
                        that.next( event );
                        event.preventDefault();
                        break;
                    }
                });
            this.items.each(function() {
                var input = $(this),
                // TODO menu var is only used on two places, doesn't quite justify the .each
                menu = input.next( that.options.menuElement );

                // might be a non-menu button
                if ( menu.length ) {
                    // TODO use _on
                    input.bind( "click.menubar focus.menubar mouseenter.menubar", function( event ) {
                        // ignore triggered focus event
                        if ( event.type === "focus" && !event.originalEvent ) {
                            return;
                        }
                        event.preventDefault();
                        // TODO can we simplify or extractthis check? especially the last two expressions
                        // there's a similar active[0] == menu[0] check in _open
                        if ( event.type === "click" && menu.is( ":visible" ) && that.active && that.active[0] === menu[0] ) {
                            that._close();
                            return;
                        }
                        if ( ( that.open && event.type === "mouseenter" ) || event.type === "click" || that.options.autoExpand ) {
                            if( that.options.autoExpand ) {
                                clearTimeout( that.closeTimer );
                            }

                            that._open( event, menu );
                        }
                    })
                    // TODO use _on
                        .bind( "keydown", function( event ) {
                            switch ( event.keyCode ) {
                            case $.ui.keyCode.SPACE:
                            case $.ui.keyCode.UP:
                            case $.ui.keyCode.DOWN:
                                that._open( event, $( this ).next() );
                                event.preventDefault();
                                break;
                            case $.ui.keyCode.LEFT:
                                that.previous( event );
                                event.preventDefault();
                                break;
                            case $.ui.keyCode.RIGHT:
                                that.next( event );
                                event.preventDefault();
                                break;
                            }
                        })
                        .attr( "aria-haspopup", "true" );

                    // TODO review if these options (menuIcon and buttons) are a good choice, maybe they can be merged
                    if ( that.options.menuIcon ) {
                        input.addClass( "ui-state-default" ).append( "<span class='ui-button-icon-secondary ui-icon ui-icon-triangle-1-s'></span>" );
                        input.removeClass( "ui-button-text-only" ).addClass( "ui-button-text-icon-secondary" );
                    }
                } else {
                    // TODO use _on
                    input.bind( "click.menubar mouseenter.menubar", function( event ) {
                        if ( ( that.open && event.type === "mouseenter" ) || event.type === "click" ) {
                            that._close();
                        }
                    });
                }

                input
                    .addClass( "ui-button ui-widget ui-button-text-only ui-menubar-link" )
                    .attr( "role", "menuitem" )
                    .wrapInner( "<span class='ui-button-text'></span>" );

                if ( that.options.buttons ) {
                    input.removeClass( "ui-menubar-link" ).addClass( "ui-state-default" );
                }
            });
            that._on( {
                keydown: function( event ) {
                    if ( event.keyCode === $.ui.keyCode.ESCAPE && that.active && that.active.menu( "collapse", event ) !== true ) {
                        var active = that.active;
                        that.active.blur();
                        that._close( event );
                        active.prev().focus();
                    }
                },
                focusin: function( event ) {
                    clearTimeout( that.closeTimer );
                },
                focusout: function( event ) {
                    that.closeTimer = setTimeout( function() {
                        that._close( event );
                    }, 150);
                },
                "mouseleave .ui-menubar-item": function( event ) {
                    if ( that.options.autoExpand ) {
                        that.closeTimer = setTimeout( function() {
                            that._close( event );
                        }, 150);
                    }
                },
                "mouseenter .ui-menubar-item": function( event ) {
                    clearTimeout( that.closeTimer );
                }
            });

            // Keep track of open submenus
            this.openSubmenus = 0;
        },

        _destroy : function() {
            this.menuItems
                .removeClass( "ui-menubar-item" )
                .removeAttr( "role" );

            this.element
                .removeClass( "ui-menubar ui-widget-header ui-helper-clearfix" )
                .removeAttr( "role" )
                .unbind( ".menubar" );

            this.items
                .unbind( ".menubar" )
                .removeClass( "ui-button ui-widget ui-button-text-only ui-menubar-link ui-state-default" )
                .removeAttr( "role" )
                .removeAttr( "aria-haspopup" )
            // TODO unwrap?
                .children( "span.ui-button-text" ).each(function( i, e ) {
                    var item = $( this );
                    item.parent().html( item.html() );
                })
                    .end()
                .children( ".ui-icon" ).remove();

            this.element.find( ":ui-menu" )
                .menu( "destroy" )
                .show()
                .removeAttr( "aria-hidden" )
                .removeAttr( "aria-expanded" )
                .removeAttr( "tabindex" )
                .unbind( ".menubar" );
        },

        _close: function() {
            if ( !this.active || !this.active.length ) {
                return;
            }
            this.active
                .menu( "collapseAll" )
                .hide()
                .attr({
                    "aria-hidden": "true",
                    "aria-expanded": "false"
                });
            this.active
                .prev()
                .removeClass( "ui-state-active" )
                .removeAttr( "tabIndex" );
            this.active = null;
            this.open = false;
            this.openSubmenus = 0;
        },

        _open: function( event, menu ) {
            // on a single-button menubar, ignore reopening the same menu
            if ( this.active && this.active[0] === menu[0] ) {
                return;
            }
            // TODO refactor, almost the same as _close above, but don't remove tabIndex
            if ( this.active ) {
                this.active
                    .menu( "collapseAll" )
                    .hide()
                    .attr({
                        "aria-hidden": "true",
                        "aria-expanded": "false"
                    });
                this.active
                    .prev()
                    .removeClass( "ui-state-active" );
            }
            // set tabIndex -1 to have the button skipped on shift-tab when menu is open (it gets focus)
            var button = menu.prev().addClass( "ui-state-active" ).attr( "tabIndex", -1 );
            this.active = menu
                .show()
                .position( $.extend({
                    of: button
                }, this.options.position ) )
                .removeAttr( "aria-hidden" )
                .attr( "aria-expanded", "true" )
                .menu("focus", event, menu.children( ".ui-menu-item" ).first() )
                // TODO need a comment here why both events are triggered
                // TODO: heh well given the above comment i'm not sure what the
                // implications might be for disabling the focus() call..but it
                // messes with text input focus in undesirable ways..so disable it
                // we will..until we know why we shouldn't
                // .focus()
                .focusin();
            this.open = true;
        },

        next: function( event ) {
            if ( this.open && this.active.data( "menu" ).active.has( ".ui-menu" ).length ) {
                // Track number of open submenus and prevent moving to next menubar item
                this.openSubmenus++;
                return;
            }
            this.openSubmenus = 0;
            this._move( "next", "first", event );
        },

        previous: function( event ) {
            if ( this.open && this.openSubmenus ) {
                // Track number of open submenus and prevent moving to previous menubar item
                this.openSubmenus--;
                return;
            }
            this.openSubmenus = 0;
            this._move( "prev", "last", event );
        },

        _move: function( direction, filter, event ) {
            var next,
            wrapItem;
            if ( this.open ) {
                next = this.active.closest( ".ui-menubar-item" )[ direction + "All" ]( this.options.items ).first().children( ".ui-menu" ).eq( 0 );
                wrapItem = this.menuItems[ filter ]().children( ".ui-menu" ).eq( 0 );
            } else {
                if ( event ) {
                    next = $( event.target ).closest( ".ui-menubar-item" )[ direction + "All" ]( this.options.items ).children( ".ui-menubar-link" ).eq( 0 );
                    wrapItem = this.menuItems[ filter ]().children( ".ui-menubar-link" ).eq( 0 );
                } else {
                    next = wrapItem = this.menuItems.children( "a" ).eq( 0 );
                }
            }

            if ( next.length ) {
                if ( this.open ) {
                    this._open( event, next );
                } else {
                    next.removeAttr( "tabIndex")[0].focus();
                }
            } else {
                if ( this.open ) {
                    this._open( event, wrapItem );
                } else {
                    wrapItem.removeAttr( "tabIndex")[0].focus();
                }
            }
        }
    });

}( jQuery ));
