/*		
 *	SlideMenu
 *	~~~~~~~~~
 *
 *	Version: 1.0.0
 *  Datum: 29.12.2005
 *	Autor: Tobias Adam
 *
 *	Getestet auf: 	Win IE 6.0
 *					Win IE 5.5
 *					Win IE 5.0
 *					Win Firefox 1.07
 *					Win Opera 8.5
 *
 *	WICHTIG !!!
 *	Leerzeichen und Umbrüche im Quelltext können u.U. dazu führen, dass das Script nicht
 *	funktioniert. Deshalb bei Erweiterungen unbedingt an die Vorlage des XHTML-Quelltextes halten.
 *
 */

/*** VARIABLEN-DEKLARATIONEN ***/
 
/***	Parameter zum Feintunen des Auffahreffekts	****/
/**/
/**/	var iterationen= 10;
/**/	var verzoegerung= 5;
/**/	var auffahreffektAn= true;
/**/
/*******************************************************/

/* Globale Variablen zur logischen Steuerung des Menüs*/
var zuletztGeoeffneteMenueNummer= -1;
var ersterProzessGestartet= false;
var prozess2An= false;
var zeitSchritte= 0;
 
/* Bietet Zugriff auf die oberste Ebene der geschachtelten ul-Listen */
var ebene1= document.getElementById("ersteListe");

/* Nach dem  Durchlauf von initEbene2() bietet ebene2 Zugriff auf alle ul-Listen der 2. Ebene
   Dabei enspricht ebene2[0] dem Untermenü der ersten Kategorie, ebene[2] dem der zweiten usw. */
var ebene2= new Array();

/* Nach dem Durchlauf von hoehenErmitteln() hat dieses Array die Höhen aller Unter-Menüs
   gespeichert */
var hoehen= new Array();

/*	Nach dem ersten Aufruf von ersteEbeneFunktionalisieren() enthält diese Variable die Anzahl
	der Menü-Punkte */
var anzahlMenuePunkte= 0;

/*** PROGRAMM ***/

init();

/*** FUNKTIONEN ***/
 
function init() {

	ersteEbeneFunktionalisieren();
	initEbene2();
	hoehenErmitteln();
	zweiteEbeneFunktionalisieren();
	adaptWidths();
	unterMenuesVerstecken();
	
	/*
	 *	Der IE zickt rum: erst beim 2. Aufruf der Funktion menuePunktAktion() funktioniert diese.
	 *	Deshalb werden die Menüs "initialisiert" indem sie zunächst einmal ohne Grund aufgerufen
	 *	werden
	 */
	
	for (i= 0; i < hoehen.length; i++) {
		unterMenueAuffahren(i,0);
	}
	
}

	
/*
 *	Speichert die Höhen aller Untermenüs im Array hoehen.
 *	WICHTIG: Kann erst NACH der Funktion initEbene2() aufgerufen werden !
 *	Durch Zuweisen eines Strings mit Textcharakter an jedes Element des hoehen-Arrays kann man auf
 *	bequeme Weise den Auffahreffekt abschalten. Gesteuert wird der Effekt über den Parameter
 *  "auffahreffektAn"
 */

function hoehenErmitteln() {

	for (i= 0; i < ebene2.length; i++) {
		hoehen[i]= ebene2[i].offsetHeight;
	}
	
	if (!auffahreffektAn) {
		for (j= 0; j < hoehen.length; j++) {
			hoehen[j]= "Tobias Adam";
		}
	}

} // end of hoehenErmitteln()

					 
/*
 *	Diese Funktion trägt in die a-Tags der obersten Ebene zusätzlich folgende Attribute ein:
 *		onMouseOver="menuePunktAktion(menuePunktNummer)"
 *		onMouseOut="unterMenueAktionOut()"
 *	mit der entsprechenden Menüpunkt-Nummer
 *  Dabei hat der erste Eintrag die Menüpunkt-Nummer 0, der zweite die Nummer 1 usw.
 */
 
function ersteEbeneFunktionalisieren() {

	menuePunktZaehler= 0;
	
	for (i= 0; i < ebene1.childNodes.length; i++) {
	 	if (ebene1.childNodes[i].nodeName == "LI") {
		
			for (j= 0; j < ebene1.childNodes[i].childNodes.length; j++) {
				if (ebene1.childNodes[i].childNodes[j].nodeName == "A") {
				
					// a-Node merken
					aNode= ebene1.childNodes[i].childNodes[j];
					// a-Href-Attribut merken
					aNodeHrefAttribute= aNode.getAttribute("href");
					// a-Id-Attribut merken
					aNodeIdAttribute= aNode.getAttribute("id");
					// Text im a-Node merken
					aNodeText= aNode.firstChild.data;

					// ul-Node merken
					var ulNode;					
					for (l= 0; l < ebene1.childNodes[i].childNodes.length; l++) {
						if (ebene1.childNodes[i].childNodes[l].nodeName == "UL") {
							ulNode= ebene1.childNodes[i].childNodes[l];
						}
					}
					
					// class-Attribute des UL-Node merken
					ulNodeClassAttribute= ulNode.getAttribute("class");
					/*
					 *  Der IE kann das Class-Attribut nur mit dem Bezeichner "className" auslesen, deshalb diese Abfrage
					 */
					if (!ulNodeClassAttribute) ulNodeClassAttribute= ulNode.getAttribute("className");
					
					//Daten im UL-Node merken
					ulNodeData= ulNode.innerHTML;
					
					ebene1.childNodes[i].removeChild(aNode);
					ebene1.childNodes[i].innerHTML= "<a href=\"" + aNodeHrefAttribute + "\" id=\"" + aNodeIdAttribute + "\" onMouseover=\"menuePunktAktion(" + menuePunktZaehler + ")\" onMouseout=\"unterMenueAktionOut()\">" +  aNodeText + "</a><ul class=\"" + ulNodeClassAttribute + "\">" + ulNodeData + "</ul>";
			
					menuePunktZaehler++;
				
				}
			}
		
		}
	}
	
	anzahlMenuePunkte= menuePunktZaehler;
	
} // end of ersteEbeneFunktionalisieren()


/*
 *	Diese Funktion liest in das Array ebene2 alle ul-Listen der 2. Ebene ein
 */

function initEbene2() {

	var arrayZaehler= 0;

	for (i= 0; i < ebene1.childNodes.length; i++) {
	 	if (ebene1.childNodes[i].nodeName == "LI") {
		
			for (j= 0; j < ebene1.childNodes[i].childNodes.length; j++) {
				if (ebene1.childNodes[i].childNodes[j].nodeName == "UL") {
				
					ebene2[arrayZaehler]= ebene1.childNodes[i].childNodes[j];
					arrayZaehler++;
				
				}
			}
		
		}
	}

} // end of initEbene2()


/*
 *	Diese Funktion trägt in die a-Tags der zweiten Menü-Ebene zusätzlich folgende Attribute ein:
 *		onMouseOver="unterMenueAktionOver()"
 *		onMouseOut="unterMenueAktionOut()"
 */

function zweiteEbeneFunktionalisieren() {

	for (k= 0; k < ebene2.length; k++) {

		for (i= 0; i < ebene2[k].childNodes.length; i++) {
		 	if (ebene2[k].childNodes[i].nodeName == "LI") {
			
				for (j= 0; j < ebene2[k].childNodes[i].childNodes.length; j++) {
					if (ebene2[k].childNodes[i].childNodes[j].nodeName == "A") {
					
						// a-Node merken
						aNode= ebene2[k].childNodes[i].childNodes[j];
						// a-Href-Attribut merken
						aNodeHrefAttribute= aNode.getAttribute("href");
						// a-Id-Attribut merken
						aNodeIdAttribute= aNode.getAttribute("id");
						// Text im a-Node merken
						aNodeText= aNode.firstChild.data;
						
						ebene2[k].childNodes[i].removeChild(aNode);
						ebene2[k].childNodes[i].innerHTML= "<a href=\"" + aNodeHrefAttribute + "\" id=\"" + aNodeIdAttribute + "\" onMouseover=\"unterMenueAktionOver()\" onMouseout=\"unterMenueAktionOut()\">" +  aNodeText + "</a>";
					
					}
				}
			
			}
		}
	
	}

} // end of zweiteEbeneFunktionalisieren()


function unterMenuesVerstecken() {
	
	for (i= 0; i < ebene2.length; i++) {
		ebene2[i].style.visibility= "hidden";
	}
	
} // end of unterMenuesVerstecken


function unterMenueAufdecken(menueNummer) {

	ebene2[menueNummer].style.visibility= "visible";
	
} // end of unterMenueAufdecken


function menuePunktAktion(menueNummer) {


   if (ersterProzessGestartet) {
      clearTimeout(prozess);
   }

   // if-Abfrage notwendig um mehrfaches Öffnen beim Überfahren des gleichen Menüpunkts zu vermeiden
   if (menueNummer != zuletztGeoeffneteMenueNummer) {

      zuletztGeoeffneteMenueNummer= menueNummer;
	  unterMenuesVerstecken();
	  
	  startPosition= - hoehen[menueNummer];
	  hoehe= hoehen[menueNummer];
	  
      unterMenueAufdecken(menueNummer);
	  zeitSchritte= 1; //reset der Zeitschritte
      unterMenueAuffahren(menueNummer,startPosition);
   
   }
	  
} // end of function menuePunktAktion()


function unterMenueAuffahren(menueNummer,anfangsPosition) {

   if (anfangsPosition <= 0) {
   
      if (prozess2An) clearTimeout(prozess2);
   
      /* Original: unterMenuePositionieren(menueNummer,anfangsPosition); */
	  /* angepasst */
	  unterMenuePositionieren(menueNummer,anfangsPosition + 3);
	  /* angepasst */
	  
      neuePosition= Math.round(- hoehen[menueNummer]*Math.exp(-(zeitSchritte/iterationen)));
	  zeitSchritte++;
      prozess2= setTimeout("unterMenueAuffahren(" + menueNummer + "," + neuePosition + ")",verzoegerung);
	  prozess2An= true;
	  
   }

} // end of function unterMenueAuffahren


/*
 *	Die Position wird relativ zur "normalen" Position angegeben (die Position, die per CSS angegeben
 *	wurde)
 */

function unterMenuePositionieren(menueNummer,position) {

	stil= ebene2[menueNummer].style;
	stil.position= "relative";
	stil.top= position + "px";

} // end of unterMenuePositionieren


function unterMenueAktionOver() {
   if (ersterProzessGestartet) {
      clearTimeout(prozess);
   }
}


function unterMenueAktionOut() {
   prozess= setTimeout("tatsaechlichSchliessen()",500);
   ersterProzessGestartet= true;
}


function tatsaechlichSchliessen() {
   unterMenuesVerstecken();
   zuletztGeoeffneteMenueNummer= -1;
}

function getChildsNamed(node,tagName) {
	var childs= new Array();
	var arrayCount= 0;
	for (i= 0; i < node.childNodes.length; i++) {
		//alert(node.childNodes[i].nodeName);
		if (node.childNodes[i].nodeName == tagName) {
			childs[arrayCount]= node.childNodes[i];
			//alert(arrayCount);
			arrayCount++;
		}
	}
	return childs;
}

function getFirstChildNamed(node,tagName) {
	for (i= 0; i < node.childNodes.length; i++) {
		if (node.childNodes[i].nodeName == tagName) {
			return node.childNodes[i];
		}
	}
	return false;
}

/*
 *  Diese Funktion passt die Breite der einzelnen Untermenüs an die Breite des jeweils größten Eintrags an.
 *  Um eine Browser-übergreifende Kompatibilität zu erreichen werden nicht direkt die offsetWidths ausgelesen, da diese vom
 *  FF nicht richtig verstanden werden, wenn Textelemente das sie umgebende Element verlassen; der IE streckt dagegegen das
 *  ihn umgebende Element
 *  Zur Lösunmg des Problems wird die Anzahl der Buchstaben der einzelnen Einträge ausgelesen und diese Anzahl dann mit einer
 *  mittleren Buchstabenbreite multipliziert, um eine annähernd angepasste Breite zu bekommen.
 */

function adaptWidths() {

	var ulTag1= document.getElementById("ersteListe");
	liTags1= getChildsNamed(ulTag1,"LI");

	// jedes liChild hat genau ein ul-Child, deshalb wird ein gleichgroßes Array ulTags2 erstellt
	var ulTags2= new Array();
	for (j= 0; j < liTags1.length; j++) {
		ulTags2[j]= getFirstChildNamed(liTags1[j],"UL");
	}

	// jedes ulTag hat mehrere liTags, deshalb gibt es jeweils ein Array aus liTags
	var liTags2= new Array();
	for (j= 0; j < ulTags2.length; j++) {
		liTags2[j]= getChildsNamed(ulTags2[j],"LI");
	}

	// jedes dieser liTags hat ein aTag
	// der IE kann daraus bereits die richtige Offset-Width berechnen
	var aTags= new Array(liTags2.length);
	for (i= 0; i < liTags2.length; i++) {
		aTags[i]= new Array(liTags2[i].length);
	}
	for (j= 0; j < liTags2.length; j++) {
		for (k= 0; k < liTags2[j].length; k++) {
			aTags[j][k]= getFirstChildNamed(liTags2[j][k],"A");
		}
	}

	// die entsprechenden OffsetWidths abspeichern im Array offsetWidths
	var offsetWidths= new Array(aTags.length);
	for (i= 0; i < aTags.length; i++) {
		offsetWidths[i]= new Array(aTags[i].length);
	}
	for (j= 0; j < aTags.length; j++) {
		for (k= 0; k < aTags[j].length; k++) {
			offsetWidths[j][k]= parseInt(aTags[j][k].offsetWidth);
		}
	}
	

	/*  Diese hier ausgeklammerte Lösung funktioniert ausschließlich für den IE und auch nur dann, wenn umgebenden ul-Tags eine
	 *  sehr kleine width bekommen, so dass der IE das umgebende ul auf die richtige Größe streckt
	 */
	
/*
	
	var biggestWidths= new Array(offsetWidths.length);
	for (i= 0; i < biggestWidths.length; i++) {
		biggestWidths[i]= -1;
	}
	
	for (i= 0; i < offsetWidths.length; i++) {
		for (j= 0; j < offsetWidths[i].length; j++) {
			if (offsetWidths[i][j] > biggestWidths[i]) {
				biggestWidths[i]= offsetWidths[i][j];
			}
		}
	}
	
	for (i= 0; i < aTags.length; i++) {
		for (j= 0; j < aTags[i].length; j++) {
			aTags[i][j].style.width= biggestWidths[i];
		}
	}
	
*/

	/*  Dies ist die oben angesprochene weniger exakte, dafür aber allgemeingültige Lösung, die mit dem FF und dem IE
	 *  funktioniert
	 */

	// hier werden die textNodes referenziert und im 2-dim. Array textNodes gespeichert
	
	var textNodes= new Array(aTags.length);
	for (i= 0; i < aTags.length; i++) {
		textNodes[i]= new Array(aTags[i].length);
	}
	for (j= 0; j < aTags.length; j++) {
		for (k= 0; k < aTags[j].length; k++) {
			textNodes[j][k]= aTags[j][k].firstChild;
		}
	}
	
	// die entsprechenden Buchstabenanzehlen der textNodes werden im 2-dim. Array textLengths gespeichert
	
	var textLengths= new Array(textNodes.length);
	for (i= 0; i < textNodes.length; i++) {
		textLengths[i]= new Array(textNodes[i].length);
	}
	for (i= 0; i < textLengths.length; i++) {
		for (j= 0; j < textLengths[i].length; j++) {
			textLengths[i][j]= textNodes[i][j].nodeValue.length;
		}
	}
	
	// die jeweils größte Buchstabenanzahl einer Kategorie wird im Array biggestTLength gespeichert
	
	var biggestTLength= new Array(textLengths.length);
	for (i= 0; i < biggestTLength.length; i++) {
		biggestTLength[i]= 0;
	}
	
	for (i= 0; i < textLengths.length; i++) {
		for (j= 0; j < textLengths[i].length; j++) {
			if (textLengths[i][j] > biggestTLength[i]) {
				biggestTLength[i]= textLengths[i][j];
			}
		}
	}
	
	// es wird eine durchschnittliche Buchstabenbreite von 8 Pixeln angenommen
	var averageLetterWidth= 8;
	
	/*  den ulTags der Unterkategorien und den in Ihnen beinhalteten a-Tags werden die maximalen Breiten ihrer jeweiligen
	 *  Kategorie zugewiesen
	 */
	
	
	for (i= 0; i < ulTags2.length; i++) {
		ulTags2[i].style.width= ((biggestTLength[i] * averageLetterWidth) + 6) + "px";
	}
	
	for (i= 0; i < aTags.length; i++) {
		for (j= 0; j < aTags[i].length; j++) {
			aTags[i][j].style.width= biggestTLength[i] * averageLetterWidth + "px";
		}
	}
	
	// hier wird noch die Position des letzten Menüpunktes so korrigiert, dass er nicht nach rechts über den Rand hinausgeht
	
	// Breite des letzten Kategoriepunkts ermitteln
	var letzterMenuePunkt= getFirstChildNamed(liTags1[liTags1.length - 1],"A");
	var letzterMenuePunktWidth= letzterMenuePunkt.offsetWidth;

	var diff= letzterMenuePunktWidth - (biggestTLength[biggestTLength.length - 1] * 8);
	
	ulTags2[ulTags2.length - 1].style.left= (diff - 20) + "px";
	
} // end of adaptWidths()