var aLinkedMultipleSelectConnects = new Object();

var aSelectRelatedOptions = new Array();


// Checks to see if the select list that is being built has a connection to another list.
// If it has a connection to another list then it's not allowed to have values that are already
// in the other list.
function LinkedSelectMayHaveValue(sSelectID, xValue)
{
	sSelectID = sSelectID.replace(/\./g,'');
	if (aLinkedMultipleSelectConnects[sSelectID] == undefined)
	{
		return true;
	}
	else
	{
		eTo = document.getElementById(aLinkedMultipleSelectConnects[sSelectID]);
		i = 0;
		while (i < eTo.options.length)
		{
			if (eTo.options[i].value == xValue)
			{
				return false;
			}
			i++;
		}
		return true;
	}
}

// Reigster a connection between select lists.  Connections are used by LinkedSelectMayHaveValue
function LinkedSelect_RegisterMultiple(from, to)
{
		from = from.replace(/\./g,'');
		aLinkedMultipleSelectConnects[from] = to;
}

function setOptionsRelatedTo(dest,val)
{
	//alert('set options related to');
	//debugObject(dest);
	//alert('Dest has options ' + dest.options.length);
	//alert('first option is ' + dest.options[0].value);
	//alert('id is ' + dest.id);
	if (aSelectRelatedOptions[dest.id] == undefined)
	{
		aSelectRelatedOptions[dest.id] = new Array();
		for (var i=0; i < dest.options.length; i++)
		{
			aSelectRelatedOptions[dest.id][i] = new Array(dest.options[i].text,dest.options[i].value);
		}
	}


	var selectedoption=0;
	if (dest.selectedIndex == -1)
	{
		dest.selectedIndex = 0;
	}
	if (dest.options.length > 0)
	{
		selectedoption=dest.options[dest.selectedIndex].text;
	}
	else
	{
		selectedOption=null;
	}

	if (val != undefined)
		dest.options.length = 0;

	//alert('Value is ' + val);
	for (i = 0; i < aSelectRelatedOptions[dest.id].length; i++)
	{
		if (aSelectRelatedOptions[dest.id][i][1].indexOf(val+'-') == 0)
		{
			//alert('option ' + aSelectRelatedOptions[dest.id][i][1] + ' is  in list');
			if (LinkedSelectMayHaveValue(dest.id,aSelectRelatedOptions[dest.id][i][1]))
			{
				//alert('may have value');
				dest.options[dest.options.length] = new Option(aSelectRelatedOptions[dest.id][i][0],aSelectRelatedOptions[dest.id][i][1]);
				if(aSelectRelatedOptions[dest.id][i][0]==selectedoption)
					dest.options[dest.options.length-1].selected=true;
			}
		}
	}

	if (dest.options.length == 0)
	{
		dest.options[dest.options.length] = new Option('None','');
	}
}



function initSelectRelated(selects,relatedValue)
{
	//alert('initSelectRelated' + relatedValue);
	if (arguments.length==1)
		relatedValue='';
	//initLinkedSelect(selects,1);
	var options = new Array();
	var nextselect = new Array();
	var val = relatedValue;
	for (k = selects.length-1 ; k > 0 ; k-- )
	{
		setOptionsRelatedTo(selects[k],relatedValue);
		if (selects[k+1] != undefined)
			val = selects[k+1].options[selects[k+1].selectedIndex()];
	}
}


function initLinkedSelect(selects) {

	var options = new Array();
	var nextselect = new Array();
	var stackLevel =0;
	for (k = selects.length-2 ; k >= 0 ; k-- )
	{
		var from=selects[k];
		var to=selects[k+1];
		if (!to.options)
			continue;

		options[from.name]=new Array();
		// below causes problems when linked selects are inside a hidden div
		//(from.style || from).visibility = "visible";
		for (var i=0; i < to.options.length; i++)
		{
			options[from.name][i] = new Array(to.options[i].text,to.options[i].value);
		}

		nextselect[from.name]=k;
		from.onchange = function() {
			to=selects[nextselect[this.name]+1];
			//settingSecondInChain = stackLevel == 0;
			settingSecondInChain = selects.indexOf(this) == 0;
			if (this.selectedIndex == -1)
			{
				this.selectedIndex = 0;
			}
			var fromCode;
			if (this.options)
			{
				fromCode = this.options[this.selectedIndex].value;
				if(fromCode.indexOf('__Any__') == -1)	// __any__ is distinct enough. blindly adding a '-' causes problems with >2 selects
				{
					fromCode += '-';
				}
				else if(fromCode.indexOf('__Any__') != 0)
				{
					// The next select down from the one changed should show all options starting with val-
					// e.g. 1-1, 1-2, 1-__Any__
					// not all options starting with val-__any__.
					// Subsequent selects should show val-__any__

					if(settingSecondInChain)
					{
						fromCode = fromCode.slice(0,fromCode.indexOf('__Any__'));
					}
				}

			}
			else
				fromCode = '';


			var selectedoption=0;
			if (to.selectedIndex == -1)
			{
				to.selectedIndex = 0;
			}
			if (to.options.length > 0)
			{
				selectedoption=to.options[to.selectedIndex].text;
			}
			else
			{
				selectedoption=null;
			}

			to.options.length = 0;
			for (i = 0; i < options[this.name].length; i++) {
				if (options[this.name][i][1].indexOf(fromCode) == 0)
				{
					if (LinkedSelectMayHaveValue(to.id,options[this.name][i][1]))
					{
						to.options[to.options.length] = new Option(options[this.name][i][0],options[this.name][i][1]);
						if(options[this.name][i][0]==selectedoption)
							to.options[to.options.length-1].selected=true;
					}
				}
			}
			if(selects[nextselect[to.name]] && selects[nextselect[to.name]].onchange){
				stackLevel++;
				selects[nextselect[to.name]].onchange();
			} else {
				stackLevel =0;
			}
		}
		from.onchange();
		YAHOO.util.Event.on(window, 'unload', function() { 
			if (from)
				from.onchange = null; 
			if (selects)
			{
				for (var i = 0, iMax = selects.length; i<iMax; i++) {
					if (selects[i] && selects[i].options)
						selects[i].options.length = 0; 
					selects[i] = null;
				}
			}
			selects = null;
			from = null;
			to = null;
		});
	}


}

function LinkedMultipleSelect_AddSelected(aSelects, sCollectionID, sHiddenFieldID)
{
	// called as an action on the '>>' button - moves the selected options from 'items' to 'c'

	listC = document.getElementById(sCollectionID);

	eLeaves = aSelects[aSelects.length-1];

	i=0;
	while (i < eLeaves.options.length)
	{
		if (eLeaves.options[i].selected == true)
		{
			// Is this item already in the 'c' list?
			j = listC.options.length;
			bAlreadyInList = false;
			for (k=0; k<j; k++)
			{
				if (listC.options[k].value == eLeaves.options[i].value)
				{
					bAlreadyInList = true;
					i++;
				}
			}

			if (bAlreadyInList == false)
			{
				// Item is not in c list - move it across and place it at the end of the list
				j = listC.options.length;

				text = eLeaves.options[i].text;
				// recurse up the list of items to find the full path and display it in the text
				for(k=aSelects.length-2;k >= 0; k--)
				{
					eParent = aSelects[k];
					text = eParent.options[eParent.selectedIndex].text + ': ' + text;
				}
				value = eLeaves.options[i].value;
				// create a new option
				newOpt = new Option(text, value);
				newOpt.setAttribute('leaftext',eLeaves.options[i].text);
				// add the option to c
				listC.options[j] = newOpt;
				// delete the option from items
				eLeaves.options[i] = null;
				// no need to increment i because the list is now one element shorter.
			}

			else
			{
				i++;
			}
		}
		else
		{
			i++;
		}
	}

	LinkedMultipleSelect_SynchroniseHiddenField(sCollectionID, sHiddenFieldID);
}

function LinkedMultipleSelect_RemoveSelected(aSelects, sCollectionID, sHiddenFieldID)
{
	// called as an action on the '<<' button - removes the selected options from 'c' and tries to put them back into 'items'

		listC = document.getElementById(sCollectionID);
		eLeaves = aSelects[aSelects.length-1];

		i = 0;

		while (i < listC.options.length)
		{
			if (listC.options[i].selected == true)
			{
				 sValue = listC.options[i].value;
				 aValues = sValue.split("-unlikelytobefoundinanid-");

				 // if there is only one level of selects then there is no concept of a group
				 if (aSelects.length > 1)
				 {
				 	eGroups = aSelects[aSelects.length-2];
				 	group = aValues[aValues.length-2];
				 }
				 else
				 {
				 	eGroups = null;
				 	group = null;
				 }


				 if (eGroups == null || aSelects[aSelects.length-2].options[aSelects[aSelects.length-2].selectedIndex].value == group)
				 {
				 			//This is the correct group
							// Is this item already in the group?
							j = eLeaves.options.length;
							bAlreadyInList = false;
							for (k=0; k<j; k++)
							{
								if (eLeaves.options[k].value == listC.options[i].value)
								{
									bAlreadyInList = true;
									break;
								}
							}

							if (bAlreadyInList == false)
							{
								// Item is not in the group so move it across

								j = eLeaves.options.length;
								// Collect the item properties
								text = listC.options[i].getAttribute('leaftext');
								value = listC.options[i].value
								// create a new option
								newOpt = new Option(text, value);
								// delete the option from c
								listC.options[i] = null;
								// add the option to items
								eLeaves.options[j] = newOpt;
								// no need to increment i because the list is now one element shorter.
							}
							else
							{
								// item is already in items list so just remove it from the 'collection
								listC.options[i] = null;
								// no need to increment i because the list is now one element shorter.
							}
					}

					else
					{
						// the correct group is not selected so this is not the correct items list - so just remove the item from the 'c' list
						listC.options[i] = null;
						// no need to increment i because the list is now one element shorter.
					}
				}
				else
				{
					i++;
				}
			}

			LinkedMultipleSelect_SynchroniseHiddenField(sCollectionID, sHiddenFieldID);
}

function LinkedMultipleSelect_SynchroniseHiddenField(sCollectionID, sHiddenFieldID)
{
	var eCollection = document.getElementById(sCollectionID);
	var eHiddenField = document.getElementById(sHiddenFieldID);

	eHiddenField.value = '';

	var sVal = '';
	var sSeparator = ',';

	var i=0;
	while (i < eCollection.options.length)
	{
		var oOpt = eCollection[i];
		var aVals = oOpt.value.split('-unlikelytobefoundinanid-');
		if (sVal != '')
			sVal += sSeparator;
		sVal += aVals[aVals.length-1];
		i++;
	}

	eHiddenField.value = sVal;
}

/** add array.indexOf compatibility method for browsers without it **/
if (!Array.prototype.indexOf)
{
  Array.prototype.indexOf = function(elt /*, from*/)
  {
    var len = this.length;

    var from = Number(arguments[1]) || 0;
    from = (from < 0)
         ? Math.ceil(from)
         : Math.floor(from);
    if (from < 0)
      from += len;

    for (; from < len; from++)
    {
      if (from in this &&
          this[from] === elt)
        return from;
    }
    return -1;
  };
}


