Ext.define('Ext.ux.Menu', {

    mixins: {
        observable: 'Ext.util.Observable'
    },

    requires: ['Ext.fx.Manager', 'Ext.util.Animate'],

    statics: {
        zSeed: 10000
    },

    direction: 'horizontal',
    showDelay: 0.2,
    hideDelay: 0.2,
    autoWidth: true,
    reqWidth: 0,
    transitionType: 'fade',
    transitionDuration: 0.1, /*0.3*/
    animate: true,
    currentClass: 'current',

    constructor: function (elId, config) {
        config = config || {};
        Ext.apply(this, config);

        this.mixins.observable.constructor.call(this);

        this.addEvents('show', 'hide', 'click');

        this.el = Ext.get(elId);

        this.initMarkup();
        this.initEvents();

        this.setCurrent();
    },

    initMarkup: function () {
        this.container = this.el.wrap({
            cls: 'ux-menu-container',
            style: 'z-index: ' + --Ext.ux.Menu.zSeed
        });
        this.items = this.el.select('li');

        this.el.addCls('ux-menu ux-menu-' + this.direction);
        this.el.select('>li').addCls('ux-menu-item-main');

        this.el.select('li:has(>ul)').addCls('ux-menu-item-parent').each(function (item) {
            item.down('a').addCls('ux-menu-link-parent').createChild({
                tag: 'span',
                cls: 'ux-menu-arrow'
            });
        });

        this.el.select('li:first-child>a').addCls('ux-menu-link-first');
        this.el.select('li:last-child>a').addCls('ux-menu-link-last');

        // create clear fixes for the floating stuff
        this.container.addCls('ux-menu-clearfix');

        // if autoWidth make every submenu as wide as its biggest child;
        if (this.autoWidth) {
            this.doAutoWidth(this.reqWidth);
        }

        var subs = this.el.select('ul');
        subs.addCls('ux-menu-sub');

        //ie6 and ie7/ie8 quirksmode need iframes behind the submenus
        if (Ext.isIEQuirks || Ext.isIE7) {
            subs.each(function (item) {
                item.parent().createChild({
                    tag: 'iframe',
                    frameBorder: 0,
                    cls: 'ux-menu-ie-iframe'
                }).setWidth(1).setHeight(1);
            });
        }

        subs.addCls('ux-menu-hidden');
    },

    initEvents: function () {
        this.showTask = new Ext.util.DelayedTask(this.showMenu, this);
        this.hideTask = new Ext.util.DelayedTask(function () {
            this.showTask.cancel();
            this.hideAll();
            this.fireEvent('hide');
        }, this);

        this.el.hover(function () {
            this.hideTask.cancel();
        }, function () {
            this.hideTask.delay(this.hideDelay * 1000);
        }, this);

        // for each item that has a submenu, create a mouseenter function that shows its submenu
        // delay 5 to make sure enter is fired after mouseover
        this.el.select('li.ux-menu-item-parent').on('mouseenter', this.onParentEnter, false, {
            me: this,
            delay: 5
        });

        // listen for mouseover events on items to hide other items submenus and remove hovers
        this.el.on('mouseover', function (ev, t) {
            this.manageSiblings(t);
            // if this item does not have a submenu, the showMenu task for a sibling could potentially still be fired, so cancel it
            if (!Ext.fly(t).hasCls('ux-menu-item-parent')) {
                this.showTask.cancel();
            }
        }, this, {
            delegate: 'li'
        });

        this.el.on('click', function (ev, t) {
            return this.fireEvent('click', ev, t, this);
        }, this, {
            delegate: 'a'
        })
    },

    onParentEnter: function (ev, link, o) {
        var item = Ext.get(this), me = o.me;

        // if this item is in a submenu and contains a submenu, check if the submenu is not still animating
        if (!item.hasCls('ux-menu-item-main') && item.parent('ul').getActiveAnimation()) {
            item.parent('ul').stopAnimation();
        }

        // if submenu is already shown dont do anything
        if (!item.child('ul').hasCls('ux-menu-hidden')) {
            return;
        }

        me.showTask.delay(me.showDelay * 1000, false, false, [item]);
    },

    showMenu: function (item) {
        var menu = item.child('ul'), x = y = 0;

        item.select('>a').addCls('ux-menu-link-hover');

        // some different configurations require different positioning
        if (this.direction == 'horizontal' && item.hasCls('ux-menu-item-main')) {
            y = item.getHeight() + 1;
        } else {
            x = item.getWidth() + 1;
        }

        // if its ie, force a repaint of the submenu
        if (Ext.isIE) {
            menu.select('ul').addCls('ux-menu-hidden');
            // ie bugs...
            if (Ext.isIEQuirks || Ext.isIE7) {
                item.down('iframe').setStyle({
                    left: x + 'px',
                    top: y + 'px',
                    display: 'block'
                });
            }
            menu.repaint();
        }

        menu.setStyle({
            left: x + 'px',
            top: y + 'px'
        }).removeCls('ux-menu-hidden');

        if (this.animate) {
            switch (this.transitionType) {
                case 'slide':
                    if (this.direction == 'horizontal' && item.hasCls('ux-menu-item-main')) {
                        menu.slideIn('t', {
                            duration: this.transitionDuration
                        });
                    } else {
                        menu.slideIn('l', {
                            duration: this.transitionDuration
                        });
                    }
                    break;

                default:
                    menu.setOpacity(0.001).fadeIn({
                        duration: this.transitionDuration
                    });
                    break
            }
        }

        this.fireEvent('show', item, menu, this);
    },

    manageSiblings: function (item) {
        var item = Ext.get(item);
            
        item.parent().select('li.ux-menu-item-parent').each(function (child) {
            if (child.dom.id !== item.dom.id) {
                child.select('>a').removeCls('ux-menu-link-hover');
                child.select('ul').stopAnimation().addCls('ux-menu-hidden');
            }
            if (Ext.isIEQuirks || Ext.isIE7) {
                child.select('iframe').setStyle('display', 'none');
            }
        });
    },

    hideAll: function () {
        this.manageSiblings(this.el);
        if (Ext.isIE8) {
            Ext.getBody().repaint();
        }
    },

    setCurrent: function () {
        var els = this.el.query('.' + this.currentClass);
        if (!els.length) {
            return;
        }
        var item = Ext.get(els[els.length - 1]).removeCls(this.currentClass).findParent('li', null, true);
        while (item && item.parent('.ux-menu')) {
            item.down('a').addCls(this.currentClass);
            item = item.parent('li');
        }
    },

    doAutoWidth: function (width) {
        var fixWidth = function (sub) {
            var widest = 0;
            var items = sub.select('>li');

            sub.setStyle({
                width: 3000 + 'px'
            });

            items.each(function (item) {
                widest = Math.max(widest, item.getWidth());
            });

            widest = Ext.isIE ? widest + 1 : widest;
            widest = width > 0 ? width : widest;

            items.setWidth(widest + 'px');
            sub.setWidth(widest + 'px');
        }

        if (this.direction == 'vertical') {
            this.container.select('ul').each(fixWidth);
        } else {
            this.el.select('ul').each(fixWidth);
        }

    }
}, function () {
    Ext.CompositeElementLite.importElementMethods();
});
