/**
 * Composant de gestion d'un menu déroulant
 *
 * - nécessite les bibliothèques suivantes : Prototype, jQuery, EventHandler
 *
 * @package    Connectikup
 * @subpackage skin
 * @author     Jean-Sébastien CONAN <jsconan@eskape.fr>
 * @version    SVN: $Id: menu.js 913 2009-09-01 13:24:27Z jsconan $
 */

var ctkMenuPage = Class.create({
  /**
   * @cfg String idHandle ID de l'élément 'poignée' reponsable du changement de direction du menu
   */
  idHandle: 'page_menu_handle'
  
  /**
   * @cfg String idLogout ID de l'élément de déconnexion
   */
  ,idLogout: 'page_menu_link'
  
  /**
   * @cfg String idMenuVer ID du container du menu en mode 'vertical'
   */
  ,idMenuVer: 'page_menu_ver'
  
  /**
   * @cfg String idMenuHor ID du container du menu en mode 'horizontal'
   */
  ,idMenuHor: 'page_menu_hor'
  
  /**
   * @cfg String idMenu ID du bloc de menu
   */
  ,idMenu: 'page_menu'
  
  /**
   * @cfg String idBar ID de la barre du bandeau à masque lorsque le menu est affiché en mode 'horizontal'
   */
  ,idBar: 'page_bandeau_barre'
  
  /**
   * @cfg String idLogo ID de l'élément logo à déplacer lorsque l'orientation du menu change
   */
  ,idLogo: 'page_entete_gauche'

  /**
   * @cfg String tagPanel Nom de la balise utilisée pour les panneaux de menu
   */
  ,tagPanel: 'ul'
  
  /**
   * @cfg String tagMenu Nom de la balise utilisée pour les entrées de menu
   */
  ,tagMenu: 'li'
  
  /**
   * @cfg String clsRoot Nom de la classe CSS des éléments racines du menu
   */
  ,clsRoot: 'page-menu-root'
  
  /**
   * @cfg String clsPanel Nom de la classe CSS des panneaux du menu
   */
  ,clsPanel: 'page-menu-panel'
  
  /**
   * @cfg String clsItem Nom de la classe CSS des entrées de menu
   */
  ,clsItem: 'page-menu-item'
  
  /**
   * @cfg String clsHandleHor Nom de la classe CSS donnant l'aspect 'horizontal' à la 'poignée' du menu
   */
  ,clsHandleHor: 'handle_hor'
  
  /**
   * @cfg String clsHandleHor Nom de la classe CSS donnant l'aspect 'vertical' à la 'poignée' du menu
   */
  ,clsHandleVer: 'handle_ver'
  
  /**
   * @cfg String imgRootOff Supplément dans le nom des images représentant les racines de menu donnant l'aspect inactif
   */
  ,imgRootOff: '_inactif'
  
  /**
   * @cfg String imgRootOn Supplément dans le nom des images représentant les racines de menu donnant l'aspect actif
   */
  ,imgRootOn: '_actif'
  
  /**
   * @cfg Number minWidth Largeur minimale des panneaux de menu
   */
  ,minWidth: 160
  
  /**
   * @cfg Number closeTimeout Délai, en millisecondes, avant fermeture automatique après que la souris soit sortie d'une racine ou d'un panneau de menu
   */
  ,closeTimeout: 250
  
  /**
   * @cfg String urlSetChangeDir URL de mémorisation du changement de direction du menu
   */
  ,urlSetChangeDir: REQUEST_HTTP_ROOT + 'accueil.php/skin/ajaxSetMenuDir'

  /**
   * Construction de l'objet
   * @param Object config Configuration supplémentaire pour l'instance en cours de création
   */
  ,initialize: function(config)
  {
    // configuration supplémentaire
    if( typeof(config) == 'object' ) Object.extend(this, config);
    
    // démarre la capture des évènements sur les contrôles du menu
    $J(document).ready(this.initOnReady.bindAsEventListener(this));
  }

  /**
   * Initialisation du menu au chargement de la page
   */
  ,initOnReady: function()
  {
    // fixe la position du logo
    try {
      var el = $(this.idLogo);
      var x = el._decal = parseInt(el.getStyle('marginLeft'));
      if( !this.isVertical() ) x += $(this.idMenuVer).getWidth();
      el.setStyle({marginLeft:x+'px'});
    } catch(e) {};
  
    // retire infobulles sur les éléments du menu
    $J('#' + this.idMenu + ' *').not('#' + this.idHandle + ',#' + this.idLogout).attr({title: "", alt: ""});
  
    // met en place les gestionnaires d'évènements
    $J('#' + this.idHandle).click(this.changeMenuDir.bindAsEventListener(this));
    $J('#' + this.idMenu + '>' + this.tagMenu + '.' + this.clsRoot).hover(
      this.overMenuEntry.bindAsEventListener(this)
      ,this.outMenuEntry.bindAsEventListener(this)
    );
    $J('#' + this.idMenu + ' ' + this.tagPanel + '.' + this.clsPanel).hide();
    $J(document).click(this.closeAllMenus.bindAsEventListener(this));
  }
  
  /**
   * Détecte l'orientation du menu
   * @return Boolean True si menu est vertical, false sinon
   */
  ,isVertical: function()
  {
    var el = $(this.idMenuVer);
    return el && el.visible();
  }

  /**
   * Changement de la direction d'affichage du menu
   * @param Event event Référence à l'objet de description de l'évènement
   */
  ,changeMenuDir: function(event)
  {
    // appel gestionnaire d'événement
    this.callHandler('beforeChangeMenuDir', this);

    // récupère référence aux éléments nécessaires
    var el = $(this.idHandle);
    var ver = $(this.idMenuVer);
    var hor = $(this.idMenuHor);
    var menu = $(this.idMenu);
    var bar = $(this.idBar);

    // masque les panneaux éventuellement affichés
    this.closeAllMenus();

    // détecte orientation du menu et agit en conséquence
    var vertical = this.isVertical();
    if( vertical )
    {
      // change apparence de la 'poignée'
      el.src = el.src.replace(this.clsHandleVer, this.clsHandleHor);
    
      // masque panneau vertical et affiche panneau horizontal
      hor.show();
      ver.hide();
      bar.hide();
      
      // déplace menu dans le panneau horizontal
      hor.appendChild(menu);
    }
    else
    {
      // change apparence de la 'poignée'
      el.src = el.src.replace(this.clsHandleHor, this.clsHandleVer);
    
      // masque panneau horizontal et affiche panneau vertical
      hor.hide();
      ver.show();
      bar.show();
      
      // déplace menu dans le panneau vertical
      ver.appendChild(menu);
    }
    
    // fixe la position du logo
    try {
      var el = $(this.idLogo);
      var x = el._decal;
      if( !this.isVertical() ) x += $(this.idMenuVer).getWidth();
      el.setStyle({marginLeft:x+'px'});
    } catch(e) {};

    // mémorise le changement
    if( this.urlSetChangeDir )
      $J.post(this.urlSetChangeDir, { menuVer: !vertical } );

    // appel gestionnaire d'événement
    this.callHandler('changeMenuDir', this);
  }
  
  /**
   * Retrouve la référence au panneau d'un menu
   * @param Element menu Référence au menu pour lequel trouver le panneau associé
   * @return Element Renvoie la référence au panneau
   */
  ,getMenuPanel: function(menu)
  {
    if( !menu ) return null;
    
    if( (typeof(menu._panel) == 'undefined') || !menu._panel )
      menu._panel = menu.down(this.tagPanel);
      
    var panel = menu._panel;
    if( !panel ) return null;
    
    if( (typeof(panel._parent) == 'undefined') || !panel._parent )
      panel._parent = menu;

    return panel;
  }
  
  /**
   * Retrouve le menu cible d'un événement
   * @param Event event référence à l'événement
   * @return Element Référence au menu ciblé
   */
  ,getMenuEvent: function(event)
  {
    // repère l'élément menu
    if( !event ) event = window.event;
    var menu = Event.element(event);
    if( menu.tagName != this.tagMenu.toUpperCase() )
      menu = menu.up(this.tagMenu);
    return menu;
  }
  
  /**
   * Ferme tous les panneaux de menu
   */
  ,closeAllMenus: function()
  {
    $$('#' + this.idMenu + '>' + this.tagMenu + '.' + this.clsRoot).each(this.closeMenu);
  }
  
  /**
   * Ferme un panneau de menu
   * @param Element menu Référence au menu à fermer
   */
  ,closeMenu: function(menu)
  {
    if( typeof(menu._panel) != 'undefined' ) menu._panel.hide();
    var img = menu.down('img');
    if( img && (typeof(img._src) != 'undefined') ) img.src = img._src;
  }
  
  /**
   * Survol d'un élément de menu
   * @param Event event Référence à l'objet de description de l'évènement
   */
  ,overMenuEntry: function(event)
  {
    // repère l'élément de menu
    var menu = this.getMenuEvent(event);
      
    // masque les panneaux éventuellement affichés
    this.closeAllMenus();
      
    // image sur l'entrée ?
    var img = menu.down('img');
    if( img )
    {
      if( typeof(img._src) == 'undefined' ) img._src = img.src;
      img.src = img.src.replace(this.imgRootOff, this.imgRootOn);
    }

    // affiche le panneau
    var panel = this.getMenuPanel(menu);
    if( panel )
    {
      this.placePanel(panel);
      panel.show();
    }
  }
  
  /**
   * Fin de survol d'un élément de menu
   * @param Event event Référence à l'objet de description de l'évènement
   */
  ,outMenuEntry: function(event)
  {
    // repère l'élément de menu, puis le masque
    var menu = this.getMenuEvent(event);
    this.closeMenu(menu);
  }
  
  /**
   * Positionne correctement un panneau en fonction de l'orientation générale du menu
   * @param Element panel Référence au panneau à positionner
   */
  ,placePanel: function(panel)
  {
    // retrouve le menu parent
    if( !panel ) return;
    var menu = panel._parent ? panel._parent : panel.up(this.tagMenu);
    if( menu )
    {
      // obtient les dimension et la position du menu
      var pos = menu.cumulativeOffset();
      var dim = menu.getDimensions();
      var vertical = this.isVertical();

      // calque la position du panneau en fonction du menu et de son orientation
      panel.setStyle({
        left: (pos.left + (vertical ? dim.width : parseInt(panel.getStyle('borderLeftWidth')))) + 'px'
        ,top: (pos.top + (vertical ? parseInt(panel.getStyle('borderTopWidth')) : dim.height)) + 'px'
      });
    }
    
    // largeur minimale du panneau
    if( panel.getWidth() < this.minWidth )
      panel.setStyle({width:this.minWidth+'px'});
    
    // redimensionne les éléments de menu sous Internet Explorer
    if( $J.browser.msie ) this.forceMenuItemWidth(panel);
  }
  
  /**
   * Force la largeur des éléments d'un panneau de menu
   * @param Element panel Référence à l'élément panneau à traiter
   */
  ,forceMenuItemWidth: function(panel)
  {
    var selector = this.tagMenu + '.' + this.clsItem;
    var item = panel.down(selector);
    if( item )
    {
      // calcule la largeur commune à tous les éléments inclus dans le panneau
      var newWidth = panel.getWidth()
                   - parseInt(item.getStyle('paddingLeft'))
                   - parseInt(item.getStyle('paddingRight'))
                   - parseInt(item.getStyle('marginLeft'))
                   - parseInt(item.getStyle('marginRight'))
                   - parseInt(item.getStyle('borderLeftWidth'))
                   - parseInt(item.getStyle('borderRightWidth'))
                   - parseInt(panel.getStyle('paddingLeft'))
                   - parseInt(panel.getStyle('paddingRight'));
                   
      // force la largeur pour chaque élément inclus
      $J(panel).find(selector).width(newWidth);
    }
  }
});

// incorpore le mécanisme de gestion d'événements sur la classe
Object.extend(ctkMenuPage.prototype, EventHandlerMultiInterface);

