/*
 * Das Panel-Objekt dient zur Verwaltung von Panels.
 * Ein Panel ist dabei einfach ein Bereich, welcher onclick einen content-Div ein- oder ausblendet.
 *
 * Verwendung:
 * 		Plain HTML
 * 			<div class="panel">
 * 				<a href="#" class="tabTitle">Title</a>
 *
 * 				<div>Content</div>
 * 			</div>
 *
 * 		JavaScript:
 * 			Es müssen natürlich die gleichen HTML-Elemente erzeugt werden (Builder.node ftw) und anschließend per
 * 				Panel.specify(titleTag);
 * 			initialisiert werden. titleTag ist dabei das A-Tag.
 *
 *
 * Plain HTML-Panels werden automatisch initialisiert sobald der DOM-Tree geladen ist.
 */

var Panel = {
	/*
	 * Die Methode wird aufgerufen sobald der DOM-Tree geladen ist und initialisiert die Panels, welche sich bereits im DOM-Tree
	 * befinden.
	 */

	init: function() {
		$$(':not(.nopanel) .panel a.tabTitle').each(function(element) {
			Panel.observe(element);
		});
	},


	/*
	 * Die Methode registriert den click-Handler für ein A-Tag.
	 * Als Parameter wird ein A-Element oder das DIV.panel erwartet.
	 */

	observe: function(e) {
		// Wenn das übergebene Element nicht die Klasse "tabTitle" besitzt, dann handelt es sich um das DIV.panel. Entsprechend
		// muss das A-Tag selektiert werden und in die e-Variable geschrieben werden.

		if (!e.hasClassName('tabTitle')) {
			e = e.down('.tabTitle');
		}


		// Evtl. bereits vorhandene Handler entfernen

		e.stopObserving();


		// Den click-Handler des Panel-Objekts registrieren

		e.observe('click', Panel.handleClick);
	},


	/*
	 * Diese Methode dient als einfache Schnittstelle nach außen. Ihr kann entweder ein Array mit Objekten oder ein einzelnes
	 * Objekt übergeben werden. Diese Objekte können entweder das A-Tag oder das DIV.panel sein.
	 *
	 * Die Methode wird benötigt um dynamisch per JS Panels erzeugen zu können. Denn die HTML-Elemente für Panels, welche per JS
	 * generiert werden stehen noch nicht zur Verfügung, wenn dom:loaded getriggert wird und samit sämtliche Panels im Dokument
	 * initialisiert werden.
	 * Nachdem Erzeugen der HTML-Elemente für ein oder mehere Panels muss das JS diese Methode aufrufen um die Panels zu
	 * initialisieren:
	 *
	 * 		Panel.specify([element1, element2]);
	 */
	specify: function(elements) {
		// Prüfen ob ein Array übergeben wurde

		if (Object.isArray(elements)) {
			// Wenn ja: einfach über die elemente im Array itereiern und für jedes Element die observe-Methode aufrufen

			elements.each(function(e) {
				Panel.observe(e);
			});
		} else {
			// Kein Array, also direkt an die observe-Methode weitergeben

			Panel.observe(elements);
		}
	},


	/*
	 * Diese Methode wird aufgerufen, sobald der Benutzer auf den Link klickt. Sie entscheidet ob das Panel eingeblendet oder
	 * ausgeblendet werden soll
	 */

	handleClick: function(event) {
		// Das eigentliche DOM-Element steckt im übergebenen event-Objekt

		var element = event.element();


		// Wenn das Element kein A-Tag ist, wird einfach der nächste, übergeordnete A-Tag verwendet

		element = (element.tagName == 'A' ? element : element.up('a'));


		// Anhand der Klasse "active" kann unterschieden werden ob das Panel bereits aufgeklappt ist oder nicht.

		if (element.hasClassName('active')) {
			Panel.hide(element);
		} else {
			Panel.show(element);
		}


		// return: false, damit der Link nicht aufgerufen wird

		return false;
	},


	/*
	 * Blendet ein Panel aus. Als Parameter wird der A-Tag des entsprechenden Panels erwaret.
	 */

	hide: function(element) {
		// Das Ganze wird nur dann ausgeführt, wenn das Panel wirklich auch eigeblendet ist, sonst kommt es zu unschönen Effekten

		if (element.hasClassName('active')) {
			// Die Klasse "active" entfernen, da das Panel ja gleich nicht mehr sichtbar ist

			element.removeClassName('active');


			// Das DIV-Element nach dem A-Tag beinhaltet den eigentlichen Content des Panels und genau das soll nun ausgeblendet
			// werden

			var div = element.next('div');

			if (div) {
				div.slideUp();
			}
		}
	},


	/*
	 * Blendet ein Panel ein. Als Parameter wird der A-Tag des entsprechenden Panels erwartet.
	 */

	show: function(element) {
		// Das Ganze wird nur dann ausgeführt, wenn das Panel wirklich auch ausgeblendet ist, sonst kommt es zu unschönen Effekten

		if (!element.hasClassName('active')) {
			// Die Klasse "active" setzen, da das Panel ja gleich sichtbar ist

			element.addClassName('active');


			// Das DIV-Element nach dem A-Tag beinhaltet den eigentlichen Content des Panels und genau das soll nun eingeblendet
			// werden

			var div = element.next('div');

			if (div) {
				div.slideDown();
			}
		}
	}
}; // Ende: Panel-Objekt



// Sobald der DOM-Tree geladen wurde, können die Panels, welche bereits im DOM-Tree stehen initialisiert werden.

window.document.observe('dom:loaded', function() {
	Panel.init();
});




//-------------------------------------------------------------------------------------------------------------------------------
// Der JS-Teil der Studienübersichten.


/*
 * Die Klasse dient zur Verwaltung der Studienübersichten und wird in jeder Instanz des Bausteins instanziiert.
 */

var studienOverview = Class.create({
	/*
	 * Beinhaltet das DIV-Element, in dem die Studien-Übersicht generiert werden soll.
	 */

	containerDiv: null,


	/*
	 * Diese Attribute werden dazu verwendet, die Session-Daten zu speichern
	 */

	uid: '',
	sid: '',


	/*
	 * Der requestType definiert, welche Art von Übersicht dargestellt werden soll.
	 */

	requestType: 'CURRICULUM',


	/*
	 * Beinhaltet die Daten, welche vom Searchalyzr zurückkommen
	 */

	data: null,


	/*
	 * Beinhaltet die URL zur Präsenz, damit das Script weiß, wohin der AJAX-Request gehen muss.
	 */

	ionasContainerURL: '',


	/*
	 * Konstruktor der Klasse
	 *
	 * Parameter:
	 * 		containerDivId: ID des DIV-Elements, in dem die Übersicht generiert werden soll
	 * 		sid: Session-ID
	 * 		uid: Benutzer-ID
	 * 		requestType: Legt die Art der Übersicht fest
	 * 		ionasContainerURL: URL der Präsenz
	 */

	initialize: function(containerDivId, sid, uid, requestType, ionasContainerURL) {
		// Alle Parameter als Attribute im Objekt ablegen

		this.containerDiv = $(containerDivId);
		this.sid = sid;
		this.uid = uid;
		this.requestType = requestType;
		this.ionasContainerURL = ionasContainerURL;


		// Daten beziehen und HTML-Elemente generieren

		this.fetchData();
	},


	/*
	 * Nachdem der DOM-Tree in diesem Bereich aufgebaut wurde, kann das container-DIV eingeblendet werden.
	 */

	show: function() {
		this.containerDiv.style.display = 'block';
	},


	/*
	 * Diese Methode setzt den AJAX-Request an den Searchalyzr (über den ajaxProxy) ab.
	 */

	fetchData: function() {
		// this wird innerhalb der Lambda-Funktionen überschrieben, damit man später dennoch darauf zugrifen kann, wird this
		// in der Variable "self" zwischengespeichert

		var self = this;


		// Der jsonParam-POST-Parameter

		var jsonParams = '{"session": {"uid": "' + this.uid + '",  "sid": "' + this.sid + '"},';
		jsonParams += '"requestType": "' + this.requestType + '"}';


		// Den AJAX-Request absetzen

		new Ajax.Request(this.ionasContainerURL + '/searchalyzr.jspx', {
			// Funktion wird aufgerufen, wenn der AJAX-Request erfolgreich war

			onSuccess: function(response) {
				// Die JSON-Struktur, die vom Searchalyzr geliefert wird, im data-Attribut des Objekts speichern.

				eval('self.data = ' + response.responseText);


				// HTML-Struktur generieren

				self.buildHTML();
		  	},


		  	// Die Such-Parameter

		  	parameters: {
				aktion: 'searchCurriculum',
				jsonParam: jsonParams,
				searchSystemType: 'seminardb'
		  	}
		}); // Ende: AJAX-Request
	},


	/*
	 *	Diese Methode erzeugt aus den Daten (this.data) die HTML-Struktur, welche zur Darstellung benötigt wird
	 */

	buildHTML: function() {
		// Da in den Lamda-Funktionen this ersetzt wird, wird das this, welches hier den Verweis auf die Instanz dieser Klasse
		// beinhaltet in der "self"-Variable gespeichert, so dass man jederzeit auf das Objekt zugreifen kann.

		var self = this;


		// Wenn keine Daten vom Server gegeben sind, soll einfach nur der Hinweis ausgegeben werden, dann keine Daten gefunden
		// wurden

		if (this.data.semester.length > 0) {
			// Hilfsvariable, die mit jedem Semester inkrementiert wird. Dient dem Zweck eindeutige IDs für die HTML-Elemente
			// generieren zu können.

			var semesterId = 0;


			// Iteration über die Semester
			// Die Variable semester beinhalter ein Objekt folgender Sturktur:
			//
			//		{
			//			expanded: true,					# gibt an, ob dieses Semester per default aufgeklappt ist, oder nicht
			//			name: "WS 2010"					# Name des Semesters
			//			resultCategories: {
			//				resultCategory: [ ... ]		# Beinhaltet die Kategorien
			//			}
			//		}

			this.data.semester.each(function(semester) {
				// Die ID-Hilfsvariable inkrementieren

				semesterId++;


				// Das Panel wird von der methode createPanel erzeugt und repräsentiert ein Semester. Die
				// ein- und ausblend-Funktionen übernimmt die Klasse Panel

				var panel = self.createPanel(semester.name, semesterId.toString(), (semester.expanded));


				// Und noch eine Hilfsvariable für eindeutige IDs, diesmal aber für die Kategorien

				var categoryCounter = 0;


				// Wieder eine Hilfsvariable für eindeutige IDs und even/odd-ClassNames der TRs

				var rowCounter = 0;


				// Die letzte Zähler-Variable wird benötigt um feststellen zu können, bei welcher Zellen-Iteration man sich gerade
				// befindet um so auf die Spalten-Definition zugreifen zu können.

				var cellCounter = 0;


				// Iteration über die Kategorien
				// Die Variable category beinhaltet ein Objekt folgender Struktur:
				//
				// 		{
				// 			columnDefinitions: {
				// 				columnDefinition: [ ... ]		# Array, welches die Spalten-Definitionen beinhaltet
				//			},
				//
				//			id: "",								# I.d.R. leer, wird nicht benötigt
				//			label: "Volkswirtschaft",			# Name der Kategorie
				//			offset: "",							# Kann ignoriert werden
				//
				//			rows: {								# Array, welches die Zeilen beinhaltet
				//				row: [...]						# (also die eigentlichen Daten der Tabelle)
				//			},
				//
				//			sorting: "",						# null?
				//			totalHits: ""						# Kann ignoriert werden
				// 		}

				semester.resultCategories.resultCategory.each(function(category) {
					// Die Hilfsvariable inkrementieren ...

					categoryCounter++;


					// Der content-Div beinhaltet den eigentlichen Inhalt (also später die table).
					// Um weitere Elemente einhängen zu können, wird das DOM-Element in der Variable content gespeichert

					var content = Builder.node('div', {
						id: 'category' + categoryCounter.toString() + 'Content',
						className: 'categoryContent'
					});


					// Die H1 ist die Überschrift der Kategorie. Der Text kommt aus dem category

					content.insert(Builder.node('h1', category.label));


					// Die eigentliche Table erzeugen und in der contentTable-Variable speichern, damit diese
					// später auch mit Inhalt (TRs, THs, TDs) befüllt werden kann

					var contentTable = Builder.node('table');


					// Der IE7 braucht ein thead & tbody ...

					contentTable.insert(Builder.node('thead'));
					contentTable.insert(Builder.node('tbody'));


					// Generieren der Kopfzeile

					var headTR = Builder.node('tr');


					// Iteration über die Kopfzellen.
					// Die Variable column beinhaltet ein Objekt folgender Struktur:
					//
					// 		{
					// 			align: "left",			# Irrelevant an dieser Stelle
					// 			id: "TITLE",			# Eindeutige ID
					// 			label: "Titel",			# Beschriftung der Zelle
					// 			sortable: false,		# Inhalt der Zelle
					// 		}

					category.columnDefinitions.columnDefinition.each(function(column) {
						// TH erstellen, column.label reinschreiben und in die headTR einhängen
						
						headTR.insert(Builder.node('th', {className: column.id} , column.label));
					});


					// Die fertige headTR kann nun in die table eingehongen werden

					contentTable.down('thead').insert(headTR);



					// Iteration über die Zeilen.
					// Die Variable row beinhaltet ein Objekt folgender Struktur:
					//
					// 		{
					// 			cells: {
					// 				cell: [ ... ]		# Beinhaltet die Zellen
					// 			}
					// 		}

					if (category.rows) {
						category.rows.row.each(function(row) {
							// Den Zeilen-Zähler inkrementieren (wird für even/odd und IDs benötigt)

							rowCounter++;


							// Die Zeile bekommt ein even/odd-className und das fertige DOM-Element wird in der tr Variable gespeichert
							// damit diese später einfach mit Inhalt befüllt werden kann

							var tr = Builder.node('tr', {
								className: (rowCounter % 2 == 0 ? 'even' : 'odd')
							});


							// Reset der Zellen-Zählervariable

							cellCounter = 0;


							// Iteration über die Zellen.
							// Die Variable cell beinhaltet ein Objekt folgender Struktur:
							//
							// 		{
							// 			link: "",				# ???
							// 			linkTarget: "",			# ???
							// 			style: "",				# ???
							// 			text: "",				# Inhalt der Zelle
							// 		}

							row.cells.cell.each(function(cell) {
								// align-Eigenschaft aus der Spalten-Definition auslesen

								var align = category.columnDefinitions.columnDefinition[cellCounter].align;
								var className = category.columnDefinitions.columnDefinition[cellCounter].id;


								// TD erstellen, cell.text reinschreiben und in die TR einhängen
								tr.insert(Builder.node('td', {align: align, className: className}).insert(cell.text));


								// Die Zählervariable wird benötigt um auf die entsprechende Spalen-Definition zugreifen zu können.
								// Der Counter muss mit 0 beginnen, daher der Inkrement erst am Ende dieser Funktion.

								cellCounter++;
							});


							// Nachdem die TR fertig gebaut ist, kann diese in die Tabelle eingefügt werden

							contentTable.down('tbody').insert(tr);

						}); // Ende Iteration Zeilen


						// Die fertige Tabelle wird in das das content-Div eingehongen

						content.insert(contentTable);
					} else {
						// Es existieren keine Zeilen in dieser resultCategorie

						$(content).insert('<div class="empty-indicator">' +
								'In diesem Bereich konnten keine passenden Einträge gefunden werden</div>');
					}


					// ... und das content-Div landet am Ende im tabContent (also im Panel)

					panel.down('div.tabContent').insert(content);

				}); // Ende Iteration Kategorien


				// Em Ende ist bekannt, wie viele Zeilen in einem Semester vorhanden sind und die Anzahl kann in das entsprechende
				// Span-Tag geschrieben werden

				panel.down('span.counter').insert('(' + rowCounter + ')');

			}); // Ende Iteration Semester
		} else {
			// Es sind keine Daten verfügbar, also nur den Hinweis ausgeben
			var emptyIndicator = Builder.node('div', { className: 'empty-indicator' },
				'In diesem Bereich konnten keine passenden Einträge gefunden werden');
			var tabContent = Builder.node('div', { className: 'tabContent active-tab' }, emptyIndicator);

			this.containerDiv.insert(tabContent);
		}
	},


	/*
	 * Erstellt unter Verwendung des Panel-Objekts ein Panel, welches ein Seminar-Repräsentiert.
	 *
	 * Parameter:
	 * 		label: Name des Semesters
	 * 		semesterId: Eindeutige ID für das Semester (im einfachsten Falle eine fortlaufende Nummer)
	 * 		active: Gibt an ob das Panel direkt geöffnet werden soll, oder nicht
	 */

	createPanel: function(label, semesterId, active) {
		// Das SPAN-Tag mit dem Label des Panels

		var label = Builder.node('span', label)


		// Wird neben dem Label-SPAN dargestellt und beinhaltet später die Anzahl der Zeilen in einem Studium

		var counter = Builder.node('span', { className: 'counter' });


		// Das A-Tag welches für die Panel-Funktionalität benötigt wird, hier werden "label" und "counter" eingehongen.

		var a = Builder.node('a',{
			id: 'semester' + semesterId + 'Tab',
			className: 'tabTitle' + (active ? ' active' : ''),
			href: '#',
			onclick: 'return false;'
		}, [ label, counter ]);


		// Ein Wrapper-Div, welches verhindert, dass es bei den Panel-Slide-Effekten zu seltsamen Effekten kommt.

		var div2 = Builder.node('div');


		// Das DIV-Element, welches den eigentlichen Inhalt beinhaltet.

		var div = Builder.node('div', {
			id: 'semester' + semesterId + 'Content',
			className: 'tabContent',
			style: (active ? '' : 'display: none;')
		}, [ div2 ]);


		// Und zulest das DIV-Element, welches das Panel umgibt. Das A-Tag und das Content-DIV-Tag wird hier eingehongen

		var panel = Builder.node('div', { className: 'searchalyzrSystem panel'}, [ a, div ]);


		// Das Panel das DIV-Elements einhängen, in welches die Übersicht generiert werden soll

		this.containerDiv.insert(panel);


		// Initialisieren des Panels (registrieren der Event-Handler)

		Panel.specify(panel);


		return panel;
	}
}); // Ende: Klasse studienOverview
