/* sidebar.js

Enthaelt die Klasse Sidebar

*/

var Sidebar = new Class({
	options: {
		kleineBilder: '',
		grosseBilder: null,
		bilder: new Array(),
		kriterien: new Array(),
		richtung: 'unten',
		tempo: 50,
		klick: Class.empty()
	},

	initialize: function(slider, box, tooltipClass, options) {
		this.slider = $(slider);
		this.box = $(box);
		if (tooltipClass != null) {
			this.tooltipClass = '.' + tooltipClass;
		} else {
			this.tooltipClass = null;
		}
		this.setOptions(options);
		
		// Nach den Kriterien gefilterterte Bilder
		this.gefilterteBilder = new Array();

		// Zeigt auf das naechste einzufuegende Bild
		this.bilder_ptr = 0;

		// läuft die Animation?
		this.status = 'stopped';

		if (this.tooltipClass != null) {
			// eine neue Instanz der Mootool-Klasse "Tooltip"
			// diese zeigt die Tooltips an
			this.tooltip = new myTips($$(this.tooltipClass), {
				// der Tooltip wird langsam ein- und ausgeblendet
				initialize:function(){
					this.fx = new Fx.Style(this.toolTip, 'opacity', {duration: 250, wait: false}).set(0);
				},
				onShow: function(toolTip) {
					this.fx.start(1);
				},
				onHide: function(toolTip) {
					this.fx.start(0);
				},
				// der Tooltip wird 375px links und 0px unter dem Cursor angezeigt
				offsets: new Object({x: -375, y: 0}),
				// maximal angezeigt Anzahl von Zeichen im Titel
				maxTitleChars: 60
			});
		}

		// eine neue "Transition"-Instanz aus der Mootool-Klasse "Fx" erstellen
		// diese steuert die Animation, d.h. die lineare Bewegung des Sliders nach unten
		this.fx = new Fx.Styles(this.slider, {
			duration: 1000, 
			wait: false,
			transition: Fx.Transitions.linear,
			onComplete: function() {
				// nach einem fx.stop wird onComplete trotzdem ausgeführt
				if (this.status == 'started') {
					// wenn das unterste (bzw. oberste) Bild nicht mehr sichtbar ist, dieses loeschen
					if (this.options.richtung == 'unten') {
						var unterstesBild = this.slider.getLast();
						while (unterstesBild != undefined && unterstesBild.getTop() > this.box.getStyle('height').toInt() + this.box.getTop()) {
							// DOM umbauen: die Position des Sliders nach oben schieben
							this.slider.setStyle('bottom', this.slider.getStyle('bottom').toInt() + unterstesBild.getStyle('height').toInt() + unterstesBild.getStyle('margin-top').toInt());
							// ... dann unterstes Bild loeschen
							unterstesBild.remove();
							unterstesBild = this.slider.getLast();
						}

					} else {
						var oberstesBild = this.slider.getFirst();
						while (oberstesBild != undefined && oberstesBild.getTop() + oberstesBild.getStyle('height').toInt() < this.box.getTop()) {
							// DOM umbauen: die Position des Sliders nach unten schieben
							this.slider.setStyle('top', this.slider.getStyle('top').toInt() + oberstesBild.getStyle('height').toInt() + oberstesBild.getStyle('margin-top').toInt());
							// ... dann oberstes Bild loeschen
							oberstesBild.remove();
							oberstesBild = this.slider.getFirst();
						}
					}

					// ggf. neues Bild anfuegen und Animation fortsetzen
					this.stop();
					this.fuellen();
					this.start();
				}
			// Funktion an this (also die Klasse!) binden, damit die Methoden verfügbar sind
			}.bind(this)
		});

		// pausieren bei MouseOver über dem Slider
		this.slider.addEvent('mouseover', function() {
			if (this.status == 'started') {
				this.stop();
			}
		}.bind(this));

		// anschliessend ggf. neues Bild anfuegen und Animation fortsetzen
		this.slider.addEvent('mouseout', function() {
			if (this.status == 'stopped') {
				this.fuellen();
				this.start();
			}
		}.bind(this));

		// Slider je nach Richtung ausrichten
		if (this.options.richtung == 'unten') {
			this.slider.setStyle('bottom', '0px');
		} else {
			this.slider.setStyle('top', '0px');
		}

		// Bilder anhand der Kriterien ausfiltern, Slider fuellen 
		this.setzeKriterien(this.options.kriterien);
	},

	// pruefen, ob dem Slider ein neues Bild angefuegt werden muss, damit im naechsten Animationsschritt keine Luecke sichtbar wird
	fuellen: function() {
		if (this.options.richtung == 'unten') {
			if (this.slider.getStyle('height').toInt() + this.slider.getStyle('bottom').toInt() < this.box.getStyle('height').toInt() + this.options.tempo) {
				this.fuegeEin.delay(10, this);
			}
		} else {
			if (this.slider.getStyle('height').toInt() + this.slider.getStyle('top').toInt() < this.box.getStyle('height').toInt() + this.options.tempo) {
				this.fuegeEin.delay(10, this);
			}
		}
	},

	// das naechste Bild oben an den Slider anfuegen und einen Tooltip erstellen
	// diese Funktion ruft wiederum fuellen() auf, was zu einer Rekursion fuehrt, solange der Slider nicht gross genug ist
	fuegeEin: function() {
		// neues Bild erstellen...
		if (this.gefilterteBilder[this.bilder_ptr] != undefined) {
			newImg = new Element('img', {
				'src': this.options.kleineBilder + this.gefilterteBilder[this.bilder_ptr][0],
				'alt': (this.options.grosseBilder != null ? this.options.grosseBilder + this.gefilterteBilder[this.bilder_ptr][0] : ''),
				'title': (this.gefilterteBilder[this.bilder_ptr][1] != null ? this.gefilterteBilder[this.bilder_ptr][1] : ''),
				'id': (this.gefilterteBilder[this.bilder_ptr][3] != null ? this.gefilterteBilder[this.bilder_ptr][3] : ''),
				'class': (this.tooltipClass != null ? this.tooltipClass : '')
			});
			
			// ... beim Klick darauf die übergebene Funktion aufrufen...
			if (this.options.klick != Class.empty()) {
				newImg.addEvent('click', this.options.klick);
			}

			// ... und ganz oben (bzw. unten) im Slider einfuegen
			if (this.options.richtung == 'unten') {
				newImg.injectTop(this.slider);
			} else {
				if (this.slider.getLast() == undefined) {
					newImg.injectInside(this.slider);
				} else {
					newImg.injectAfter(this.slider.getLast());
				}
			}
			// Zeiger auf das naechste Bild vorruecken
			if (this.bilder_ptr + 1 >= this.gefilterteBilder.length) {
				this.bilder_ptr = 0;
			} else {
				this.bilder_ptr += 1;
			}

			// Methode, die Tooltip fuer das neue Bild erzeugt
			if (this.tooltipClass != null) {
				this.tooltip.build(newImg);
			}

			this.fuellen();
		}
	},

	// naechsten Animationsschritt starten: Slider um $step Pixel nach unten (bzw. oben) schieben
	start: function() {
		if (this.status == 'stopped' || this.status == 'paused') {
			if (this.options.richtung == 'unten') {
				this.fx.start({'bottom': [this.slider.getStyle('bottom').toInt(), this.slider.getStyle('bottom').toInt() - this.options.tempo]});
			} else {
				this.fx.start({'top': [this.slider.getStyle('top').toInt(), this.slider.getStyle('top').toInt() - this.options.tempo]});
			}
			this.status = 'started';
		}
	},

	// Slider anhalten
	stop: function() {
		this.fx.stop();
		this.status = 'stopped';
	},

	// Slider anhalten bzw. fortsetzen, wenn pausiert
	pause: function() {
		if (this.status == 'paused') {
			this.fuellen();
			this.start();
		} else if (this.status == 'started') {
			this.fx.stop();
			this.status = 'paused';
		}
	},

	// setzt Suchkriterien zur Auswahl der anzuzeigenden Bilder, wendet sie auf das Array bilder an,
	// speichert die gefilterten Bilder in Array gefilterteBilder und sortiert dieses zufällig
	// leert anschliessend den Slider und baut ihn neu auf
	setzeKriterien: function(kriterien) {
		var tempBilder = new Array();
		if (kriterien.length == 0) {
			// alle Bilder sollen gezeigt werden - Array kopieren
			tempBilder = this.options.bilder.copy();
		} else {
			// es sollen nur bestimmte Bilder gezeigt werden, Array bilder leeren und neu füllen
			tempBilder = this.options.bilder.filter(function(bild, index) {
				// sobald das erste Kriterium bei diesem Bild NICHT zutrifft, bricht every() mit FALSE ab
				return kriterien.every(function(kriterium, index2) {
					return bild[2].contains(kriterium);
				});
			});
		}

		// gefilterte Bilder zufällig sortieren
		this.bilder_ptr = 0;
		this.gefilterteBilder = new Array();
		while (tempBilder.length > 0) {
			var item = tempBilder.getRandom();
			this.gefilterteBilder.push(item);
			tempBilder.remove(item);
		}

		// alle Nodes des Sliders loeschen
		var myStatus = this.status;
		if (myStatus == 'started') {
			this.stop();
		}
		this.slider.empty();

		// wenn die Kriterien dazu führen, dass kein Bild passt, eine Meldung ausgeben
		if (this.gefilterteBilder.length == 0) {
			msg = new Element('p', {'id': 'kriterienfehler'}).setText('Es konnte kein Stoff gefunden werden, der Ihren Kriterien entspricht.');
			msg.injectTop(this.box);
			if (myStatus == 'started') {
				this.status = 'started';
			}
		} else {
			// falls Fehlermeldung (s.o.) vorhanden, löschen
			while (this.box.hasChild($('kriterienfehler'))) {
				$('kriterienfehler').remove();
			}
			// Bilder einfuegen
			this.fuellen();
			if (myStatus == 'started') {
				this.start();
			}
		}
	},
	
	// Geschwindigkeit erhöhen oder verringern - langsamer als 0 und schneller als 160 sind nicht erlaubt
	setzeTempo: function(tempo) {
		if (this.options.tempo + tempo < 40) {
			this.options.tempo = 40;
		} else {
			this.stop();
			if (this.options.tempo + tempo > 160) {
				this.options.tempo = 160;
			} else {
				this.options.tempo = this.options.tempo + tempo;
			}
			this.fuellen();
			this.start();
		}
	},
	
	// Richtung der Animation setzen: "oben" oder "unten" (Standard)
	setzeRichtung: function(richtung) {
		if ((richtung == 'oben' && this.options.richtung == 'unten') ||
		    (this.status == 'paused' && richtung == 'oben')) {
			this.stop();
			this.options.richtung = 'oben';

			var altTop = this.slider.getStyle('top');
			if (altTop == 'auto') {
				altTop = - (this.slider.getStyle('height').toInt() - this.box.getStyle('height').toInt() - 2*this.box.getStyle('border-width').toInt() + this.slider.getStyle('bottom').toInt());
			}
			this.slider.setStyle('bottom', 'auto');
			this.slider.setStyle('top', altTop);

			this.fuellen();
			this.start();
		} else if ((richtung == 'unten' && this.options.richtung == 'oben') ||
		           (this.status == 'paused' && richtung == 'unten')) {
			this.stop();
			this.options.richtung = 'unten';

			var altBottom = this.slider.getStyle('bottom');
			if (altBottom == 'auto') {
				altBottom = - (this.slider.getStyle('height').toInt() - this.box.getStyle('height').toInt() - 2*this.box.getStyle('border-width').toInt() + this.slider.getStyle('top').toInt());
			}
			this.slider.setStyle('top', 'auto');
			this.slider.setStyle('bottom', altBottom);

			this.fuellen();
			this.start();
		}
	}

});

Sidebar.implement(new Options);
