var branch;

/* Le paramètre correspond à l'élément racine du menu */
function dropdownMenu(navid) {
	/* On fait quelques tests pour certains naviguateurs */
	var isopera = typeof window.opera != 'undefined';
	/* Est ce que Script marche ("document.all" est du Jscript, pas du javascript) */
	var isie = typeof document.all != 'undefined'
		&& !isopera && navigator.vendor != 'KDE';
	if(isie && /msie 8/i.test(navigator.userAgent)) { isie = false; }
	var issafari = navigator.vendor == 'Apple Computer, Inc.';

	if (typeof document.getElementById == 'undefined'
		|| (issafari && typeof window.XMLHttpRequest == 'undefined')
		|| (isie && typeof document.uniqueID == 'undefined')) {
		return;
	}
	
	/* récupération de l'objet correspondant à l'élément racine */
	var tree = document.getElementById(navid);
	if (tree) {
		/* 
			La fonction "indexOf" retourne la position d'une sous-chaîne (lettre ou groupe de lettres) dans une chaîne de caractère,
			en effectuant la recherche de gauche à droite .
			En l'occurence, la classe de l'objet "tree" est "horizontal". La fonction renvoie donc 0 (début de la chaîne).
			Si la fonction ne trouve pas la sous string, elle renvoie -1.
		*/
		var horiz = tree.className.indexOf('horizontal') != -1;
		branch = tree;
		
		/* Récupération des éléments "li" */
		var items = tree.getElementsByTagName('li');
		for (var i = 0; i < items.length; i++) {
			/* Appel à la fonction "dropdownTrigger" définie plus bas. */
			dropdownTrigger(tree, items[i], navid, isie, horiz);
			
		}
		
		/* Exécution de la boucle si le naviguateur n'est pas Opéra. */
		/* Boucle servant au déplacement via les touches du clavier. */
		if (!isopera) {
			cleanUselessWhitespace(tree);
			var keyevent = issafari || isie ? 'keydown' : 'keypress';
			attachEventListener(document, keyevent, function(e) {
				if(e.cmdKey || e.metaKey) {
					return true;
				}
		
				var target = typeof e.target != 'undefined'
					? e.target : e.srcElement;
        
				if (tree.contains(target) && target.getAttribute('href')) {
					if (/^(37|38|39|40)$/.test(e.keyCode.toString())) {
						arrowKeyNavigation(tree, target, e.keyCode, horiz);

						if (typeof e.preventDefault != 'undefined') {
							e.preventDefault();
						}
						return false;
					}
				}
				return true;
			}, false);
		}
		
	/* 
		Récupération de l'ensemble des éléments du documents:
			- utilisation de "document.all pour Jscript
			- utilisation de "document.getElementsByTagName('*')" si Jscript ne marche pas
	*/
    var eles = typeof document.all != 'undefined'
        ? document.all : document.getElementsByTagName('*');
	
    for (i = 0; i < eles.length; i++) {
      /* On attache un évênement à chaque élément: A chaque fois qu'on cliquera sur un élément, la fonction définie se lancera */
	  attachEventListener(eles[i], 'focus', function(e)
      {
		/* S'il s'agit d'un lien, la variable sera l'adresse du site pointé */
        var target = typeof e.target != 'undefined'
            ? e.target : e.srcElement;

        if (!tree.contains(target)) {
		  resetSiblingBranches(items[0]);
        }
      }, false);
    }
	
	/* Si Jscript ne marche pas: */
    if (!isie) {
		/* Création d'une fonction */
		tree.contains = function(node) {
			if (node == null) {
				return false;
			}
			if (node == this) {
				return true;
			}
			else { 
				return this.contains(node.parentNode);
			}
		};
    }
  }
}

/* Déclaration d'une fonction */
function dropdownTrigger(tree, li, navid, isie, horiz) {
	/*
		tree = élément racine
		li = un élément "li"
		navid = nom de l'id de l'élément racine
		isie = booleen valant vrai si Jscript marche, false sinon
		horiz = booléen valant true si l'index auquel "horizontal" apparaît dans le nom de la classe de l'élément racine
	*/
	
	var opentime, closetime;
	/* La variable a équivaut à l'adresse pointée dans l'élément "li" */
	var a = li.getElementsByTagName('a')[0];

	/*
		On compte le nombre de sous listes de chaque éléments li.
		S'il y a au moins une sous liste, on prend la première
	*/
	var menu = li.getElementsByTagName('ul').length > 0
		? li.getElementsByTagName('ul')[0] : null;

	/* issub vaut true si le parent de l'élément "li" est l'élément racine */
	var issub = li.parentNode.id == navid;
	
	/* S'il y a au moins une sous liste */
	if (menu) {
		li.className += (li.className == '' ? '' : ' ') + 'hasmenu';
	}
	
	/* ajout d'un évènement à chaque fois qu'on cliquera sur un lien */
	attachEventListener(a, 'focus', function(e) {
		/* Méthode suspendant la minuterie "closetime" déclarée par la méthode "setTimeout" */
		clearTimeout(closetime);
		
		/* Quand on clique sur un lien, on ajoute une classe "rollover" à celui-ci */
		a.className += (a.className == '' ? '' : ' ') + 'rollover';
		
		/* ?? */
		resetSiblingBranches(li);
		
		if (menu) {
			/* Appel à la méthode "showMenu" définie plus bas */
			/* Pour les éléments "li" qui ont des sous listes, c'est nécessaire pour faire marcher les liens */
			showMenu(menu, horiz, issub, li, a, isie);
		}
		
		/* Récupération du parent de l'élément "li" */
		var parent = li.parentNode;
		/* Si ce parent n'est pas un élément de "premier niveau" */
		if (parent != tree) {
			if (parent.style.left == '' || parent.style.left == '-100em') {
				/* Appel à la fonction "showAncestor" */
				showAncestors(tree, parent, horiz, issub, isie);
			}

			if (toggleSelects('visible') && tree.contains(e.srcElement)) {
				toggleSelects('hidden');
			}
		}
	}, false);
	
	/* De même, on définit une fonction quand la souris est sur l'élément "li" en question */var index=0;
	attachEventListener(li, 'mouseover', function(e) {
		if (unwantedTextEvent()) {
			return;
		}
		
		/* Méthode suspendant la minuterie "closetime" déclarée par la méthode "setTimeout" */	
		clearTimeout(closetime);
		
		/* On regarde si la variable "branch" initialisée comme étant "tree" vaut "li" */
		if (branch == li) { 
			branch = null;
		}
		
		/* Modification de la classe du lien */
		a.className += (a.className == '' ? '' : ' ') + 'rollover';

		var target = typeof e.target != 'undefined' ? e.target : window.event.srcElement;
		
		/*
			A priori, le noeud est un lien. On remonte jusqu"à trouver un élément "li"
		*/
		while (target.nodeName.toUpperCase() != 'LI') {
			target = target.parentNode;
		}
		
		/* Boucle importante (sinon les sous sous menu ne s'ouvrent pas) */
		if (target != li) { 
			/* Lorsqu'il s'agit d'éléments "li" pas de premier niveau, on rentre dans cette boucle */
			return;
		}
		/*if(index==0){alert("coucou")}*/
		/* Lorsqu'il s'agit d'éléments "li"  de premier niveau, on ne rentre pas dans la boucle et on continue */
		
		/* Lorsqu'on est sur un élément "li" et qu'il y a un sous menu */
		if (menu) {
			/* Utilisation d'une minuterie pour retarder l'ouverture: la fonction ne s'éxécutera que lorsque la minuterie sera terminée */
			opentime = window.setTimeout(function() {
				if (branch) {
					/* fonction définie plus bas */
					clearMenus(branch);
					branch = null;
				}
				/* Fonction définie plus bas */
				resetSiblingBranches(li);
				
				/* Fonction servant à afficher le sous menu */
				showMenu(menu, horiz, issub, li, a, isie);
			}, 250);
			/*  */
		}index=1;
	}, false);
	
	/* De la même manière, une méthode est définie quand la souris quitte l'élément */
	attachEventListener(li, 'mouseout', function(e) {
		if (unwantedTextEvent()) {
			return;
		}
		
		var related = typeof e.relatedTarget != 'undefined' ? e.relatedTarget : window.event.toElement;

		if (!li.contains(related)) {
			clearTimeout(opentime);
			
			/* Redéfinition de la variable "branch" */
			branch = li;
			
			/* Suppression de la classe "rollover" des liens */
			a.className = a.className.replace(/ ?rollover/g, '');
			if (menu) {
				/* On ne fermera le menu qu'à la fin de la minuterie */
				closetime = window.setTimeout(function() {
					/* Permet de cacher le menu */
					menu.style.left = '-100em';

					if (toggleSelects('visible') && tree.contains(related)) {
						/* Méthode définie plus bas */
						toggleSelects('hidden');
					}
					else {
						removeIframeLayer(menu);
					}
				}, 600);
			}
		}
	}, false);

	if (!isie) {
		li.contains = function(node) {
			if (node == null) {
				return false;
			}
			if (node == this) {
				return true; 
			}
			else {
				return this.contains(node.parentNode); 
			}
		};
	}
}

/* Fonction servant à afficher le menu */
function showMenu(menu, horiz, issub, li, a, isie)	{
	/*
		menu = menu à afficher (null s'il n'y a pas de menu à afficher (pas de balise "ul" fille de l'élément "li")
		horiz = booléen valant true si l'index auquel "horizontal" apparaît dans le nom de la classe de l'élément racine
		issub = booléen indiquant si l'élément "li" est un fils de l'élément racine
		isie = booléen valant true si Jscript marche, false sinon
	*/
	
	var parent = menu.parentNode;
	var parent_name = parent.nodeName;
	
	while (parent_name.toUpperCase() != 'UL') {
		parent = parent.parentNode;
		parent_name = parent.nodeName;
	}
	
	/* Calcul de la largeur de la liste */	
	var items = menu.getElementsByTagName('li');
	var longueur = 0;
	var longueur2 = 0;
	var li_long = 0;
	var li_long2 = 0;
	for (var i = 0 ; i < items.length ; i++) {
		var parent = items[i].parentNode;
		if (parent == menu) {
			li_long = items[i].clientWidth;
			if (li_long > longueur) {
				longueur = li_long;
			}
		}
		else {
			li_long2 = items[i].clientWidth;
			if (li_long2 > longueur2) {
				longueur2 = li_long2;
			}
		}
	}
	
	menu.style.width = longueur +'px';
	var difference = longueur2 - longueur;
	menu.style.margin = '0 ' + difference + 'px 0 0';
	
	for (var i = 0; i < items.length; i++) {
		var parent = items[i].parentNode;
		if (parent == menu) {
			items[i].style.width = longueur + 'px';
		}
	}

	
	var parent2 = menu.parentNode;
	var parent_name2 = parent2.nodeName;
	
	
	while (parent_name2.toUpperCase() != 'UL') {
		parent2 = parent2.parentNode;
		parent_name2 = parent2.nodeName;
	}
	var racine2 = parent2.className.indexOf('horizontal') == -1;
	if (racine2) {
		/* Récupération d'un fils 'li' de la liste parente */
		var fils = parent2.getElementsByTagName('li');
		var largeur = fils[0].clientWidth;
	
		var marge = largeur - 10;marge = marge + 'px';
		menu.style.margin = '10px 0px 0px ' + marge;
	}	
	
	/* Modification du style pour faire apparaître le sous menu alert(li.offsetLeft);*/
	menu.style.left = horiz
		? 'auto' : '0';
	
	menu.style.top = horiz && issub
		? (isie ? '197px' : 'auto')
		: (isie ? li.offsetTop + 'px' : '0');

	
	/* Fonction définie plus bas */
	/*repositionMenu(menu);*/

	if (typeof document.uniqueID != 'undefined') {
		createIframeLayer(menu);
	}
}

/* Fonction permettant d'afficher les ancêtres quand on a cliqué sur un lien (même si on n'est plus sur le lien) */
function showAncestors(tree, menu, horiz, issub, isie) {
	/*
		tree = élément racine
		menu = menu à afficher (null s'il n'y a pas de menu à afficher (pas de balise "ul" fille de l'élément "li")
		horiz = booléen valant true si l'index auquel "horizontal" apparaît dans le nom de la classe de l'élément racine
		issub = booléen indiquant si l'élément "li" est un fils de l'élément racine
		isie = booléen valant true si Jscript marche, false sinon
	*/
	clearMenus(tree);
	
	/* Tant qu'on n'est pas arrivé à la racine, on remonte d'un élément */
	while (menu.id != tree.id) {
		var li = menu.parentNode;
		var a = li.getElementsByTagName('a')[0];
		
		/* Affichage du sous-menu de chaque parent */
		showMenu(menu, horiz, issub, li, a, isie);
		
		/* On remonte d'un cran */
		menu = li.parentNode;
	}

}

/* Fonction servant à supprimer les classes des liens */
function resetSiblingBranches(trigger) {
	/* trigger = un élément "li" */
	
	clearMenus(trigger.parentNode);

	var links = trigger.parentNode.getElementsByTagName('a');
	for (var i = 0; i < links.length; i++) {
		links[i].className = links[i].className.replace(/ ?rollover/g, '');
	}
}

function cleanUselessWhitespace(node)
{
  for (var x = 0; x < node.childNodes.length; x++)
  {
    var child = node.childNodes[x];
    if (child.nodeType == 3 && !/\S/.test(child.nodeValue))
    {
      node.removeChild(node.childNodes[x]);
      x--;
    }
    if (child.nodeType == 1)
    {
      cleanUselessWhitespace(child);
    }
  }
}

function mapKeyCode(keycode, type)
{
  switch (type)
  {
    case 0:
      if (keycode == 37) keycode = 39;
      else if (keycode == 39) keycode = 37;
      break;

    case 1:
      if (keycode % 2) keycode++;
      else keycode--;
      break;

    case 2:
      if (keycode == 38) { keycode = 37; }
      break;
  }

  return keycode;
}

function arrowKeyNavigation(tree, link, keycode, horiz)
{
  var li = link.parentNode;
  var menu = li.getElementsByTagName('ul').length > 0
      ? li.getElementsByTagName('ul')[0] : null;
  var parent = li.parentNode;

  if (menu)
  {
    if (getRoughPosition(menu, 'x')
        < getRoughPosition(li.parentNode, 'x'))
    {
      keycode = mapKeyCode(keycode, 0);
    }
  }
  else if (parent != tree)
  {
    if (getRoughPosition(parent.parentNode.parentNode, 'x')
        > getRoughPosition(parent, 'x'))
    {
      keycode = mapKeyCode(keycode, 0);
    }
  }

  if (horiz)
  {
    if (parent == tree)
    {
      keycode = mapKeyCode(keycode, 1);
    }
    else if (parent.parentNode.parentNode == tree
        && li == li.parentNode.firstChild)
    {
      keycode = mapKeyCode(keycode, 2);
    }
  }

  switch (keycode)
  {
    case 37:
      parent = parent.parentNode;
      if (tree.parentNode == parent) { parent = null; }
      if (parent)
      {
        parent.firstChild.focus();
      }
      break;

    case 38:
      var previous = li.previousSibling;
      if (!previous)
      {
        previous = li.parentNode.childNodes
            [li.parentNode.childNodes.length - 1];
      }
      previous.firstChild.focus();
      break;

    case 39:
      if (menu)
      {
        menu.firstChild.firstChild.focus();
      }
      break;

    case 40:
      var next = li.nextSibling;
      if (!next)
      {
        next = li.parentNode.childNodes[0];
      }
      next.firstChild.focus();
      break;
  }
}

function clearMenus(root)
{
  var menus = root.getElementsByTagName('ul');
  for (var i = 0; i < menus.length; i++)
  {
    menus[i].style.left = '-100em';
    removeIframeLayer(menus[i]);
  }
}

function unwantedTextEvent()
{
  return (navigator.vendor == 'Apple Computer, Inc.'
      && (event.target == event.relatedTarget.parentNode
      || (event.eventPhase == 3
      && event.target.parentNode == event.relatedTarget)));
}

function getRoughPosition(ele, dir)
{
  var pos = dir == 'x' ? ele.offsetLeft : ele.offsetTop;
  var tmp = ele.offsetParent;
  while (tmp != null)
  {
    pos += dir == 'x' ? tmp.offsetLeft : tmp.offsetTop;
    tmp = tmp.offsetParent;
  }
  return pos;
}

function getViewportSize()
{
  var size = [0,0];

  if (typeof window.innerWidth != 'undefined')
  {
    size = [
        window.innerWidth,
        window.innerHeight
    ];
  }
  else if (typeof document.documentElement != 'undefined'
      && typeof document.documentElement.clientWidth != 'undefined'
      && document.documentElement.clientWidth != 0)
  {
    size = [
        document.documentElement.clientWidth,
        document.documentElement.clientHeight
    ];
  }
  else
  {
    size = [
        document.getElementsByTagName('body')[0].clientWidth,
        document.getElementsByTagName('body')[0].clientHeight
    ];
  }

  return size;
}

function repositionMenu(menu)
{
  var extent = [
      getRoughPosition(menu, 'x') + menu.offsetWidth + 25,
      getRoughPosition(menu, 'y') + menu.offsetHeight + 25
  ];
  var viewsize = getViewportSize();

  if (extent[0] > viewsize[0])
  {
    var offset = menu.offsetWidth
        + menu.parentNode.parentNode.offsetWidth;
    var inset = menu.parentNode.offsetWidth
        - menu.offsetLeft;

    menu.style.left = (0 - offset + (inset * 2)) + 'px';
  }

  if (extent[1] > viewsize[1])
  {
    var current = parseInt(menu.style.top, 10);
    var difference = extent[1] - viewsize[1];

    menu.style.top = (current - difference) + 'px';
  }
}

function createIframeLayer(menu)
{
  if (!toggleSelects('hidden'))
  {
    var layer = document.createElement('iframe');
    layer.tabIndex = '-1';
    layer.src = 'javascript:false;';
    menu.parentNode.appendChild(layer);

    layer.style.left = menu.offsetLeft + 'px';
    layer.style.top = menu.offsetTop + 'px';
    layer.style.width = menu.offsetWidth + 'px';
    layer.style.height = menu.offsetHeight + 'px';
  }
}

function removeIframeLayer(menu)
{
  if (!toggleSelects('visible'))
  {
    var layers = menu.parentNode.getElementsByTagName('iframe');
    while (layers.length > 0)
    {
      layers[0].parentNode.removeChild(layers[0]);
    }
  }
}

function toggleSelects(vis)
{
  if (typeof document.uniqueID != 'undefined'
      && typeof document.body.style.scrollbarTrackColor == 'undefined')
  {
    var selects = document.getElementsByTagName('select');
	
    for (var i = 0; i < selects.length; i++)
    {
      selects[i].style.visibility = vis;
    }

    return true;
  }

  return false;
}

function attachEventListener(target, eventType, functionRef, capture)
{
  if (typeof target.addEventListener != 'undefined')
  {
    target.addEventListener(eventType, functionRef, capture);
  }
  else if (typeof target.attachEvent != 'undefined')
  {
    target.attachEvent('on' + eventType, functionRef);
  }
  else
  {
    eventType = 'on' + eventType;

    if (typeof target[eventType] == 'function')
    {
      var oldListener = target[eventType];

      target[eventType] = function()
      {
        oldListener();

        return functionRef();
      }
    }
    else
    {
      target[eventType] = functionRef;
    }
  }

  return true;
}

function addLoadListener(fn)
{
  if (typeof window.addEventListener != 'undefined')
  {
    window.addEventListener('load', fn, false);
  }
  else if (typeof document.addEventListener != 'undefined')
  {
    document.addEventListener('load', fn, false);
  }
  else if (typeof window.attachEvent != 'undefined')
  {
    window.attachEvent('onload', fn);
  }
  else
  {
    var oldfn = window.onload;
    if (typeof window.onload != 'function')
    {
      window.onload = fn;
    }
    else
    {
      window.onload = function()
      {
        oldfn();
        fn();
      };
    }
  }
}
/*
	On attache un "menu déroulant" au document lorsqu'il est chargé.
	On passe en paramètre l'élément "racine" du menu.
*/
addLoadListener(function() { dropdownMenu('navigation'); });
