/*
 * Ext Core Library Examples 3.0 Beta
 * http://extjs.com/
 * Copyright(c) 2006-2009, Ext JS, LLC.
 * 
 * The MIT License
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 * 
 */

Ext.ns('Ext.ux');

Ext.ux.Menu = Ext.extend(Ext.util.Observable, {
    direction:          'horizontal',
    delay:              0.2,
    autoWidth:          true,
    transitionType:     'fade',
    transitionOutType:  'fade',
    transitionDuration: 0.3,
    animate:            true,
    currentClass:       'current',
    vAlign:             'bottom',
    floor:              -1,
    ceiling:            0,

    constructor: function(elId, config) {
        config = config || {};
        Ext.apply(this, config);

        Ext.ux.Menu.superclass.constructor.call(this, config);

        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.addClass('ux-menu ux-menu-' + this.direction);
        this.el.select('>li').addClass('ux-menu-item-main');

        this.el.select('li:has(>ul)').addClass('ux-menu-item-parent').select('a').addClass('ux-menu-link-parent');
        
        this.el.select('li:first-child>a').addClass('ux-menu-link-first');
        this.el.select('li:last-child>a').addClass('ux-menu-link-last');

        // create clear fixes for the floating stuff
        this.container.addClass('ux-menu-clearfix');

        // if autoWidth make every submenu as wide as its biggest child;
        if(this.autoWidth) {
            this.doAutoWidth();
        }

        var subs = this.el.select('ul');
        subs.addClass('ux-menu-sub');
        
        //ie6 and ie7/ie8 quirksmode need iframes behind the submenus
        if(Ext.isBorderBox || Ext.isIE7) {
            subs.each(function(item) {
                item.parent().createChild({tag: 'iframe', cls: 'ux-menu-ie-iframe'})
                    .setWidth(item.getWidth())
                    .setHeight(item.getHeight());
            });
        }
        
        subs.addClass('ux-menu-hidden');
    },

    initEvents: function() {
        this.data = {};

        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.delay*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).hasClass('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.hasClass('ux-menu-item-main') && item.parent('ul').hasActiveFx()) {
            item.parent('ul').stopFx(true);
        }

        // if submenu is already shown dont do anything
        if(!item.child('ul').hasClass('ux-menu-hidden')) {
            return;
        }
        
        me.showTask.delay(me.delay*1000, false, false, [item]);   
    },

    showMenu : function(item) {
        var menu = item.child('ul'),
            x = y = 0;

        item.select('>a').addClass('ux-menu-link-hover');

        // some different configurations require different positioning
        if(this.direction == 'horizontal' && item.hasClass('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').addClass('ux-menu-hidden');
            // ie bugs...
            if(Ext.isBorderBox || Ext.isIE7) {
                item.down('iframe').setStyle({left: x + 'px', top: y + 'px', display: 'block'});
            }
        }

        if (!this.data[menu.id] && this.direction == 'vertical' && this.vAlign == 'middle') {
            menu.setStyle('display', 'block');
            y = 0 - menu.getHeight() / 2 + item.getHeight() / 2;

            var iBottom = menu.getOffsetsTo(Ext.getBody())[1] + menu.getHeight();
            if (iBottom > this.floor) {
                y = 0 - (iBottom - this.floor);
            }
            var iTop = menu.getOffsetsTo(Ext.getBody())[1] + y;
            if (iTop < this.ceiling) {
                y = y + Math.abs(iTop); // I'm not sure if this math is right or not . . .
            }

            menu.setStyle('display', 'none');
        }

        if (!this.data[menu.id]) {
            menu.setStyle({left: x + 'px', top: y + 'px'});
        }
        menu.removeClass('ux-menu-hidden');
        this.data[menu.id] = 1;

        if(this.animate) {
            switch(this.transitionType) {
                case 'slide':
                    if(this.direction == 'horizontal' && item.hasClass('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').removeClass('ux-menu-link-hover');
                child.select('ul').stopFx(false).addClass('ux-menu-hidden');
                if (Ext.isBorderBox || Ext.isIE7) {
                    child.select('iframe').setStyle('display', 'none');
                }
            }
        });
    },

    hideAll: function() {
        this.manageSiblings(this.el);
    },
    
    setCurrent: function() {
        var els = this.el.query('.' + this.currentClass);
        if(!els.length) {
            return;
        }
        var item = Ext.get(els[els.length-1]).removeClass(this.currentClass).findParent('li', null, true);
        while(item && item.parent('.ux-menu')) {
            item.down('a').addClass(this.currentClass);
            item = item.parent('li');
        }
    },

    doAutoWidth: function() {
        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;
            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);
        }
        
    }
});

Ext.ux.Menu.zSeed = 10000;