/**
 * ./out/lascana/src/lca_productVariantSelects.class.js
 * @author Bjoern Simon Lange <bjoern.lange@twt.de>, 31.10.2009
 * @package out
 * @subpackage lascana
 * @version $id$
 */

/**
 * Diese Klasse uebernimmt das Select-Menue-Handling der mehrfachen Variantendimensionen.
 *
 * Vorraussetung fuer diese Klasse ist eingebundenes jQuery.
 * @author Bjoern Simon Lange <bjoern.lange@twt.de>, 31.10.2009
 * @package out
 * @subpackage lascana
 * @param Array aUsedSelects Die genutzten Select-Felder.
 * @version $id$
 */
function LCA_ProductVariantSelects(aUsedSelects)
{
	/**
	 * Diese Elemente sollen mit aktiviert und deaktiviert werden, wenn die Select-Auswahl erfolgt.
	 * @access private
	 * @var Array
	 */
	var aEnablingChain = new Array();

	/**
	 * Die behandelten Select-Menues.
	 * @access private
	 * @var Array
	 */
	var aSelects = aUsedSelects;

	/**
	 * Diese Eigenschaft gibt an ob das JSON noch geladen werden muss.
	 * @access private
	 * @var bool
	 */
	var bLoaded = false;

	/**
	 * Wieviele Select-Menues behandeln wir?
	 * @access private
	 * @var Integer
	 */
	var iSelectCount = aUsedSelects.length;

	/**
	 * Bei einem Refresh ist hier der aktuelle Index des geaenderten Select-Menues zu finden.
	 * @access private
	 * @var Integer
	 */
	var iUsedSelect = 0;

	/**
	 * Dieses Objekt wird aufgerufen, um z.B. bei Aenderung eines Selects bestimmte Aktionen auszufueren.
	 * Object
	 */
	var oContentHandler = null;

	/**
	 * Die Daten der Select als JSON-Objekt.
	 * @access private
	 * @var Object
	 */
	var oJsonSelectData = null;

	/**
	 * Klasseninstanz zur Sichtbarkeit in privaten Methoden.
	 * @access private
	 * @var ProductVariantSelects
	 */
	var oSelf = this;

	/**
	 * Dieses Zeichen wird genutzt um die ausgewaehlten Texte zu konkatinieren.
	 * @access public
	 * @var string
	 */
	this.sConcatChar = '|';

	/**
	 * Der aktuell ausgewaehlte Text der Select-Felder, normalerweise mit einer Pipe konkatiniert.
	 * @access private
	 * @var String
	 */
	var sSelectedTexts = '';

	/**
	 * Fuegt den ausgewaehlten Text des angegebenen Select-Feld der Auswahl hinzu.
	 * @access private
	 * @param object oSelect Das jeweilige Select-Menue.
	 * @return void.
	 */
	var addSelectString = function(oSelect)
	{
		sSelectedTexts += oSelf.sConcatChar + urlencode($(oSelect.options[oSelect.selectedIndex]).text());
	}; // function

	/**
	 * Fuegt Elemente hinzu, die in den Chain fuer das Aktivieren und Deaktivieren auch beachtet werden sollen.
	 * @access public
	 * @param Object oElement Das deaktivierbare HTML-Element.
	 * @return void
	 */
	this.addToEnablingChain = function(oElement) {
		if (jQuery.inArray(oElement, aEnablingChain) === -1) // Dies funktioniert nicht sauber!
		{
			aEnablingChain.push(oElement);
		} // if
	}; // function

	/**
	 * Returnt die aktuellen JSON-Daten gemaesz ausgewaehltem Text.
	 * @access private
	 * @see sSelectedTexts, oJsonSelectData
	 * @return object
	 */
	var getActualJsonData = function()
	{
		return oJsonSelectData[sSelectedTexts];
	}; // function

	/**
	 * Laedt die Select-Informationen.
	 *
	 * Diese Methode wurde ausgelagert um den Zeitpunkt des Ladens bestimmen zu koennen.
	  * @param string sFetchingUrl Unter dieser URL koennen die Select-Informationen als JSON abgerufen werden.
	  * @param boolean bWithSync Asynchrones (false) oder synchrones (true) Laden.
	  * @return void
	 */
	this.loadJsonData = function(sFetchUrl, bWithSync)
	{
		if (!bLoaded)
		{
			bLoaded = true;
			aSelects.attr('disabled', true);
			// TODO Was passiert wenn der AJAX-Request fehlschlaegt?! Markierung fuer Wartezeit anzeigen.
			$.ajax({
				async: (!bWithSync),
				dataType: 'json',
				success: function(oData, status)
				{
					aSelects.attr('disabled', false);

					/*
					 * Sobald wir mehr als 2 Select-Felder haben, sollten diese deaktiviert sein, da es imho keinen Zustand
					 * gibt, bei dem die Felder > Index 2 schon aktiviert sein koennten.
					 */
					if (aSelects.size() > 2)
					{
						aSelects.slice(2).attr('disabled', true);
					} // if

					oJsonSelectData = oData;
				}, // function
				url: sFetchUrl
			});
		} // if
	} // function

	/**
	 * Iteriert durch die Elemente der Chain und aktiviert oder deaktiviert sie.
	 * @access private
	 * @var boolean bEnabling Sollen die Elemente aktiviert oder deaktiviert werden?
	 * @return void
	 */
	var processEnablingChain = function(bEnabling)
	{
		for (iRound in aEnablingChain)
		{
			// Moechtest du weitere Aktionen fuer ein Element ausfuehren, regstriere den Change-Handler.
			$(aEnablingChain[iRound]).attr('disabled', !bEnabling).trigger('change');
		} // for
	}; // function

	/**
	 * Refresht die Folgefelder mit den entsprechenden JSON-Daten fuer die Select-Felder.
	 * @access public
	 * @param object oChangedSelect Das aktuell geaenderte Select-Menu.
	 * @return boolean
	 * @see resetFollowingFields(), resetSelectText()
	 */
	this.refresh = function(oChangedSelect)
	{
		if (oJsonSelectData === null)
		{
			return false;
		} // if

		iUsedSelect           = jQuery.inArray(oChangedSelect, aSelects);
		var iRefreshingBorder = iUsedSelect + 1;

		triggerChanges();
		resetFollowingFields();
		resetSelectText();

		if (iRefreshingBorder >= iSelectCount)
		{
			processEnablingChain(oChangedSelect.selectedIndex);
		} // if

		if (!oChangedSelect.selectedIndex && oChangedSelect.value == '')
		{
			return false;
		} // if

		// Das erste Element soll nie refresht werden.
		for (iRound = 1; iRound <= iRefreshingBorder; iRound++)
		{
			if (oIteratedElement = aSelects[iRound])
			{
				oIteratedElement.disabled = false;

				if ((iRound > iUsedSelect) && (oUsedValues = getActualJsonData()))
				{
					jQuery.each(
						oUsedValues,
						function(sSelectText, sArticleId)
						{
							$(oIteratedElement).append(
								'<option value="' + sArticleId + '">' + decodeURIComponent(sSelectText.replace(/\+/g, '%20')) + '</option>'
							);
						}
					);
				}

				if (iRound < iRefreshingBorder)
					addSelectString(oIteratedElement);
			} // if
		} // for

		return true;
	}; // function

	/**
	 * Resettet alle Folgefelder des aktuell geaenderten Elements.
	 * @access private
	 * @see iUsedSelect
	 * @return void
	 */
	var resetFollowingFields = function()
	{
		for (iRound = iUsedSelect + 1; iRound < iSelectCount; iRound++)
		{
			var oIteratedElement = $(aSelects[iRound]);
			oIteratedElement.attr('disabled', 'disabled');

			/*
			 * Hier der harte Aufruf auf die options direkt statt auf oIteratedElement.children() um z.B. moegliche spaetere
			 * optiongroups etc auszuschlieszen.
			 */
			var oFirstElement = aSelects[iRound].options[0];
			// @todo .html schlaegt im IE bei neuer jQuery-Version fehl
			oIteratedElement.html('');
			oIteratedElement.append(oFirstElement);
		} // for

		processEnablingChain(false);
	}; // function

	/**
	 * Diese Methode resettet den Stringh zu Auswahl der tieferen Variantenebenen.
	 * @access private
	 * @return void
	 */
	var resetSelectText = function()
	{
		// .replace(/ /g, '+')
		// Der Replace muss leider noch hinzu, da das Leerzeichen anders umgesetzt wird.
		sSelectedTexts = urlencode($(aSelects[0].options[aSelects[0].selectedIndex]).text());
	}; // function

	/**
	 * Setzt den zusaetzlichen Content Handler bei Aenderung eines Selects.
	 * @access public
	 * @param Object oHandler
	 * @return void
	 * @see oContentHandler
	 */
	this.setContentHandler = function(oHandler)
	{
		oContentHandler = oHandler;
	}; // function

	/**
	 * Diese Methode ueberprueft ob der ContentHandler als Objekt eine Methode fuer die Select-Aenderung hat und ruft diese auf.
	 * @access private
	 * @return void
	 * @see iUsedSelect
	 * @see aSelects
	 */
	var triggerChanges = function()
	{
		if ((oContentHandler !== null) )
		{
			var oUsedSelect = aSelects[iUsedSelect];

			if (typeof oContentHandler['handleSelect'] === 'function')
			{
				oContentHandler.handleSelect(iSelectCount, iUsedSelect, oUsedSelect);
			}; // if

			var sFunction = 'handleSelectLevel' + (iUsedSelect + 1);

			if (typeof oContentHandler[sFunction] === 'function')
			{
				oContentHandler[sFunction](oUsedSelect);
			} // if
		} // if
	}; // function

	/**
	 * Workaround um die exakte Schreibweise wie bei PHP zu erhalten.
	 * @access private
	 * @param String sString
	 * @return String
	 */
	var urlencode = function(sString)
	{
		return encodeURIComponent((sString + '').toString())
			.replace(/!/g, '%21')
			.replace(/'/g, '%27')
			.replace(/\(/g, '%28')
			.replace(/\)/g, '%29')
			.replace(/\*/g, '%2A')
			.replace(/%20/g, '+');
	}; // function

	/**
	 * Sind in allen Selects Dinge ausgewaehlt?
	 * @author Sabine Salzsiedler
	 * @return bool
	 */
	this.getSelectsStatus = function()
	{
		var bDetailsSelected = true;

		aSelects.each(function (i)
		{
			// Sonderbehandlung fuer ersten Select: hier darf auch die erste
			// Option ausgewaehlt sein, da wegen Ticket 16848 "Farbe" als
			// erste Option entfaellt.
			if ((this.selectedIndex == 0) && (i != 0))
			{
				bDetailsSelected = false;
			}
		});

		return bDetailsSelected;
	}; // function
}; // class