/**
 * Usage:
 * var myMenu = new DropNav(
    {
        delay: 250,
        selector: '#nav',
        MenuHighlights:
        [{
            target: 'li.root',
            transition:
            {
                type: MenuHighlightTransitions.Appear
            }
        },
        {
            target: 'li.root li',
            transition:
            {
                type: MenuHighlightTransitions.BounceDown
            }
        }]
    });
 */


var DropNav = Class.create({
	initialize: function(options)
    {
        if (typeof(empty) != 'function')
            throw('DropNav.class.js :: Requires bootstrap.js.')
            
        this.options                      = empty(options)                                    ? {}                                        : options;
        this.selector                     = !empty(this.options.selector)                     ? this.options.selector                     : '.ulNav'; 
        this.fly_down_menu_class_name     = !empty(this.options.class_name)                   ? this.options.class_name                   : 'flyDownMenu';
        this.fly_up_menu_class_name       = !empty(this.options.fly_up_class_name)            ? this.options.fly_up_class_name            : 'flyUpMenu';
        this.click_menu_class_name        = !empty(this.options.click_menu_class_name)        ? this.options.click_menu_class_name        : 'clickMenu';
        this.click_menu_expand_class_name = !empty(this.options.click_menu_expand_class_name) ? this.options.click_menu_expand_class_name : 'clickMenu';
        this.delay                        = !empty(this.options.delay)                        ? this.options.delay                        : 250;
        this.iframe                       = !empty(this.options.iframe)                       ? this.options.iframe                       : true;
        this.parent_li_class_name         = !empty(this.options.parent_li_class_name)         ? this.options.parent_li_class_name         : 'branch';
        this.menuHighlights               = !empty(this.options.MenuHighlights)               ? this.options.MenuHighlights               : false;
        this.timers                       = []; //array of objects with 2 props: element + timer
        this.uls                          = $$('ul' + this.selector);
        this.t                            = 0;
        var dn                            = this;
        
        this.uls.each(function(ul)
        {
            lis = ul.select('li');
            if(this.menuHighlights)
            {
                this.menuHighlights.each(function(i)
                {                    
                    highlight = new MenuHighlight(ul.select(i.target), i);
                });
            }
            lis.each(function(li)
            {
		        
                if(!empty(li.down('ul')))
                {
	                li.fly_up        = false;
	                li.has_offset    = false;
	                li.need_timeout  = false;
	                li.addClassName(this.parent_li_class_name);
	                
	                if (ul.hasClassName(this.click_menu_class_name)) // click deployment 
	                {
	                    if(!li.hasClassName('bgIFrameCont'))
	                    {
	                        var a = li.down('a');
	                        Event.observe(a, 'click', dn.clickmenu.bindAsEventListener(dn, a))
	                    }
	                }
	                else // simple drop down (default)
	                {
	                    li.timerID = dn.t++;
	                    
	                    // possible for menu to fly up
	                    if (ul.hasClassName(dn.fly_up_menu_class_name))
	                        li.fly_up = true;
	                    
	                    /** Add an iframe to this menu */
	                    li.select('ul').each(function(ul)
	                    {
                            if(li.fly_up)
                                ul.setStyle({top: (ul.offsetTop - ul.offsetHeight + "px")});
                                
                            dn.addIFrame(li, ul);
	                    }, dn);
	                    
	                    li.need_timeout       = true;
	                    dn.timers[li.timerID] = {
	                        element:        li,
	                        timer:          null
	                    };
	                    
	                    //assign mouseover/out
	                    Event.observe(li, 'mouseover', dn.flyMenuMouseOver.bindAsEventListener(dn, li));
                        Event.observe(li.down('a'), 'focus', dn.flyMenuMouseOver.bindAsEventListener(dn, li));
	                    Event.observe(li, 'mouseout', dn.flyMenuMouseOut.bindAsEventListener(dn, li));
	                }
                }
                else
                {
                    var tgt = li.down('a.root');
                    if(tgt)
                        Event.observe(tgt, 'focus', dn.flyMenuMouseOver.bindAsEventListener(dn, li));
                }
                
            }, dn);
        }, dn);
    }, // end init()
	        
    /*
     * flyMenuMouseOver : handles the li mouseover functions of flyDown or flyUp menu
     *
     */
    flyMenuMouseOver: function(e) 
    {
        var li = arguments[1];
        var dn = this;
        
        //Remove the hover from adjacent lis when moving between menus
        li.adjacent('li.' + this.parent_li_class_name).each(function(node)
        {
	        if((!empty(this.timers[node.timerID]) && !empty(this.timers[node.timerID].timer)))
	            this.removeHover(node.timerID);
	        
	        if(node.hasClassName('hover'))
	            node.removeClassName('hover');
        }, dn);
        
        if (li.hasClassName('hover') && !empty(this.timers[li.timerID].timer))
        {
            this.timers[li.timerID].timer.stop();
            this.timers[li.timerID].timer = null;
        }
        
        if (!li.hasClassName('hover'))
            li.addClassName('hover');
        
        // check for offscreen menu
        li.select('ul').each(function(ul)
        {
            var li_left   = parseInt(ul.offsetLeft, 10);
            var li_width  = parseInt(ul.offsetWidth, 10);
            var doc_width = parseInt(document.documentElement.offsetWidth, 10);
        
            if (li_left + li_width > doc_width)
            {
                var offside   = (li_left + li_width) - doc_width;
                li.has_offset = true;
                ul.setStyle({left: (li_left - offside - 20 + "px")});
            }
        }, li);
    }, // end flyMenuMouseover     
     
    /*
     * flyMenuMouseOut : handles the li mouseout functions of flyDown or flyUp menu
     *
     */
    flyMenuMouseOut: function()
    {
        var li      = arguments[1];
        var timerID = li.timerID;
        var delay   = (li.need_timeout) ? this.delay : 0;
         
        if (!empty(this.timers[timerID]) && !empty(this.timers[timerID].timer))
            this.timers[timerID].timer.stop();
            
        this.timers[timerID] =
        {
            element: li,
            timer:   new PeriodicalExecuter(this.removeHover.bind(this, timerID), delay / 1000)
        };        
    }, // end flyMenuMouseout	    
	    
    /*
     * removeHover : removes hover state from li
     * @param timerID    : Number - index in timers[]
     * 
     */
    removeHover: function(timerID)
    {
        var li = this.timers[timerID].element;
        this.timers[timerID].timer.stop();
        this.timers[timerID].timer = null;
        
        li.removeClassName('hover');
        
        if (li.has_offset) 
        {
            li.select('ul').each(function(ul)
            {
                ul.style.left = null;
                li.has_offset = false;
            }, li);
        }
    }, // end removeHover    
    
    /*
     * addIframe: Create a transparent Iframe, and shim it underneath the dropdown UL, to compensate for lack of z-index on windowed elements
     * @param el        : HTMLListItemElement
     * @param ul_node    : HTMLListElement
     */
    addIFrame: function(el, ul_node) 
    {
        if(this.iframe)
        {
	        var frame  = new Element('iframe')            
					        .setStyle({
					           position: 'absolute',
					           zIndex:   '-1',
					           filter:   'alpha(opacity=0)',
					           opacity:  0,
					           height:   parseInt(ul_node.offsetHeight, 10) + 'px',
					           width:    parseInt(ul_node.offsetWidth, 10) + 'px',
					           top:      '0px',
					           left:     '0px'
					        });
            var new_li = new Element('li')
					        .setStyle({
					           borderWidth: '0px',
					           height:      '0px',
					           bottom:      '0px'
					        });
	        new_li.insert({top: frame});
	        ul_node.insert({top: new_li});
        }        
    }, // end addIFrame    
    
    /*
     * clickMenu : When the A within the menu LI is clicked, toggle expansion of parent LI
     *
     */
    clickMenu: function() 
    {
        var a  = arguments[1];
        var li = a.up();
        
        if (li.hasClassName("sfhide"))
            li.removeClassName(this.click_menu_expand_class_name);
        else
            li.addClassName(this.click_menu_expand_class_name);
    } // end clickMenu    	    
});
