/**
 *  Eskape JavaScript framework
 *  (c) 2007 Eskape
 *
 *  Nécessite les frameworks suivants :
 *  - Prototype 1.5.0
 *  - Script.aculo.us 1.7.0
 *  - StdLib 1.0
 *
 * @version 1.0.0
 * @date 2007-09-05
 *
 */


// {{{ Eskape
/**
 * Objet maître de la bibliothèque
 */
var Eskape = {
  version: '1.0.0'
};
// }}}

// {{{ Eskape.MenuBar
/**
 * Classe gestionnaire de menus
 */
Eskape.MenuBar = Class.create();
Eskape.MenuBar.prototype = {

	// {{{ classes
	/**
	 * Nom de classe des éléments de menu
	 * @var Object
	 */
	classes: {
		header: 'menuHeader',
		panel: 'menuPanel',
		item: 'menuItem'
	},
	// }}}

 	// {{{ names
 	/**
 	 * Nom de base des ID pour les éléments de menu
 	 * @var Object
 	 */
	names: {
	  header: 'mh',
	  panel: 'mp',
		item: 'mi'
	},
	// }}}

 	// {{{
	/**
	 * Gestionnaires d'évènements associés à chaque catégorie d'éléments de menus
	 * @var Objects
	 */
	events: {
	  header: {
			onmouseover: function(e)
			{
			  if( this.menuPanel )
				{
				  setObjectX(this.menuPanel, getObjectXPage(this));
				  setObjectY(this.menuPanel, getObjectYPage(this) + getObjectHeight(this));

					this.menuPanel.onmouseover(e);
				}
			},

			onmouseout: function(e)
			{
			  if( this.menuPanel )
				{
				  this.menuPanel.onmouseout(e);
				}
			}
		},

		panel: {
		  onmouseover: function(e)
			{
			  if( this._displayed ) return;
		    if( this._closeTimer )
		    {
		      window.clearTimeout(this._closeTimer);
		      this._closeTimer = null;
				}

			  //this.showPanel();
				this._openTimer = window.setTimeout("$('"+this.id+"').showPanel();", this.eskapeMenuBar.openDelay);
			},

			onmouseout: function(e)
			{
			  if( !this._displayed ) return;
			  if( this._openTimer )
		    {
		      window.clearTimeout(this._openTimer);
		      this._openTimer = null;
		      return;
				}
			
			  this._closeTimer = window.setTimeout("$('"+this.id+"').hidePanel();", this.eskapeMenuBar.closeDelay);
			},

			showPanel: function()
			{
			  this._openTimer = null;
				if( this._displayed ) return;

				new Effect.Parallel([
					new Effect.Opacity(this, { sync:true, from:0.5, to:1 }),
				  new Effect.SlideDown(this, { sync:true })
					], {
					  duration:0.3,
						queue: {
							scope:this.id,
							position:'end',
							limit:2
						}
					}
				);

				this._displayed = true;
			},

			hidePanel: function()
			{
			  this._closeTimer = null;
				if( !this._displayed ) return;

				new Effect.Parallel([
				  new Effect.DropOut(this, { sync:true })
					], {
					  duration:0.3,
						queue: {
							scope:this.id,
							position:'end',
							limit:2
						}/*,
						afterFinish: function(effect) {
						  Element.hide(effect.effects[0].element);
						}*/
					}
				);

				this._displayed = false;
			}
		},

		item: {
    	onmouseover: function(e)
			{
			  if( this.menuPanel )
				{
				  setObjectX(this.menuPanel, getObjectXPage(this) + getObjectWidth(this));
				  setObjectY(this.menuPanel, getObjectYPage(this));

					this.menuPanel.onmouseover(e);
				}
			},

			onmouseout: function(e)
			{
			  if( this.menuPanel )
				{
				  this.menuPanel.onmouseout(e);
				}
			}
		}
	},
	// }}}

	// {{{ list
	/**
	 * Liste des éléments de menus
	 * @var Object
	 */
	list: {
	  header: null,
	  panel: null,
	  item: null
	},
	// }}}
	
	// {{{ openDelay
	/**
	 * Délais d'attente avant la fermeture des menus
	 * @var Number
	 */
	openDelay: 100,
	// }}}
	
	// {{{ closeDelay
	/**
	 * Délais d'attente avant la fermeture des menus
	 * @var Number
	 */
	closeDelay: 250,
	// }}}

	// {{{ initialize
	/**
	 * Construction de l'instance
	 * @param String|Element parent ID ou référence à l'objet contenant les menus
	 * @param Object options Objet JSON apportant des modification au gestionnaire de menus
	 * <code>
	 * {
	 *     // Nom de classe des éléments de menu
	 *   classes: {
	 *     header: 'menuHeader',    // en-tête de menu
	 *     panel: 'menuPanel',      // conteneur de menus et sous-menus
	 *     item: 'menuItem',        // entrée de menu
	 *   },
	 *     // Nom de base des ID pour les éléments de menu
	 *   names: {
	 *     header: 'mh',   // en-tête de menu
	 *     panel: 'mp',    // conteneur de menus et sous-menus
	 *     item: 'mi',     // entrée de menu
	 *     subItem: 'si',  // entrée de sous-menu
	 *   },
	 *     // Délais d'attente avant la fermeture des menus
	 *   delay: 250,
	 * }
	 * </code>
   * @access private
	 */
  initialize: function(parent, options)
  {
		if( parent ) this.parent = $(parent);
		if( !this.parent ) this.parent = document;

    if( options )
    {
      if( options.classes )
      {
        if( options.classes.header ) this.classes.header = options.classes.header;
				if( options.classes.panel ) this.classes.item = options.classes.panel;
				if( options.classes.item ) this.classes.item = options.classes.item;
			}
			
			if( options.names )
      {
        if( options.names.header ) this.names.header = options.names.header;
				if( options.names.panel ) this.names.item = options.names.panel;
				if( options.names.item ) this.names.item = options.names.item;
			}
			
			if( options.openDelay ) this.openDelay = options.openDelay;
			if( options.closeDelay ) this.closeDelay = options.closeDelay;
		}
		
		this.listAll();
		this.register();
	},
	// }}}
	
	// {{{ listAll
	/**
	 * Établit la liste des éléments constituant les menus
   * @access public
	 */
	listAll: function()
	{
	  this.list = {
			header: this.parent.getElementsByClassName(this.classes.header),
			panel: this.parent.getElementsByClassName(this.classes.panel),
			item: this.parent.getElementsByClassName(this.classes.item)
	  };
	},
	// }}}
	
	// {{{ unregister
	/**
	 * Désactive la gestion des menus : retire les gestionnaires pour chaque catégorie d'éléments du menu
   * @access public
	 */
	unregister: function()
	{
	  // détruit les liaisons et retires les gestionnaires
	  this.unmount(this.list.header, this.events.header);
	  this.unmount(this.list.panel, this.events.panel);
	  this.unmount(this.list.item, this.events.item);
	},
	// }}}
	
	// {{{ register
	/**
	 * Active la gestion des menues : enregistre les gestionnaires pour chaque catégorie d'éléments du menu
   * @access public
	 */
	register: function()
	{
	  // construit les structures et enregistre les gestionnaires
	  this.mount(this.list.header, this.events.header);
	  this.mount(this.list.panel, this.events.panel);
	  this.mount(this.list.item, this.events.item);
	},
	// }}}
	
	// {{{ unmount
	/**
	 * Retire les gestionnaires d'évènements associés à une collection d'éléments
	 * @param Array collection : Tableau d'éléments desquels retirer les gestionnaires
	 * @param Object events : Objet JSON listant les gestionnaires associés (eventName: function())
	 * @access private
	 */
	unmount: function(collection, events)
	{
	  if( !collection || !events ) return;
	  var i;
	  for(i = 0; i < collection.length; i++)
	  {
	    for(var e in events)
	      collection[i][e] = null;

			collection[i].eskapeMenuBar = null;
			collection[i].menuPanel = null;
		}
	},
	// }}}
	
	// {{{ mount
	/**
	 * Construit les liaisons entres les éléments des menus.
	 * Associe des gestionnaires d'évènements à une collection d'éléments.
	 * @param Array collection : tableau d'éléments auxquels associer les gestionnaires
	 * @param Object events : objet JSON listant les gestionnaire à associer (eventName: function())
	 * @access private
	 */
	mount: function(collection, events)
	{
	  if( !collection || !events ) return;
	  var i;
	  for(i = 0; i < collection.length; i++)
	  {
	  	var el = $(collection[i].id + this.names.panel)
      collection[i].menuPanel = el ? el : null;
	  	collection[i].eskapeMenuBar = this;

	  	Object.extend(collection[i], events);
		}
	}
	// }}}
};
// }}}


// {{{ isValidNumber
/**
 * Détermine si une chaîne représente un nombre valide
 * @param boolean intsOnly : Demande la présence d'un entier uniquement, sinon tolère les rééls
 */
String.prototype.isValidNumber = function ( intsOnly )
{
  text = this ;
  if( typeof( intsOnly == 'undefined' ) ) intsOnly = true ;
  text = text.replace(/^\s+|\s+$/g, '') ;
  var value = intsOnly ? parseInt( text, 10 ) : parseFloat( text ) ;
  return String( value ) === text ;
}
// }}}


// {{{ isIE
/**
 * Détection du navigateur
 */
var isIE = document.all ? true : false;
// }}}


// {{{ rand
/**
 * Retourne une valeur entière aléatoire
 *
 * @param integer max Valeur maximale
 * @return integer Retourne une valeur aléatoire entre 0 et max-1
 */
function rand(max)
{
  if( typeof(max) == 'undefined' ) max = 100;
  return Math.floor( Math.random() * max );

}
// }}}


// {{{ getWindowWidth
/**
 * Lecture de la largeur de la fenêtre
 *
 * @return integer Largeur de la fenêtre
 */
getWindowWidth = function()
{
  if( isIE ) return Math.max(document.documentElement.clientWidth, document.body.clientWidth);
  else return window.innerWidth;
}
// }}}


// {{{ getWindowHeight
/**
 * Lecture de la hauteur de la fenêtre
 *
 * @return integer Hauteur de la fenêtre
 */
getWindowHeight = function()
{
  if( isIE ) return Math.max(document.documentElement.clientHeight, document.body.clientHeight);
  else return window.innerHeight;
}
// }}}


// {{{ getPageWidth
/**
 * Lecture de la largeur de la page
 *
 * @return integer Largeur de la page
 */
getPageWidth = function()
{
  if( isIE ) return Math.max(document.documentElement.scrollWidth, document.body.scrollWidth);
  else return document.width;
}
// }}}


// {{{ getPageHeight
/**
 * Lecture de la hauteur de la page
 *
 * @return integer Hauteur de la page
 */
getPageHeight = function()
{
  if( isIE ) return Math.max(document.documentElement.scrollHeight, document.body.scrollHeight);
  else return document.height;
}
// }}}


// {{{ getPageX
/**
 * Lecture de la position horizontale de la fenêtre dans la page
 *
 * @return integer Position horizontale de la fenêtre
 */
getPageX = function()
{
  if( isIE ) return Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
  else return window.pageXOffset;
}
// }}}


// {{{ getPageY
/**
 * Lecture de la position verticale de la fenêtre dans la page
 *
 * @return integer Position verticale de la fenêtre
 */
getPageY = function()
{
  if( isIE ) return Math.max(document.documentElement.scrollTop, document.body.scrollTop);
  else return window.pageYOffset;
}
// }}}


// {{{ setObjectContent
/**
 * Modifie le contenu d'un objet HTML
 *
 * @param object obj Objet dont il faut modifier le contenu
 * @param string text Nouveau contenu
 */
setObjectContent = function(obj, text)
{
  if( obj ) obj.innerHTML = text;
}
// }}}


// {{{ getObjectContent
/**
 * Retourne le contenu d'un objet HTML
 *
 * @param object obj Objet dont il faut modifier le contenu
 * @return string Contenu de l'objet
 */
getObjectContent = function(obj)
{
  if( obj )
  {
    var value = obj.innerHTML;
    if( typeof(value) == 'undefined' ) return '';
    return value;
  }
  return '';
}
// }}}


// {{{ setObjectCSS
/**
 * Modifie la classe de style CSS d'un objet HTML
 *
 * @param object obj Objet dont il faut modifier la classe
 * @param string css Nouvelle classe CSS
 */
setObjectCSS = function(obj, css)
{
  if( obj ) obj.className = css;
}
// }}}


// {{{ getObjectCSS
/**
 * Retourne la classe de style CSS d'un objet HTML
 *
 * @param object obj Objet dont il faut modifier la classe
 * @return string Classe CSS de l'objet HTML
 */
getObjectCSS = function(obj)
{
  if( obj )
  {
    var value = obj.className;
    if( typeof(value) == 'undefined' ) return '';
    return value;
  }
  return '';
}
// }}}


// {{{ setObjectStyle
/**
 * Modifie le style d'un objet HTML
 *
 * @param object obj Objet dont il faut modifier le style
 * @param string style Description du style à appliquer
 */
if( isIE ) setObjectStyle = function(obj, style) { if( obj ) obj.style.setAttribute("cssText", style); };
else setObjectStyle = function(obj, style) { if( obj ) obj.setAttribute("style", style); };
// }}}


// {{{ hideObject
/**
 * Masque un objet HTML
 *
 * @param object obj Objet qui doit être masqué
 */
hideObject = function(obj)
{
  if( obj ) obj.style.visibility = 'hidden';
}
// }}}


// {{{ showObject
/**
 * Affiche un objet HTML
 *
 * @param object obj Objet qui doit être affiché
 */
showObject = function(obj)
{
  if( obj ) obj.style.visibility = 'visible';
}
// }}}


// {{{ displayObjectNone
/**
 * Efface un objet HTML
 *
 * @param object obj Objet qui doit être effacé
 */
displayObjectNone = function(obj)
{
  if( obj ) obj.style.display = 'none';
}
// }}}


// {{{ displayObject
/**
 * Replace un objet effacé
 *
 * @param object obj Objet qui doit être replacé
 * @param string displayType Mode d'affichage à restaurer (par défaut block)
 */
displayObject = function(obj, displayType)
{
  if( typeof(displayType) == 'undefined' ) displayType = 'block';
  if( obj ) obj.style.display = displayType;
}
// }}}


// {{{ moveObjectTo
/**
 * Déplace un objet HTML
 *
 * @param object obj Objet à déplacer
 * @param integer x Position horizontale
 * @param integer y position verticale
 */
moveObjectTo = function(obj, x, y)
{
  if( obj )
  {
    if( !x ) x = 0;
    if( !isNaN(x) ) x += 'px';
    if( !y ) y = 0;
    if( !isNaN(y) ) y += 'px';
    obj.style.left = x;
    obj.style.top = y;
  }
}
// }}}


// {{{ setObjectX
/**
 * Déplace un objet HTML horizontalement
 *
 * @param object obj Objet à déplacer
 * @param integer x Position horizontale
 */
setObjectX = function(obj, x)
{
  if( obj )
  {
    if( !x ) x = 0;
    if( !isNaN(x) ) x += 'px';
    obj.style.left = x;
  }
}
// }}}


// {{{ setObjectY
/**
 * Déplace un objet HTML verticalement
 *
 * @param object obj Objet à déplacer
 * @param integer y Position verticale
 */
setObjectY = function(obj, y)
{
  if( obj )
  {
    if( !y ) y = 0;
    if( !isNaN(y) ) y += 'px';
    obj.style.top = y;
  }
}
// }}}


// {{{ setObjectZ
/**
 * Modifie l'indice de superposition d'un objet HTML
 *
 * @param object obj Objet à modifier
 * @param integer z Indice de superposition
 */
setObjectZ = function(obj, z)
{
  if( obj ) obj.style.zIndex = z ? z : 1;
}
// }}}


// {{{ resizeObjectTo
/**
 * Redimensionne un objet HTML
 *
 * @param object obj Objet à modifier
 * @param integer w Largeur
 * @param integer h Hauteur
 */
resizeObjectTo = function(obj, w, h)
{
  if( obj )
  {
    if( !w ) w = 0;
    if( !isNaN(w) ) w += 'px';
    if( !h ) h = 0;
    if( !isNaN(h) ) h += 'px';
    obj.style.width = w;
    obj.style.height = h;
  }
}
// }}}


// {{{ setObjectWidth
/**
 * Modifie la largeur d'un objet HTML
 *
 * @param object obj Objet à modifier
 * @param integer w Largeur
 */
setObjectWidth = function(obj, w)
{
  if( obj )
  {
    if( !w ) w = 0;
    if( !isNaN(w) ) w += 'px';
    obj.style.width = w;
  }
}
// }}}


// {{{ setObjectHeight
/**
 * Modifie la hauteur d'un objet HTML
 *
 * @param object obj Objet à modifier
 * @param integer h Largeur
 */
setObjectHeight = function(obj, h)
{
  if( obj )
  {
    if( !h ) h = 0;
    if( !isNaN(h) ) h += 'px';
    obj.style.height = h;
  }
}
// }}}


// {{{ getObjectX
/**
 * Retourne la position horizontale d'un objet HTML par rapport à son conteneur
 *
 * @param object obj Objet à interroger
 * @return integer Position horizontale de l'objet
 */
getObjectX = function(obj)
{
  if( obj ) return obj.offsetLeft;
  return 0;
}
// }}}


// {{{ getObjectY
/**
 * Retourne la position verticale d'un objet HTML par rapport à son conteneur
 *
 * @param object obj Objet à interroger
 * @return integer Position verticale de l'objet
 */
getObjectY = function(obj)
{
  if( obj ) return obj.offsetTop;
  return 0;
}
// }}}


// {{{ getObjectXPage
/**
 * Retourne la position horizontale d'un objet HTML dans la page
 *
 * @param object obj Objet à interroger
 * @return integer Position horizontale de l'objet
 */
getObjectXPage = function(obj)
{
  if( obj )
  {
    if( obj.offsetParent ) return obj.offsetLeft + getObjectXPage(obj.offsetParent);
    else return obj.offsetLeft;
  }
  return 0;
}
// }}}


// {{{ getObjectYPage
/**
 * Retourne la position verticale d'un objet HTML dans la page
 *
 * @param object obj Objet à interroger
 * @return integer Position verticale de l'objet
 */
getObjectYPage = function(obj)
{
  if( obj )
  {
    if( obj.offsetParent ) return obj.offsetTop + getObjectYPage(obj.offsetParent);
    else return obj.offsetTop;
  }
  return 0;
}
// }}}


// {{{ getObjectZ
/**
 * Retourne l'indice de superposition d'un objet HTML
 *
 * @param object obj Objet à interroger
 * @return integer Indice de superposition de l'objet
 */
getObjectZ = function(obj)
{
  if( obj )
  {
    var z = obj.style.zIndex;
    return z ? z : 0;
  }
  return 0;
}
// }}}


// {{{ getObjectWidth
/**
 * Retourne la largeur d'un objet HTML
 *
 * @param object obj Objet à interroger
 * @return integer Largeur de l'objet
 */
getObjectWidth = function(obj)
{
  if( obj ) return obj.offsetWidth;
  return 0;
}
// }}}


// {{{ getObjectHeight
/**
 * Retourne la hauteur d'un objet HTML
 *
 * @param object obj Objet à interroger
 * @return integer Hauteur de l'objet
 */
getObjectHeight = function(obj)
{
  if( obj ) return obj.offsetHeight;
  return 0;
}
// }}}
