
/**
 * menuMatic 
 * @version 0.68.3 (beta)
 * @author Jason J. Jaeger | greengeckodesign.com
 * @copyright 2008 Jason John Jaeger
 * @license MIT-style 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.
 *	
 *  @changeLog_________________________________________________________________________________
 *  
 *  Nov  15th 2008
 *  JJJ - incremented version to 0.68.3
 *  	- Fixed bug which occured when ol was used instead of ul.. was because you cannot use selectors such 
 *  		as 'ul, ol' with getParent() and getNext() despite the mootool documentation saying "if Selectors 
 *  		is included, a full CSS selector can be passed."
 *  
 *  Nov 4th 2008
 *  JJJ - incremented version to 0.68.2
 *  	- Removed extranious comma which threw an error in IE. (Thanks to Robert S. for catching that)
 *  	- Added check to change the opacity to 99.9 if it is over 99 due to the fact that 
 *  		setting the opaicty to 100% in safari caused misc strange behaviour (thanks to Roland Barker 
 *  		at xnau webdesign for reporting this one)
 *  
 *  Nov 3rd 2008
 *  JJJ - Renamed menuWidth option to stretchMainMenu and made it work much quicker
 *  
 *  Nov 2nd 2008
 *  JJJ - Finished adding several callback functions
 *  	- Added fixHasLayoutBug option
 *  
 *  Oct 4th 2008
 *  JJJ - Continued to go through code to optimize and clean it up
 *  	- Added center option
 *  
 *  Sept 28th 2008
 *  JJJ - Incremented version to 0.68
 *  	- Began optimizing & better commenting code
 *  
 *  Sept 16th 2008
 *  JJJ - Incremented version to 0.67
 *  	- Specifically set each submenu z-index on show, incrementing each time. Set z-index back to 1 on hide.
 *  
 *  Sept 14th 2008
 *  JJJ - Added bottom edge detection and redirection (if bottom of subsequent submenu is lower than the scrollheight of the body)
 *  
 *  Sept 10th 2008
 *  JJJ - Did a google search for MooMenu and it looks like that name is already being used, so I must reluctently change the name.
 *  		The name I have chose to move forward with is: MenuMatic.
 *  
 *  Sept 8th 2008
 *  JJJ - Incremented version to 0.66
 *  	- Fixed IE bug whiched caused some events to be incorrectly attached to parent buttons causing sub submenus to not open
 *  	  correctly when transitions are enabled. This error was introduced in 0.65. 
 *  
 *  August 10th 2008
 *  JJJ - Incremented verion to 0.65
 *  	- Fixed bug with edge detection and redirection
 *  	- Improved javascript and CSS to assure the submenus will always be on top
 *  	- Improved edge detection and redirection logic
 *  	- Added subMenusContainerId option so that if you have multiple MooMenu instances on a page they can be styled differently
 *  
 *  May 7th 2008
 *  JJJ - Incremented version to 0.64
 *  	- Fixed bug with that occured when firing events
 *  
 *  April 28th 2008:
 *  JJJ - Incremented version to 0.63
 *  	- Added killDivider option
 *  	- Removed focus on hover since it adds browser default dotted outline
 *  	- Changed menuWidth option to use actual width of nav element (so it can be set in css) instead of a width set in javascript
 *  
 *  Feb 17th 2008:
 *  JJJ - Incremented version to 0.62
 *  	- Added mmbClassName and mmbFocusedClassName options to allow morphing of main menu btns
 *  
 *  Feb 16th 2008:
 *  JJJ - Incremented version to 0.61
 *  	- Made changes to options syntax. 
 *  	- Improved keyboard accessability to take into account a menu's orientation, and its x and y direction when using arrow keys
 *  	- Added matchWidthMode option.
 *  
 *  Feb 14th 2008:
 *  JJJ - Incremented version to 0.60
 *  	- Added menuWidth option to simulate a table based layout for the main menu when the orienation is horizontal
 **/


/*
 * To Do:
 * 
 * 1. Make screencast tutorials
 * 
 * 2. Add more examples to website
 * 
 * 3. Clean up/optimize CSS / make easier to edit 
 * 
 * 4. Make online generator 
 * 
 * 5. Add rounded corners option
 * 
 * 6. Add drop shadow option
 * 
 * 7. Add sound integration 
 * 
 */

var MenuMatic = new Class({
  Implements: Options,
  options: {
        id: 'nav',//the id of the main menu (ul or ol)
        subMenusContainerId:'subMenusContainer',//id of the container div that will be generated to hold the submenus 
    
    //subMenu behavior
    effect: 'slide & fade',// 'slide', 'fade', 'slide & fade', or  null
    duration: 600,//duration of the effect in milliseconds
    physics: Fx.Transitions.Pow.easeOut,//how the effect behaves
    hideDelay: 1000,//in milliseconds, how long you have after moving your mouse off of the submenus before they dissapear
    
    //layout
    stretchMainMenu:false,//stretch main menu btn widths to fit within the width {set in the css} of the parent UL or OL
    matchWidthMode:false,//initial submenus match their parent button's width
    orientation: 'horizontal',//horizontal or vertical
    direction:{	x: 'right',	y: 'down' },//for submenus ( relative to the parent button )left or right, up or down
    tweakInitial:{ x:0, y:0	},//if you need to tweak the placement of the initial submenus
    tweakSubsequent:{ x:0, y:0 },//if you need to tweak the placement of the subsequent submenus
    center: false,// will attempt to center main nav element
    
    //dynamic style
    opacity: 95,//of the submenus
    mmbFocusedClassName:null,//main menu button classname, used for morphing to focused state
    mmbClassName:null,//main menu button classname, used for morphing back to original state
    killDivider:null,	
    
    fixHasLayoutBug:false,	
    
    onHideAllSubMenusNow_begin: (function(){}),
    onHideAllSubMenusNow_complete: (function(){}),
    
    onInit_begin: (function(){}),
    onInit_complete: (function(){})		

    },
  
  hideAllMenusTimeout:null,
  allSubMenus:[],
  subMenuZindex:1,
  
  initialize: function(options){		
    //if(Browser.Engine.webkit419){return;}		
        this.setOptions(options);
    this.options.onInit_begin();
    if(this.options.opacity > 99){this.options.opacity = 99.9;}
    this.options.opacity = this.options.opacity /100;

    Element.implement({
        getId: function(){
        //If this element does not have an id, give it a unique one
            if(!this.id){ 
          var uniqueId = this.get('tag') + "-" + $time();
          while($(uniqueId)){
            //make sure it is absolutely unique
            uniqueId = this.get('tag') + "-" + $time();						
          }
          this.id = uniqueId;						
        }
          return this.id;
        }
    });
    
    //initialize directions
    this.options.direction.x = this.options.direction.x.toLowerCase();
    this.options.direction.y = this.options.direction.y.toLowerCase();
    if(this.options.direction.x === 'right'){
      this.options.direction.xInverse = 'left';
    }else if(this.options.direction.x === 'left'){
      this.options.direction.xInverse = 'right';
    }
    if(this.options.direction.y === 'up'){
      this.options.direction.yInverse = 'down';
    }else if(this.options.direction.y === 'down'){
      this.options.direction.yInverse = 'up';
    }
    
    var links = $(this.options.id).getElements('a');
    
    links.each(function(item,index){
      
      //store parent links & child menu info
      item.store('parentLinks', item.getParent().getParents('li').getFirst('a'));
      
      item.store('parentLinks',item.retrieve('parentLinks').erase(item.retrieve('parentLinks').getFirst()));
      item.store('childMenu',item.getNext('ul') || item.getNext('ol'));
      
      //determine submenu type
      theSubMenuType = 'subsequent';
      
      //console.log($(this.options.id).getElements('ul, ol'));
      //console.log(item.getParent(['body ul,ol']));
      
      //console.log($(item.getParent('ul') || item.getParent('ol') ));
      
      if( $(item.getParent('ul') || item.getParent('ol') ).id === this.options.id){theSubMenuType = 'initial';	}
      item.store('subMenuType',theSubMenuType );
      
      //add classes to parents
      if(theSubMenuType === 'initial' && $(item.getNext('ul') || item.getNext('ol') )){
        item.addClass('mainMenuParentBtn');
      }else if($(item.getNext('ul') || item.getNext('ol') )){
        item.addClass('subMenuParentBtn');
      }			
    }.bind(this));
    
    //rip the submenus apart into separate divs inside of subMenusContainer
    var subMenusContainer = new Element('div', { 'id': this.options.subMenusContainerId	}).inject( $(document.body) ,'bottom');
    $(this.options.id).getElements('ul, ol').each(function(item,index){	
      new Element('div',{'class': 'smOW'}).inject(subMenusContainer).grab(item);		
    }.bind(this));		
    
    //set tabindex to -1 so tabbing through links in page does not go through hidden links in submenus container, since arrow keys can be used to navigate through submenus
    subMenusContainer.getElements('a').set('tabindex','-1'); 
    
    links.each(function(item,index){
      //only apply to links with subMenus
      if (!item.retrieve('childMenu')) {return;}
      
      //update childMenu pointer to look at smOW DIVs
      item.store('childMenu', item.retrieve('childMenu').getParent('div'));
      
      //add to allSubMenus array
      this.allSubMenus.include(item.retrieve('childMenu'));			
      
      //store parentSubMenus
      item.store('parentSubMenus',item.retrieve('parentLinks').retrieve('childMenu'));

      //now create the MenuMaticSubMenu class instances 
      var aSubMenu = new MenuMaticSubMenu(this.options,this, item);

    }.bind(this));
      
    //attach event handlers to non-parent main menu buttons
    var nonParentBtns = $(this.options.id).getElements('a').filter(function(item, index){ return !item.retrieve('childMenu'); });
    nonParentBtns.each(function(item, index){
      item.addEvents({
        'mouseenter': function(e){					
          //e = new Event(e).stop();
          this.hideAllSubMenusNow();	
          if(this.options.mmbClassName && this.options.mmbFocusedClassName){
            $(item).retrieve('btnMorph', new Fx.Morph(item, { 'duration':(this.options.duration/2), transition:this.options.physics, link:'cancel'})).start(this.options.mmbFocusedClassName); 
          }								
        }.bind(this),
        
        'focus': function(e){
          //e = new Event(e).stop();
          this.hideAllSubMenusNow();	
          if(this.options.mmbClassName && this.options.mmbFocusedClassName){
            $(item).retrieve('btnMorph', new Fx.Morph(item, { 'duration':(this.options.duration/2), transition:this.options.physics, link:'cancel'})).start(this.options.mmbFocusedClassName); 
          }
        }.bind(this),
        
        'mouseleave':function(e){
          //e = new Event(e).stop();
          if (this.options.mmbClassName && this.options.mmbFocusedClassName) {						
            $(item).retrieve('btnMorph', new Fx.Morph(item, {	'duration': (this.options.duration * 5),transition: this.options.physics,link: 'cancel'	})).start(this.options.mmbClassName);
          }	
        }.bind(this),
        
        'blur':function(e){
          //e = new Event(e).stop();
          if (this.options.mmbClassName && this.options.mmbFocusedClassName) {						
            $(item).retrieve('btnMorph', new Fx.Morph(item, {	'duration': (this.options.duration * 5),transition: this.options.physics,link: 'cancel'	})).start(this.options.mmbClassName);
          }					
        }.bind(this),
        
        'keydown' : function(e){
            var event = new Event(e);
          if (e.key === 'up' || e.key === 'down' || e.key === 'left' || e.key === 'right') {	e.stop();	}
          
          if( e.key === 'left' && this.options.orientation === 'horizontal' || 
            e.key === 'up' && this.options.orientation === 'vertical'){
            
            if(item.getParent('li').getPrevious('li')){
              item.getParent('li').getPrevious('li').getFirst('a').focus();
            }else{
              item.getParent('li').getParent().getLast('li').getFirst('a').focus();
            }
          }else if(e.key === 'right' && this.options.orientation === 'horizontal' || 
               e.key === 'down' && this.options.orientation === 'vertical'){
            if(item.getParent('li').getNext('li')){
              item.getParent('li').getNext('li').getFirst('a').focus();
            }else{
              item.getParent('li').getParent().getFirst('li').getFirst('a').focus();
            }	
          }
        }.bind(this)
      });
    }, this);

    
    this.stretch();
    this.killDivider();
    this.center();
    this.fixHasLayoutBug();
    this.options.onInit_complete();		
    },
  
  fixHasLayoutBug:function(){
    if(Browser.Engine.trident && this.options.fixHasLayoutBug){
      $(this.options.id).getParents().setStyle('zoom',1);
      $(this.options.id).setStyle('zoom',1);
      $(this.options.id).getChildren().setStyle('zoom',1);
      $(this.options.subMenusContainerId).setStyle('zoom',1);
      $(this.options.subMenusContainerId).getChildren().setStyle('zoom',1);
    }		
  },
  
  center:function(){
    if(!this.options.center){return;}
    $(this.options.id).setStyles({'left':'50%','margin-left': -($(this.options.id).getSize().x/2) });
  },
  
  stretch:function(){
    //stretch main menu btn widths to fit within the width of the parent UL or OL
    if(this.options.stretchMainMenu  && this.options.orientation === 'horizontal'){
      var targetWidth = parseFloat($(this.options.id).getCoordinates().width) ;
      var totalBtnWidth = 0;
      var mainBtns = $(this.options.id).getElements('a');
      mainBtns.setStyles({'padding-left':0,'padding-right':0});
      mainBtns.each(function(item,index){ totalBtnWidth+= item.getSize().x; }.bind(this));
      if(targetWidth < totalBtnWidth){return;}
      var increment = (targetWidth - totalBtnWidth)/ mainBtns.length;
      mainBtns.each(function(item,index){ item.setStyle('width',item.getSize().x+increment);	}.bind(this));
      mainBtns.getLast().setStyle('width',mainBtns.getLast().getSize().x-1);
    }
  },
  
  killDivider:function(){
    if(this.options.killDivider && this.options.killDivider.toLowerCase() === 'first'){
      $($(this.options.id).getElements('li')[0]).setStyles({'background':'none'});
    }else if(this.options.killDivider && this.options.killDivider.toLowerCase() === 'last'){
      $($(this.options.id).getElements('li').getLast()).setStyles({'background':'none'});
    }
  },

  hideAllSubMenusNow: function(){
    this.options.onHideAllSubMenusNow_begin();
    $clear(this.hideAllMenusTimeout);
    $$(this.allSubMenus).fireEvent('hide');
    this.options.onHideAllSubMenusNow_complete();	
  } 
  
});

var MenuMaticSubMenu = new Class({
  Implements: Options,
  Extends: MenuMatic,
    options: {
    onSubMenuInit_begin: (function(subMenuClass){}),
    onSubMenuInit_complete: (function(subMenuClass){}),
    
    onMatchWidth_begin: (function(subMenuClass){}),
    onMatchWidth_complete: (function(subMenuClass){}),
    
    onHideSubMenu_begin: (function(subMenuClass){}),
    onHideSubMenu_complete: (function(subMenuClass){}),
    
    onHideOtherSubMenus_begin: (function(subMenuClass){}),
    onHideOtherSubMenus_complete: (function(subMenuClass){}),		
    
    onHideAllSubMenus_begin: (function(subMenuClass){}),
    onHideAllSubMenus_complete: (function(subMenuClass){}),
    
    onPositionSubMenu_begin: (function(subMenuClass){}),
    onPositionSubMenu_complete: (function(subMenuClass){}),
    
    onShowSubMenu_begin: (function(subMenuClass){}),
    onShowSubMenu_complete: (function(subMenuClass){})
  },
  root:null,
  btn:null,
  hidden:true,
  myEffect:null,
    
  initialize: function(options,root,btn){
    this.setOptions(options);		
    this.root = root;
    this.btn = btn;
    this.childMenu = this.btn.retrieve('childMenu');
    this.subMenuType = this.btn.retrieve('subMenuType');
    this.childMenu = this.btn.retrieve('childMenu');
    this.parentSubMenus =  $$(this.btn.retrieve('parentSubMenus'));
    this.parentLinks =  $$(this.btn.retrieve('parentLinks'));
    this.parentSubMenu = $(this.parentSubMenus[0]);
    if(this.parentSubMenu ){this.parentSubMenu =this.parentSubMenu.retrieve('class');}
    this.childMenu.store('class',this);
    this.btn.store('class',this);
    this.childMenu.store('status','closed')
    
    this.options.onSubMenuInit_begin(this);		
    
    //add hide Event
    this.childMenu.addEvent('hide',function(){this.hideSubMenu();}.bind(this));
    
    //add show Event
    this.childMenu.addEvent('show',function(){this.showSubMenu();}.bind(this));

    if(this.options.effect){
      this.myEffect = new Fx.Morph(
        $(this.childMenu).getFirst(), {	duration: this.options.duration, transition: this.options.physics,  link: 'cancel' } 
      );
    }
    if(this.options.effect === 'slide' || this.options.effect === 'slide & fade'){
      if (this.subMenuType == 'initial' && this.options.orientation === 'horizontal' ) {
        this.childMenu.getFirst().setStyle('margin-top','0' );
      }else {
        this.childMenu.getFirst().setStyle('margin-left', '0');
      }
      
    }else if (this.options.effect === 'fade' || this.options.effect === 'slide & fade'){
      this.childMenu.getFirst().setStyle('opacity',0 );
    }
    
    if (this.options.effect != 'fade' && this.options.effect != 'slide & fade') {
      this.childMenu.getFirst().setStyle('opacity',this.options.opacity);
    }

    
    //attach event handlers to non-parent sub menu buttons
    var nonParentBtns = $(this.childMenu).getElements('a').filter(function(item, index){ return !item.retrieve('childMenu'); });
    nonParentBtns.each(function(item, index){
      $(item).addClass('subMenuBtn');
      
      item.addEvents({
        'mouseenter': function(e){
          this.childMenu.fireEvent('show');
          this.cancellHideAllSubMenus();					
          this.hideOtherSubMenus();				
        }.bind(this),
        
        'focus': function(e){
          this.childMenu.fireEvent('show');
          this.cancellHideAllSubMenus();		
          this.hideOtherSubMenus();
        }.bind(this),
        
        'mouseleave': function(e){
          this.cancellHideAllSubMenus();
          this.hideAllSubMenus();					
        }.bind(this),
        
        'blur': function(e){
          this.cancellHideAllSubMenus();
          this.hideAllSubMenus();
        }.bind(this),
        
        'keydown' : function(e){
            var event = new Event(e);
          
          if (e.key === 'up' || e.key === 'down' || e.key === 'left' || e.key === 'right' || e.key === 'tab') {	e.stop();	}
          
          if(e.key === 'up'){
            if(item.getParent('li').getPrevious('li')){
              //move focus to the next link up if possible
              item.getParent('li').getPrevious('li').getFirst('a').focus();
            }else if(this.options.direction.y ==='down'){
              //move focus to the parent link
              this.btn.focus();
            }else if(this.options.direction.y ==='up'){
              //move focus to the last link in the subMenu
              item.getParent('li').getParent().getLast('li').getFirst('a').focus();
            }
          }else if(e.key === 'down'){
            if(item.getParent('li').getNext('li')){
              //move focus to the next link down if possible
              item.getParent('li').getNext('li').getFirst('a').focus();
            }else if(this.options.direction.y ==='down'){
              //move focus to the first link in the submenu
              item.getParent('li').getParent().getFirst('li').getFirst('a').focus();
            }else if(this.options.direction.y ==='up'){
              //move focus to the parent link
              this.btn.focus();
            }
          }else if(e.key === this.options.direction.xInverse){
            this.btn.focus();
          }
        }.bind(this)
      });
      
    }, this);
    
    $(this.btn).removeClass('subMenuBtn');
    
    if (this.subMenuType == 'initial') {
      this.btn.addClass('mainParentBtn');	
    }else{	
      this.btn.addClass('subParentBtn');	
    }
    
    //attach event handlers to parent button
    $(this.btn).addEvents({
      'mouseenter' : function(e){
        //e = new Event(e).stop();
        this.cancellHideAllSubMenus();
        this.hideOtherSubMenus();
        this.showSubMenu();
        if(this.subMenuType === 'initial' && this.options.mmbClassName && this.options.mmbFocusedClassName){
          $(this.btn).retrieve('btnMorph', new Fx.Morph($(this.btn), { 'duration':(this.options.duration/2), transition:this.options.physics, link:'cancel' })).start(this.options.mmbFocusedClassName);
        }
      }.bind(this),
      
      'focus' : function(e){
        //e = new Event(e).stop();
        this.cancellHideAllSubMenus();
        this.hideOtherSubMenus();
        this.showSubMenu();
        if(this.subMenuType === 'initial' && this.options.mmbClassName && this.options.mmbFocusedClassName){
          $(this.btn).retrieve('btnMorph', new Fx.Morph($(this.btn), { 'duration':(this.options.duration/2), transition:this.options.physics, link:'cancel' })).start(this.options.mmbFocusedClassName);
        }
      }.bind(this),
        
      'mouseleave': function(e){
        //e = new Event(e).stop();
        this.cancellHideAllSubMenus();
        this.hideAllSubMenus();
      }.bind(this),
      
      'blur': function(e){
        //e = new Event(e).stop();
        this.cancellHideAllSubMenus();
        this.hideAllSubMenus();
      }.bind(this),
      
      'keydown' : function(e){
          e = new Event(e)
        if (e.key === 'up' || e.key === 'down' || e.key === 'left' || e.key === 'right') {	e.stop();	}
        
        if(!this.parentSubMenu){
          //main menu parent buttons
          if(
            this.options.orientation === 'horizontal' && e.key === this.options.direction.y ||
            this.options.orientation === 'vertical' && e.key === this.options.direction.x
          ){
            if(this.options.direction.y ==='down'){
              //move focus to the first link in the child menu
              this.childMenu.getFirst().getFirst('li').getFirst('a').focus();
            }else if(this.options.direction.y ==='up'){
              //move focus to the first link in the child menu
              this.childMenu.getFirst().getLast('li').getFirst('a').focus();
            }
          }else if(
            this.options.orientation === 'horizontal' && e.key === 'left' ||
            this.options.orientation === 'vertical' && e.key === this.options.direction.yInverse 
          ){
            //move focus to the previous link if possible, if not, move focus to the last link in the menu
            if(this.btn.getParent().getPrevious()){
              this.btn.getParent().getPrevious().getFirst().focus();
            }else{
              this.btn.getParent().getParent().getLast().getFirst().focus();
            }
          }else if(
            this.options.orientation === 'horizontal' && e.key === 'right' ||
            this.options.orientation === 'vertical' && e.key === this.options.direction.y 
          ){
            //move focus to the next link if possible, if not, move focus to the first link in the menu
            if (this.btn.getParent().getNext()) {
              this.btn.getParent().getNext().getFirst().focus();
            }else{
              this.btn.getParent().getParent().getFirst().getFirst().focus();
            }
          }
        }else{
          if(e.key === 'tab'){e.stop();}
          //submenu parent buttons
          if (e.key === 'up') {
            if (this.btn.getParent('li').getPrevious('li')) {
              //move focus to the next link up
              this.btn.getParent('li').getPrevious('li').getFirst('a').focus();
            }else if(this.options.direction.y === 'down'){
              //move focus to the parent link
              this.parentSubMenu.btn.focus();
            }else if(this.options.direction.y === 'up'){
              //move focus to the bottom link in this submenu
              this.btn.getParent('li').getParent().getLast('li').getFirst('a').focus();
            }
          }else if(e.key === 'down'){
            if(this.btn.getParent('li').getNext('li')){
              //move focus to the next link down
              this.btn.getParent('li').getNext('li').getFirst('a').focus();
            }else if(this.options.direction.y === 'down'){
              //move focus to the top link in this submenu
              this.btn.getParent('li').getParent().getFirst('li').getFirst('a').focus();
            }else if(this.options.direction.y === 'up'){
              //move focus to the parent link
              this.parentSubMenu.btn.focus();
            }
          }else if(e.key === this.options.direction.xInverse){
            this.parentSubMenu.btn.focus();
          }else if(e.key === this.options.direction.x){
            if(this.options.direction.y === 'down'){
              this.childMenu.getFirst().getFirst('li').getFirst('a').focus();
            }else if(this.options.direction.y === 'up'){
            //	this.childMenu.getFirst().getLast('li').getFirst('a').focus();
            }
          }
        }
      }.bind(this)	
    });
    
    this.options.onSubMenuInit_complete(this);
    
    },
  
  matchWidth:function(){
    if (this.widthMatched || !this.options.matchWidthMode || this.subMenuType === 'subsequent'){return;}
    this.options.onMatchWidth_begin(this);
    var parentWidth = this.btn.getCoordinates().width;
    $(this.childMenu).getElements('a').each(function(item,index){
      var borderWidth = parseFloat($(this.childMenu).getFirst().getStyle('border-left-width')) + parseFloat($(this.childMenu).getFirst().getStyle('border-right-width'));
      var paddingWidth = parseFloat(item.getStyle('padding-left')) +	 parseFloat(item.getStyle('padding-right'));
      var offset = borderWidth + paddingWidth ;
      if(parentWidth > item.getCoordinates().width){
        item.setStyle('width',parentWidth - offset);
        item.setStyle('margin-right',-borderWidth);
      }
    }.bind(this));
    this.width = this.childMenu.getFirst().getCoordinates().width;
    this.widthMatched = true;
    this.options.onMatchWidth_complete(this);
  },
  
  hideSubMenu: function() {	
    if(this.childMenu.retrieve('status') === 'closed'){return;}	
    this.options.onHideSubMenu_begin(this);
    if (this.subMenuType == 'initial') {
      if(this.options.mmbClassName && this.options.mmbFocusedClassName){
        $(this.btn).retrieve('btnMorph', new Fx.Morph($(this.btn), { 'duration':(this.options.duration), transition:this.options.physics, link:'cancel' })).start(this.options.mmbClassName )
        .chain(function(){
          $(this.btn).removeClass('mainMenuParentBtnFocused');
          $(this.btn).addClass('mainMenuParentBtn');
        }.bind(this));
      }else{
        $(this.btn).removeClass('mainMenuParentBtnFocused');
        $(this.btn).addClass('mainMenuParentBtn');
      }
    }else{
      $(this.btn).removeClass('subMenuParentBtnFocused');
      $(this.btn).addClass('subMenuParentBtn');
    }
    
    this.childMenu.setStyle('z-index',1);
    
    if(this.options.effect && this.options.effect.toLowerCase() === 'slide'){
      if (this.subMenuType == 'initial' && this.options.orientation === 'horizontal' && this.options.direction.y === 'down') {
        this.myEffect.start({ 'margin-top': -this.height }).chain(function(){	this.childMenu.style.display = "none";	}.bind(this));
      }else if (this.subMenuType == 'initial' && this.options.orientation === 'horizontal' && this.options.direction.y === 'up') {
        this.myEffect.start({ 'margin-top': this.height }).chain(function(){	this.childMenu.style.display = "none";	}.bind(this));
      }else if(this.options.direction.x === 'right'){
        this.myEffect.start({ 'margin-left': -this.width }).chain(function(){	this.childMenu.style.display = "none";	}.bind(this));
      }else if(this.options.direction.x === 'left'){
        this.myEffect.start({ 'margin-left': this.width }).chain(function(){	this.childMenu.style.display = "none";	}.bind(this));
      }
    }else if(this.options.effect == 'fade'){
      this.myEffect.start({ 'opacity': 0 }).chain(function(){	this.childMenu.style.display = "none";	}.bind(this));
    }else if(this.options.effect == 'slide & fade'){
      
      if (this.subMenuType == 'initial' && this.options.orientation === 'horizontal' && this.options.direction.y === 'down') {
        this.myEffect.start({ 'margin-top': -this.height,opacity:0 }).chain(function(){	this.childMenu.style.display = "none";	}.bind(this));
      }else if (this.subMenuType == 'initial' && this.options.orientation === 'horizontal' && this.options.direction.y === 'up') {
        this.myEffect.start({ 'margin-top': this.height,opacity:0 }).chain(function(){	this.childMenu.style.display = "none";	}.bind(this));
      }else if(this.options.direction.x === 'right'){
        this.myEffect.start({ 'margin-left': -this.width,opacity:0 }).chain(function(){	this.childMenu.style.display = "none";	}.bind(this));
      }else if(this.options.direction.x === 'left'){
        this.myEffect.start({ 'margin-left': this.width, opacity:0 }).chain(function(){	this.childMenu.style.display = "none";	}.bind(this));
      }
    }else{
      this.childMenu.style.display = "none";
    }
    this.childMenu.store('status','closed');
    this.options.onHideSubMenu_complete(this);
  },
  
  hideOtherSubMenus: function() {		
    this.options.onHideOtherSubMenus_begin(this);
    //set up otherSubMenus element collection
    if(!this.btn.retrieve('otherSubMenus')){
      this.btn.store('otherSubMenus', $$(this.root.allSubMenus.filter(function(item){ return !this.btn.retrieve('parentSubMenus').contains(item) && item != this.childMenu; }.bind(this)) ));
    }		
    this.parentSubMenus.fireEvent('show');
    this.btn.retrieve('otherSubMenus').fireEvent('hide');
    this.options.onHideOtherSubMenus_complete(this);
  },
  
  hideAllSubMenus: function(){
    this.options.onHideAllSubMenus_begin(this);
    $clear(this.root.hideAllMenusTimeout);
    this.root.hideAllMenusTimeout = (function(){
      $clear(this.hideAllMenusTimeout);			
      $$(this.root.allSubMenus).fireEvent('hide');			
    }).bind(this).delay(this.options.hideDelay);
    this.options.onHideAllSubMenus_complete(this);		
  },

  cancellHideAllSubMenus: function(){ 
    $clear(this.root.hideAllMenusTimeout);	
  },
  
  showSubMenu: function(now){		
    if(this.childMenu.retrieve('status') === 'open'){return;}
    this.options.onShowSubMenu_begin(this);
    if (this.subMenuType == 'initial') {
      $(this.btn).removeClass('mainMenuParentBtn');
      $(this.btn).addClass('mainMenuParentBtnFocused');	
    }else{
      $(this.btn).removeClass('subMenuParentBtn');
      $(this.btn).addClass('subMenuParentBtnFocused');
    }
    this.root.subMenuZindex++;
    this.childMenu.setStyles({'display':'block','visibility':'hidden','z-index':this.root.subMenuZindex});
    
    if(!this.width || !this.height ){
      this.width = this.childMenu.getFirst().getCoordinates().width;
      this.height = this.childMenu.getFirst().getCoordinates().height;
      this.childMenu.setStyle('height',this.height,'border');
      if(this.options.effect === 'slide' || this.options.effect === 'slide & fade'){
        if (this.subMenuType == 'initial' && this.options.orientation === 'horizontal' ) {
          this.childMenu.getFirst().setStyle('margin-top','0' );
          if(this.options.direction.y === 'down'){
            this.myEffect.set({ 'margin-top': - this.height });
          }else if(this.options.direction.y === 'up'){
            this.myEffect.set({ 'margin-top': this.height });
          }
        }else {
          if(this.options.direction.x === 'left'){
            this.myEffect.set({ 'margin-left': this.width });
          }else{
            this.myEffect.set({ 'margin-left': -this.width });
          }
        }
      }
    }
    this.matchWidth();
    this.positionSubMenu();
    
    if(this.options.effect === 'slide' ){
      this.childMenu.setStyles({'display':'block','visibility':'visible'});
      if (this.subMenuType === 'initial' && this.options.orientation === 'horizontal') {
        if(now){
          this.myEffect.set({ 'margin-top': 0 }).chain(function(){	this.showSubMenuComplete();	}.bind(this));
        }else{
          this.myEffect.start({ 'margin-top': 0 }).chain(function(){	this.showSubMenuComplete();	}.bind(this));
        }
      }else{
        if (now) {
          this.myEffect.set({ 'margin-left': 0 }).chain(function(){	this.showSubMenuComplete();	}.bind(this));
        }else{
          this.myEffect.start({ 'margin-left': 0 }).chain(function(){	this.showSubMenuComplete();	}.bind(this));
        }
      }
    }else if(this.options.effect === 'fade' ){
      if (now) {
        this.myEffect.set({'opacity': this.options.opacity}).chain(function(){	this.showSubMenuComplete();	}.bind(this));
      }else{
        this.myEffect.start({'opacity': this.options.opacity}).chain(function(){	this.showSubMenuComplete();	}.bind(this));
      }
    }else if(this.options.effect == 'slide & fade'){
      this.childMenu.setStyles({'display':'block','visibility':'visible'});
      this.childMenu.getFirst().setStyles({'left':0});
      if (this.subMenuType === 'initial' && this.options.orientation === 'horizontal') {
        if (now) {
          this.myEffect.set({ 'margin-top': 0, 'opacity': this.options.opacity }).chain(function(){	this.showSubMenuComplete();	}.bind(this));
        }else{
          this.myEffect.start({ 'margin-top': 0, 'opacity': this.options.opacity }).chain(function(){	this.showSubMenuComplete();	}.bind(this));
        }
      }else{
        if (now) {
          if (this.options.direction.x === 'right') {
            this.myEffect.set({ 'margin-left': 0, 'opacity': this.options.opacity }).chain(function(){	this.showSubMenuComplete();	}.bind(this));
          }else if (this.options.direction.x === 'left') {
            this.myEffect.set({ 'margin-left': 0, 'opacity': this.options.opacity }).chain(function(){	this.showSubMenuComplete();	}.bind(this));
          }	
        }else{
          if (this.options.direction.x === 'right') {						
            this.myEffect.set({ 'margin-left': -this.width, 'opacity': this.options.opacity });						
            this.myEffect.start({ 'margin-left': 0, 'opacity': this.options.opacity }).chain(function(){	this.showSubMenuComplete();	}.bind(this));
          }else if (this.options.direction.x === 'left') {
            this.myEffect.start({ 'margin-left': 0, 'opacity': this.options.opacity }).chain(function(){	this.showSubMenuComplete();	}.bind(this));
          }
        }
      }
    }else{
      this.childMenu.setStyles({'display':'block','visibility':'visible'}).chain(function(){	this.showSubMenuComplete(this);	}.bind(this));
    }
    this.childMenu.store('status','open');
    
  },
  
  showSubMenuComplete:function(){		
    this.options.onShowSubMenu_complete(this);
  },
  
  positionSubMenu: function(){
    this.options.onPositionSubMenu_begin(this);
    this.childMenu.setStyle('width',this.width) ;
    this.childMenu.getFirst().setStyle('width',this.width) ;
        
    //if any parent has bounced off a viewport edge, inherit that new direction
    if (this.subMenuType === 'subsequent') {
      if(this.parentSubMenu && this.options.direction.x != this.parentSubMenu.options.direction.x){
        if(this.parentSubMenu.options.direction.x === 'left' && this.options.effect && this.options.effect.contains('slide')){
          this.myEffect.set({ 'margin-left': this.width });	
        }
      }
      this.options.direction.x = this.parentSubMenu.options.direction.x;
      this.options.direction.xInverse = this.parentSubMenu.options.direction.xInverse;
      this.options.direction.y = this.parentSubMenu.options.direction.y;
      this.options.direction.yInverse = this.parentSubMenu.options.direction.yInverse;
    }

    var top;
    var overlap
    if(this.subMenuType == 'initial'){
      if(	this.options.direction.y === 'up'){				
        if(this.options.orientation === 'vertical'){
          top = this.btn.getCoordinates().bottom - this.height + this.options.tweakInitial.y ;
        }else{			
          top = this.btn.getCoordinates().top - this.height + this.options.tweakInitial.y ;
        }
        this.childMenu.style.top = top+ 'px';
      }else if(this.options.orientation == 'horizontal'){
        this.childMenu.style.top = this.btn.getCoordinates().bottom + this.options.tweakInitial.y + 'px';
      }else if(this.options.orientation == 'vertical'){
        top = this.btn.getPosition().y + this.options.tweakInitial.y ;				
        if((top + this.childMenu.getSize().y) >= $(document.body).getScrollSize().y){
          overlap = (top + this.childMenu.getSize().y) - $(document.body).getScrollSize().y  ;
          top = top - overlap - 20;
        }	
        this.childMenu.style.top = top+ 'px';
      }
      if(	this.options.orientation == 'horizontal'){
        this.childMenu.style.left = this.btn.getPosition().x + this.options.tweakInitial.x + 'px';
      }else if(this.options.direction.x == 'left'){
        this.childMenu.style.left = this.btn.getPosition().x - this.childMenu.getCoordinates().width + this.options.tweakInitial.x + 'px';
      }else if(this.options.direction.x == 'right'){
        this.childMenu.style.left = this.btn.getCoordinates().right + this.options.tweakInitial.x + 'px';
      }
    }else if(this.subMenuType == 'subsequent'){
      
      if(this.options.direction.y === 'down'){
        if( (this.btn.getCoordinates().top + this.options.tweakSubsequent.y+ this.childMenu.getSize().y) >= $(document.body).getScrollSize().y ){
          overlap =  (this.btn.getCoordinates().top + this.options.tweakSubsequent.y+ this.childMenu.getSize().y) -$(document.body).getScrollSize().y  ;
          this.childMenu.style.top = (this.btn.getCoordinates().top + this.options.tweakSubsequent.y) - overlap - 20+ 'px';
        }else{
          this.childMenu.style.top = this.btn.getCoordinates().top + this.options.tweakSubsequent.y + 'px';
        }
      }else if(this.options.direction.y === 'up'){
        if((this.btn.getCoordinates().bottom - this.height + this.options.tweakSubsequent.y)< 1){
          this.options.direction.y = 'down';
          this.options.direction.yInverse = 'up';
          this.childMenu.style.top = this.btn.getCoordinates().top + this.options.tweakSubsequent.y + 'px';
        }else{
          this.childMenu.style.top = this.btn.getCoordinates().bottom - this.height + this.options.tweakSubsequent.y + 'px';
        }
      }
      if(this.options.direction.x == 'left'){
        this.childMenu.style.left = this.btn.getCoordinates().left - this.childMenu.getCoordinates().width + this.options.tweakSubsequent.x + 'px';
        
        if( this.childMenu.getPosition().x < 0){					
          this.options.direction.x = 'right';
          this.options.direction.xInverse = 'left';
          this.childMenu.style.left = this.btn.getPosition().x + this.btn.getCoordinates().width + this.options.tweakSubsequent.x + 'px';
          
          if(this.options.effect === 'slide' || this.options.effect === 'slide & fade'){
            this.myEffect.set({ 'margin-left': -this.width, 'opacity': this.options.opacity });						
          }
        }
      }else if(this.options.direction.x == 'right'){
        this.childMenu.style.left = this.btn.getCoordinates().right + this.options.tweakSubsequent.x + 'px';
        var smRight = this.childMenu.getCoordinates().right;
        var viewportRightEdge = document.getCoordinates().width + window.getScroll().x;				
        if( smRight > viewportRightEdge ){
          this.options.direction.x = 'left';
          this.options.direction.xInverse = 'right';
          this.childMenu.style.left = this.btn.getCoordinates().left - this.childMenu.getCoordinates().width + this.options.tweakSubsequent.x + 'px'
          if (this.options.effect === 'slide' || this.options.effect === 'slide & fade') {
            this.myEffect.set({	'margin-left': this.width,	'opacity': this.options.opacity	});
          }
        }
      }
    }
    this.options.onPositionSubMenu_complete(this);
  }	
});

