
/* ========================================================================================================
	introslider.js
	Bilder-Schiebeeffekt
	Copyright (c) Wolfram Biedermann, Regen - Jede unerlaubte Verwendung untersagt
   ========================================================================================================
*/

function introslider (
			viewport_id,
			elem_id_basisname,
			anz_elem,
			senkrecht,
			von_links,
			minimum_vorgabe,
			lfz,
			id_erg_cont, 
			id_erg_schat,					// elem_id_basisname + i +  dieser Wert
			id_erg_html_dyn_kurz,			// elem_id_basisname + i +  dieser Wert
			id_erg_html_dyn_lang			// elem_id_basisname + i +  dieser Wert
		 		)
{
	thisObject = this;

	var viewport;
	var breite_viewport = 0;
	var breite_viewport_alt = 0;
	var breite_elem = 0;
	var anzeigebreite_elem = 0;
	var anzeigebreite_elem_neutral = 0;
	var minimum = 0;

// in_move ist hier nicht als flag, sondern als Zaehler ausgebildet, weil mit der Verknuepfung mehrerer moves nacheinander
// (beim Ein- und Ausgehen in die / aus der Neutralstellung) eine uebergeordnete Ebene existiert,die die in_move-Sperre durchgehend
// braucht
	var in_move = 0;
	var mover;
	var move_elements = [];
	var x_mover;
	var move_takt = true;
	var move_rest = 0;
	var schrittweite = 30;
	var delay = 30;

// lfz_grundstellung: Voreinstellung der lfz
// 		-2: ungueltig, 
//		-1: neutral (gleichmaessig verteilen)
//		0-x: bestimmte lfz
// Die lfz der Parameterliste bewirkt nur die anfaengliche Darstellung mit einer best. lfz, sofern die Grundstellung nicht dagegenspricht.
	var lfz_grundstellung = -2;		
	var verlassen_nach_aussen = false;
	var glo_mouseout_event = null;

	var folge_lfz = -99;		// weiter Event, wenn noch in_move

	var is_init = false;
	var preOnloadInit = false;

//========================================================================================================
//	Parameter setzen (durch Anwendung)
//========================================================================================================

	///////////////////////////////////////////////////////
	// schon beim Registrieren anfangen
	//
	this.activatePreOnloadInit = function activatePreOnloadInit () {
		preOnloadInit = true;
	}

	///////////////////////////////////////////////////////
	// Verschiebe-Parameter setzen
	// delay_mouseout hat nur eine Bedeutuhg, wenn auch eine Grundstellung gesetzt ist
	//
	this.setTechParam = function setTechParam ( sw, del, del_mo ) {
		schrittweite = sw;
		delay = del;
		delay_mouseout = del_mo;
	}

	///////////////////////////////////////////////////////
	// lfz-Grundstellung registrieren
	//
	this.setLfzGrundstellung = function setLfzGrundstellung ( glfz )
	{
		if( glfz < -2 )	
			lfz_grundstellung = -2;		// ungueltig, keine bestimmte Grundst.
		else if( glfz == -1 ) {
			lfz_grundstellung = -1;
			lfz = -1;
		}
		else {
			lfz_grundstellung = glfz;
			lfz = glfz;
		}
	}

//========================================================================================================
//	Initialisieren 
//========================================================================================================

	///////////////////////////////////////////////////////
	//	initialisieren
	//	Ermittelt verschiedene Werte (einmalig zu Beginn).
	//
	this.initialisieren = function initialisieren()
	{
		var erstesElemId = elem_id_basisname + '0';
		var element;
		var i;

		if( is_init )
	return;
		if( lfz >= anz_elem )
			lfz = anz_elem -1;

		if( viewport = document.getElementById( viewport_id ) ) {
			if( document.getElementById( erstesElemId ) ) 
			{
// Fallweise Eventhandler beim Verlassen
// Problematik: "onmouseout" wird auch gerufen, wenn der viewport nach innen (in die elemente hinein) "verlassen" wird
// Auch ist es schoener, wenn beim Verlassen nicht sofort reagiert wird. Beim schnellen Wiederbetreten der Funktion entsteht dann ein
// haesslicher Flackereffekt.
// Konstruiere also einen Mechanismus, der nur mit Verzoegerung und nur beim Verlassen nach aussen aktiv wird.
// (und verzichte gleichzeitig auf browserabhaengige Mauskoo-abfrage)
// Ein Verlassen nach aussen liegt dann vor, wenn bei onmouseout nicht in zuegiger Folge ein normaler Verschiebe-event ausgeloest wird.
// Auch muss sichergestellt sein, dass der Event, fuer den der Reset-Befehl gesetzt wurde, auch nach der Verzoegerung noch derselbe ist.
// Ein neuer Event soll eine neue Verzoegerung ausloesen, der alte soll vergessen werden.
// Merke also hier den ausloesenden Event und setze ihn gleichzeitig global. Rufe dann mit Verzoegerung den Reset-Eventhandler.
// Der globale Event-Wert wird von zwischenzeitlich eintretenden normalen Verschiebe-Events zurueckgesetzt. 
// Daran erkennt der Eventhandler, wenn er endlich ausgefuhert wird, dass er nichts mehr tun soll und der Befehl
// "verpufft" wirkungslos.
// Sonderfall IE (auch 8): das Event-Objekt kann nicht direkt in einen globalen event gespeichert werden, da werden Eigenschaften vergessen (?!)
// Daher bei IE Teile des Events (Mauskoo, die aendern sich am ehesten) in ein neues Objekt kopieren und dieses hernehmen.
				if( lfz_grundstellung > -2 )
				{
					viewport.onmouseout = function( event ){ 
							if( !event )		// == bei IE
								event = { clientX: window.event.clientX, clientY: window.event.clientY };
// Wenn wirklich von innen-event zurueckgesetzt wurde, merke den neuen Event
							if( ! glo_mouseout_event ) {
							 	glo_mouseout_event = event;
								window.setTimeout( function () { thisObject.grundstellung_event( event );	}, delay_mouseout );
							}
					};
				}
				if( senkrecht )
					breite_elem = document.getElementById( erstesElemId ).offsetHeight;
				else
					breite_elem = document.getElementById( erstesElemId ).offsetWidth;

// Jetzt die Eventhandler eintragen. Content von 0 bis anz-1, schatten von 1 bis anz
// Verlassen-Event "ausschalten" (zuruecksetzen), wir bleiben drin
				for( i = 0; i < anz_elem; i++ ) {
					element = document.getElementById( elem_id_basisname + i + id_erg_cont );
					element.ilfz = i;
					element.onmouseover = function() { 
							 	glo_mouseout_event = null;
								thisObject.move_event( this.ilfz ); 
													};
				}
				for( i = 1; i <= anz_elem; i++ ) {
// Wenn Schatten existiert, diesen den Wert des darutnterliegenden divs geben
// Verlassen-Event "ausschalten" (zuruecksetzen), wir bleiben drin
					if( element = document.getElementById( elem_id_basisname + i + id_erg_schat ) ) {
						element.ilfz = i-1;	
						element.onmouseover = function() { 
								 	glo_mouseout_event = null;
									thisObject.move_event( this.ilfz ); 
														};
					}
				}
				is_init = true;
			}
		}
	}

	///////////////////////////////////////////////////////
	// setzt die Position top/left/bottom/right abhaengig von der Ausrichtung
	//
	this.setPosition = function setPosition ( elem, pos )
	{
		if( senkrecht ) {
			if( von_links )		// heisst von oben
				elem.style.top = pos + "px";
			else
				elem.style.bottom = pos + "px";
		}
		else {
			if( von_links )
				elem.style.left = pos + "px";
			else
				elem.style.right = pos + "px";
		}
// Speichere die Position in einer eigenen Eigenschaft
		elem.glccpos = pos;
	}

	///////////////////////////////////////////////////////
	// setzt dyn-html-Text abhaengig von lfz
	//
	this.setDynHTML = function setDynHTML ( i )
	{
		var elem;
		var id_kurz, id_lang;

		if( i < 0 )
	return;
		id_kurz = elem_id_basisname + i + id_erg_html_dyn_kurz;
		id_lang = elem_id_basisname + i + id_erg_html_dyn_lang;

		if( i == lfz ) {
			if( elem = document.getElementById( id_kurz ))
				elem.style.display = "none";
			if( elem = document.getElementById( id_lang ))
				elem.style.display = "block";
		}
		else {
			if( elem = document.getElementById( id_kurz ) ) 
				elem.style.display = "block";
			if( elem = document.getElementById( id_lang ) )
				elem.style.display = "none";
		}
	}

//========================================================================================================
//	Ausgangsstellung setzen
//========================================================================================================

	///////////////////////////////////////////////////////
	// Zielposition ermitteln
	// Wird von setzeAusgangsstellung gerufen und von Wechsel von/zu Neutralstellung
	// Gibt einen Array 0 bis anz_elem-1 zurueck mit den Sollpositionen
	//
	this.ermittleZielposition = function ermittleZielposition ( kuenftige_lfz )
	{
		var positionen = [];
		var pos = 0, i;

		for( i = 0; i < anz_elem; i++ ) 
		{
			positionen[positionen.length] = pos;
			if( kuenftige_lfz == -1 )
				pos += anzeigebreite_elem_neutral;
			else if( i == kuenftige_lfz )
				pos += anzeigebreite_elem;
			else
				pos += minimum;
		}
	return positionen;
	}

	///////////////////////////////////////////////////////
	// setzt die Bilder auf eine Ausgangsstellung (ueber lfz festgelegt) 
	// und ermittelt gleichzeitig de noetigen Parameter (Anzeigebreite, Minimum):
	// Wenn lfz >= 0, mit offenem aktivem Bild
	// Wenn lfz < 0, gleichmaessig verteilen
	// Wird bei resize gerufen und auch bei Rueckkehr in die Grundstellung, wenn gleichmaessig verteilt werden soll
	// breite_viewport und breite_elen muessen bekannt sein
	//
	this.setzeAusgangsstellung = function setzeAusgangsstellung ()
	{
		var zu_verteilen;
		var elem_id, i;
		var zielpos = [];

// Setze in_move auch hier auf true, waehrend die Funktion laeuft
		if( in_move > 0 )
	return;
		in_move++;

// ermittle das tatsaechliche Minimum ( Wenn elem + alle Minima den freien Raum nicht ueberdecken, wird das minimum so vergroessert, dass es passt)
// Fuer den Extremfall, dass Summe der Elemente < Viewport-Breite, gibt es keine befriedigende Loesung.
// In diesem Fall entstehen eben Luecken.

		zu_verteilen = breite_viewport - breite_elem;
		if( anz_elem > 1 )
			minimum = Math.ceil( zu_verteilen / ( anz_elem -1 ) );
		if( minimum < minimum_vorgabe )
			minimum = minimum_vorgabe;

		anzeigebreite_elem_neutral = Math.round( breite_viewport / anz_elem );

// Wie gross kann das aktive Element angezeigt werden? 
// Es kann nie kleiner werden als das minimum. Kosequenz, wenn Vieport zu schmal: Elemente werden ins unsichtbare geschrieben
// Die Anwendung muss ihre Parameter so einstellen, dass der Introslider gut ausschaut
		anzeigebreite_elem = breite_viewport - minimum * ( anz_elem -1 );
		if( anzeigebreite_elem < minimum )
			anzeigebreite_elem = minimum;

		zielpos = thisObject.ermittleZielposition( lfz );

		for( i = 0; i < anz_elem; i++ ) 
		{
			elemId = elem_id_basisname + i;
			thisObject.setPosition( document.getElementById( elemId ), zielpos[i] );
			thisObject.setDynHTML( i );
		}
		in_move--;
	}

//========================================================================================================
//	Verschiebe-Events
//========================================================================================================

	///////////////////////////////////////////////////////
	// reset-Event
	// Wird beim Verlassen des Viewports gerufen, wenn eine Grundstellung eingetragen ist
	// Hantiert mit 2 Werten: Parameter event und glo_mouseout_event
	// Dient dazu, festzustellen, ob der Event, auf den nach der verzoegerung delay_mouseout reagiert wird, wirklich derselbe ist, fuer den
	// die Funktion gerufen wurde. glo_mouseout_event kann von "inneren" Events (normales Verschieben) geaendert werden, dann gilt der
	// Reset-Befehl nicht mehr. Also nur ausfuehren, wenn sich am urspruenglichen Reset-Befehl nichts geaendert hat.
	//
	this.grundstellung_event = function grundstellung_event( event )
	{
		var lfz_alt = lfz;
		if( glo_mouseout_event != event )
	return;
		if( lfz == -1 )		// ist das moeglich ?? - nur Sicherheit
	return;

		if( in_move == 0 ) {
			if( lfz_grundstellung >= 0 )
				thisObject.move_event( lfz_grundstellung );
			else if( lfz_grundstellung == -1 ){
				lfz = -1;
				thisObject.move_neutralstellung( lfz_alt, lfz );
				lfz = lfz_grundstellung;
			}
		}
		else
			window.setTimeout( function () { grundstellung_event( event );	}, 100 );
	}

	///////////////////////////////////////////////////////
	// verschiebe-Event
	// Wenn neue_lfz -99 ist, heisst das, die globale folge_lfz  nehmen
	// Dies ist der aktuelle, letztgueltige Wert, der waehrend eines Moves angewaehlt wurde
	//
	this.move_event = function move_event( neue_lfz )
	{
		var alte_lfz = lfz;

		if( neue_lfz == -99 ) {
			neue_lfz = folge_lfz;
/*
 			document.getElementById( "testanzeige1").innerHTML = "<p>neueLfz " + neue_lfz + 
																" -- altelfz : " + alte_lfz + 
																"-- folgelfz : " + folge_lfz +"</p>";
*/
		}
		if( neue_lfz == lfz )
	return;
		if( system_floatResize.isInEvent() )	// Resize hat Prioritaet, auf move einfach verzichten
	return;

		if( in_move == 0 ) {
			lfz = neue_lfz;
			if( alte_lfz == -1 ) {
// aus der Grundstellung heraus oder in sie hinein
				thisObject.move_neutralstellung( alte_lfz, lfz );
			}
			else {
				in_move++;
				thisObject.move( alte_lfz, neue_lfz );
			}
//  		document.getElementById( "testanzeige").innerHTML = "<p>EInleiten: neueLfz " + neue_lfz + " -- altelfz : " + alte_lfz + "</p>";
		}
		else {
			if( neue_lfz != -99 )
				folge_lfz = neue_lfz;
			window.setTimeout( function () { thisObject.move_event( -99 );	}, 100 );
		}
	}

	///////////////////////////////////////////////////////
	// Move in/aus Neutralstellung
	// lfz ist bereits auf den neuen Wert gesetzt
	// Quasi die "Meta-Ebene" zum normalen move.
	// Hier werden die divs nacheinander in einer bestimmten Reihenfolge verschoben und ueber die "kleine" Zeitschleife mit in_move == 1
	// eine "grosse" gelegt mit in_move == 2
	//
	this.move_neutralstellung = function move_neutralstellung ( alte_lfz, neue_lfz )
	{
// Reihenfolge der zu verschiebenden divs (enthaelt die Indexwerte der Elemente)
		var move_sequenz = [];
		var zielpos = thisObject.ermittleZielposition( neue_lfz );
		var i;

		function move_einzel() 
		{
			var element;
			var verschiebung;

			if( i == anz_elem -1 ) {
				in_move--;			// 1 -> 0
		return;
			}
			if( in_move == 1 ) {
				in_move++;		// 1 -> 2
				move_elements = new Array();
				element = document.getElementById( elem_id_basisname + move_sequenz[i] );
				move_elements[move_elements.length] = element;
				verschiebung = zielpos[move_sequenz[i]] - element.glccpos;
				thisObject.move_ausfuehren( true, verschiebung );
				i++;
			}
			window.setTimeout( function () { move_einzel();	},	20 );
		}
		in_move++;		// 0 -> 1

		thisObject.setDynHTML( alte_lfz );
		thisObject.setDynHTML( neue_lfz );

// aus der Grundstellung in lfz-Anzeigestellung
		if( lfz >= 0 ) {
			for( i = 1; i <= neue_lfz; i++ )
				move_sequenz[move_sequenz.length] = i;
			for( i = anz_elem - 1; i > neue_lfz; i-- )
				move_sequenz[move_sequenz.length] = i;
			i = 0;
			move_einzel();  // in_move wird 2 und wieder 1
		}
		else {
 			for( i = alte_lfz + 1; i < anz_elem; i++ ) 
				move_sequenz[move_sequenz.length] = i;
 			for( i = alte_lfz; i > 0; i-- ) 
				move_sequenz[move_sequenz.length] = i;
			i = 0;
			move_einzel();  // in_move wird 2 und wieder 1
		}
	}

	///////////////////////////////////////////////////////
	// verschiebe-Event
	//
	this.move = function move ( alte_lfz, neue_lfz )
	{
		var i, verschiebung;

		if( alte_lfz == neue_lfz )
	return;

// Welche Elemente muessen verschoben werden ?
		move_elements = new Array();
		if( neue_lfz > alte_lfz ) {
			for( i = alte_lfz + 1; i <= neue_lfz; i++ ) {
				move_elements[move_elements.length] = document.getElementById( elem_id_basisname + i.toString() );
			}
			verschiebung = -anzeigebreite_elem + minimum;
		} 
		else {
			for( i = neue_lfz + 1; i <= alte_lfz; i++ ) {
				move_elements[move_elements.length] = document.getElementById( elem_id_basisname + i.toString() );
			}
			verschiebung = anzeigebreite_elem - minimum;
		}
// lfz ist hier schon neu gesetzt
		thisObject.setDynHTML( alte_lfz );
		thisObject.setDynHTML( lfz );
		thisObject.move_ausfuehren( true, verschiebung );
// dyn_html in move_ausfuehren einschalten, wenn man es hier macht, wird bisweilen ein "Verschwindeeffekt" beobachtet
	}

	///////////////////////////////////////////////////////
	//	move_ausfuehren
	//  fuehrt die Verschiebung aus
	//
	this.move_ausfuehren = function move_ausfuehren( init, verschiebung )
	{
		var sgn_sw = ( verschiebung > 0 ? 1 : -1 );
		var verwendete_sw = sgn_sw * schrittweite;
		var i, elem_neu, rest;
		var pos = 0, neupos;
//		var anz_bremsschritte;
		
		if( init )
		{
//			thisObject.setDynHTML( lfz );
			mover = document.createElement( "div" );
			mover.id = elem_id_basisname + "_mover";	// ist eindeutig
			mover.style.position = "absolute";

// Kopiere alle zu verschiebenden Elemente nacheinander auf den mover
			for( i = 0; i < move_elements.length; i++ ) 
			{
				elem_neu = document.getElementById( move_elements[i].id ).cloneNode( true );
				system_deleteIdsRecursive( elem_neu );
				thisObject.setPosition( elem_neu, pos );
				pos += minimum;
				mover.appendChild( elem_neu );
			}

// Position des Movers festlegen
			if( senkrecht )
				x_mover = von_links ?
								move_elements[0].offsetTop:
								breite_viewport - ( move_elements[0].offsetTop + breite_elem );
			else 
				x_mover = von_links ?
								move_elements[0].offsetLeft:
								breite_viewport - ( move_elements[0].offsetLeft + breite_elem );
			
			thisObject.setPosition( mover, x_mover );
			move_rest = verschiebung;	
			viewport.insertBefore( mover, move_elements[0] );

// Hinter dem "Vorhang" die alten divs ausblenden und direkt auf die Zielkoordinaten umsetzen.
			for( i = 0; i < move_elements.length; i++ ) 
			{
				if( senkrecht )
					neupos = von_links ? 
								move_elements[i].offsetTop + verschiebung : 
								breite_viewport - ( move_elements[i].offsetTop + breite_elem ) + verschiebung;
				else
					neupos = von_links ? 
								move_elements[i].offsetLeft + verschiebung : 
								breite_viewport - ( move_elements[i].offsetLeft + breite_elem ) + verschiebung;

				move_elements[i].style.display = "none";
				thisObject.setPosition( move_elements[i], neupos );
			}
		}
		if( move_rest == 0 )
		{
// die "echten" divs wieder einblenden und Vorhang zerstoeren
			for( i = 0; i < move_elements.length; i++ ) {
				move_elements[i].style.display = "block";
			}
			viewport.removeChild( mover );
//			bremsstufe = 0;
// in_move kann auch groesser als 1 sein, bei Wechsel von/zu Neutralstellung
			in_move--;
	return;
		}

// Wenn der naechste Takt freigegeben ist oder beim ersten Mal (init)
		if( move_takt || init )
		{	
			move_takt = false;
			window.setTimeout( function() { move_takt = true; }, delay );

			rest = move_rest - verwendete_sw;

			if( ( verschiebung > 0 && rest < 0 ) || ( verschiebung < 0 && rest > 0 ) ) {
				verwendete_sw = move_rest;
				rest = 0;
			}

			move_rest = rest;
			x_mover += verwendete_sw;
			thisObject.setPosition( mover, x_mover );
		}
		window.setTimeout( function () { thisObject.move_ausfuehren( false, verschiebung );	}, 1 );
	}

//========================================================================================================
//	Resize-Funktionen
//========================================================================================================
// Die Methoden resizeInit(), onloadInit(), resize() und isLocallyProtected() werden von system_floatResize benoetigt

	///////////////////////////////////////////////////////
	// onloadInit
	//
	this.onloadInit = function onloadInit () {
		breite_viewport_alt = 0;	// Erzwinge resize zu Sicherheit
		thisObject.resize();
	}

	///////////////////////////////////////////////////////
	//  Systemfunktion resizeInit
	//	Wenn preOnloadInit gesetzt, schon vorab anfangen
	// 
	this.resizeInit = function resizeInit () {
		if( preOnloadInit )
			thisObject.resize();
	}

	///////////////////////////////////////////////////////
	//	isLocallyProtected
	//  anhand dieser Methode erkennt system_floatResize, ob ein lokaler Event einen Schutz gegen gleichzeitiges Aufrufen
	//  von resize() benoetigt. Falls ja, wartet system_floatResize, bis der lokale Schutz nicht mehr existiert, also bis die
	//  Methode isLocallyProtected() false zurueckgibt.
	//  Nehme im konkreten Fall die bereits fuer internen Schutz gebrauchte Variable in_move her.
	//
	this.isLocallyProtected = function isLocallyProtected () {
	return( in_move != 0 );
	}

	///////////////////////////////////////////////////////
	// resize
	// muss folgende Rueckgaben machen: true fuer VERAENDERT, false fuer UNVERAENDERT
	//
	this.resize = function resize ()
	{
		var rueck = false;

		thisObject.initialisieren();
		if( !is_init )
	return rueck;

		if( senkrecht )
			breite_viewport = viewport.offsetHeight;
		else
			breite_viewport = viewport.offsetWidth;

		if( breite_viewport != breite_viewport_alt ) {
			thisObject.setzeAusgangsstellung();
			breite_viewport_alt = breite_viewport;
			rueck = true;
		}
	return rueck;
	}
}
