/*
 * CascadingSelector
 *
 * A class to handle arbitrarily deep cascading <select> objects.
 *
 * The constructor takes two parameters:
 *	itsSelects:
 *		An array of <select> object references that are to be cascaded, in cascade order.
 *
 *	itsData:
 *		The data to populate the cascades.  It is an array of objects with two properties:
 *			option: the <option> object for the select, created with new Option().
 *			values: an array of data to cascade to the next <select> in the list.  The
 *					elements are of the same structure (i.e. { option: ..., values: ... }).
 *					If the cascade goes no further then the elements can also be <option>
 *					objects.
 *
 * The constructor will set up the onchange handlers to make the cascade work, chaining to
 * any existing onchange handlers.  Note that onchange handlers do not get called when
 * code changes the selection, only when the user does, though.  It is an open question
 * whether this code should call those handlers explicitly when cascading new values into
 * a <select>.
 *
 * Dependencies:
 *	ParameterBinding.js
 */
function CascadingSelector(inSelects,inData)
{
	var self = this;
	var itsData = inData;
	var itsSelects = inSelects;


	function loadOptions(inSelect,inOptionSpecification)
	{
		var i;
		var isSelected;

		isSelected = false;
		for (i = 0; i < inOptionSpecification.length; i++)
		{
			if (inOptionSpecification[i].option !== undefined)
				inSelect.options[i] = inOptionSpecification[i].option;
			else
				inSelect.options[i] = inOptionSpecification[i];
			if (inSelect.options[i].defaultSelected)
			{
				inSelect.selectedIndex = i;
				isSelected = true;
			}
		}
		inSelect.options.length = inOptionSpecification.length;
		if (!isSelected)
			inSelect.selectedIndex = 0;
	}


	this.changeHandler = function(inDepth)
	{
		var i;
		var theSpec;

		theSpec = itsData;
		for (i = 0; i <= inDepth && i < itsSelects.length && theSpec !== undefined; i++)
			theSpec = theSpec[itsSelects[i].selectedIndex].values;
		for ( ; i < itsSelects.length; i++)
		{
			loadOptions(itsSelects[i],theSpec !== undefined ? theSpec : []);
			if (theSpec !== undefined)
				theSpec = theSpec[itsSelects[i].selectedIndex].values;
		}
	};


	this.reset = function()
	{
		var i;
		var theHandler;

		if (itsSelects !== undefined && itsData !== undefined)
		{
			for (i = 0; i < itsSelects.length; i++)
			{
				theHandler = itsSelects[i].onchange;
				if (theHandler === undefined || theHandler === null)
					itsSelects[i].onchange = ParameterBinding.bind1(self.changeHandler,i);
				else
					itsSelects[i].onchange = ParameterBinding.chain(ParameterBinding.bind1(self.changeHandler,i),theHandler);
			}
			loadOptions(itsSelects[0],itsData);
			self.changeHandler(0);
		}
	};


	self.reset();
}
