/* Menu Javascript library, version 2.0b
 * (c) July 2006 Elmar Keij
 *
 * Description:
 *   TODO
 *
 * Usage:
 *   TODO
 */

var Menu =  Class.create();
Menu.prototype = {
  animating : false,
  effects : [],
  events: [],
  showingSubmenu : null,
  timeoutId: null,
  count: 0,

  initialize: function(menu, options){
    // set all the options
    this.options = options || {};
    this.menuName = this.options.menuName || 'menu';
    this.menuItemName = this.options.menuItemName || 'menu_item';
    this.submenuName = this.options.submenuName || 'submenu';
    this.submenuItemName = this.options.submenu || 'submenu_item';
    this.animation = this.options.animation || 'slide';
    this.selectedBackground = this.options.selectedBackground || '#FFFFFF';
    this.normalBackground = this.options.normalBackground || '#000000';

    this.menu = $(menu);
    this.menuItems = $$('.' + this.menuItemName);

    this.menuHandler = this._constructAnimation.bindAsEventListener(this);
    for(var i = 0; menuItem = this.menuItems[i]; i++){
      Event.observe(menuItem, 'mouseover', this.menuHandler);
      Event.observe(menuItem, 'mouseout', this.menuHandler);
      var submenus = menuItem.getElementsByClassName(this.submenuName);
      if(submenus.length > 0) {
        menuItem.submenu = submenus[0];
        menuItem.submenu.setStyle($H({display: 'none', visibility: 'visible'}));
        menuItem.submenu.dimensions = menuItem.submenu.getDimensions();
      }
    }
  },

  _constructAnimation: function(event){
    var menuItem = this.findElement(event, this.menuItemName)
    var from = Event.fromElement(event);
    var to = Event.toElement(event);
    if(!to || !from)
      return;

    // Enable menuItem
    if ((to == menuItem || to.childOf(menuItem))) {
      if(menuItem._enabled)
        return;
      menuItem._enabled = true;
    }
    // Disable menuItem
    else if ((from == menuItem || from.childOf(menuItem)) && (to != menuItem && !to.childOf(menuItem))){
      if(!menuItem._enabled)
        return;
      menuItem._enabled = false;
    }

    var submenu = menuItem.submenu
    var effects = [];

    if(menuItem._enabled) {
      if(!this.selectedBackground) {
        throw("Menu.mouseOverHandler: selectedBackground not set")
      }
      menuItem.style.background = this.selectedBackground;

      if(!submenu || this.showingSubmenu == submenu){
        return;
      }
      this.submenuShow(submenu, effects);
      if (this.showingSubmenu) {
        this.submenuHide(this.showingSubmenu, effects)
        this.showingSubmenu = submenu;
      }
    } else {
      if(!this.normalBackground) {
        throw("Menu.mouseOutHandler: normalBackground not set")
      }
      menuItem.style.background = this.normalBackground;
      if(submenu) {
        this.submenuHide(submenu, effects);
        this.showingSubmenu = null;
      }
    }

    this._doAnimation(effects);
  },

  _doAnimation: function(effects) {
    // perform the queued effects in parallel;
    new Effect.Parallel(effects, {
      sync: true,
      queue: {
        position: 'end',
        scope: 'menuAnimation'
      },
      afterFinish: function() {
        this.effects = [];
      }.bind(this)
    });
  },

  submenuShow: function(submenu, effects){
    element = $(submenu).cleanWhitespace();
    oldInnerBottom = element.down().getStyle('bottom');

    effects.push(
      new Effect.Scale(element, 100, {
        duration: 0.45,
        scaleContent: false,
        scaleX: false,
        scaleMode: {originalHeight: submenu.dimensions.height, originalWidth: submenu.dimensions.width},
        scaleFrom: window.opera ? 0 : 1,
        transition: Effect.Transitions.sinoidal,
        restoreAfterFinish: true,
         afterSetup: function(effect) {
          effect.element.makePositioned();
          effect.element.down().makePositioned();
          if(window.opera) effect.element.setStyle({top: ''});
            effect.element.makeClipping().setStyle({height: '0px'}).show();
        },
        afterUpdateInternal: function(effect) {
          effect.element.down().setStyle({bottom:
            (effect.dims[0] - effect.element.clientHeight) + 'px' });
        },
        afterFinishInternal: function(effect) {
          effect.element.undoClipping().undoPositioned();
          effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom});
        }
      })
    );
  },

  submenuHide: function(submenu, effects){
    element = $(submenu).cleanWhitespace();
    oldInnerBottom = element.down().getStyle('bottom');

    effects.push(
      new Effect.Scale(element, window.opera ? 0 : 1,{
        duration: 0.45,
        scaleContent: false,
        scaleX: false,
        scaleMode: {originalHeight: submenu.dimensions.height, originalWidth: submenu.dimensions.width},
        scaleFrom: 100,
        transition: Effect.Transitions.sinoidal,
        restoreAfterFinish: true,
         beforeStartInternal: function(effect) {
          effect.element.makePositioned();
          effect.element.down().makePositioned();
          if(window.opera) effect.element.setStyle({top: ''});
            effect.element.makeClipping().show();
        },
        afterUpdateInternal: function(effect) {
          effect.element.down().setStyle({bottom:
            (effect.dims[0] - effect.element.clientHeight) + 'px' });
        },
        afterFinishInternal: function(effect) {
          effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom});
            effect.element.down().undoPositioned();
        }
      })
    );
  },

  findElement : function(event, className) {
    var element = Event.element(event);
    while (element.parentNode && (!element.className ||
        (element.className.toUpperCase() != className.toUpperCase())))
      element = element.parentNode;
    return element;
  }
}