///////////////////////////////////////////////////////
// by danny					     //
// 						     //
// refer to http://wiki.project.cvs/Cascading_Select //
///////////////////////////////////////////////////////

//////////////////////////////////////////////////////////
// MSIE6 requires all OPTIONS to have @value attribute! //
//////////////////////////////////////////////////////////
// If the @value is not used then SELECTBOX.value is empty string.
// There is only SELECTBOX.text available but it is difficult to
// distinguish if the @value is empty or simply not set. We need to
// check the OPTION.hasAttribute('value') ... but it is simply better to
// have value all the time. (Maybe in the future I will change it if it
// causes problms.

/**
 * This method must be called in order to have the Relations work.
 * It hooks the applyTaRels() on "change" event of the select boxes.
 *
 * @access public
 * @param array ids Array of SELECT box' IDs
 * @param array rels Array ordered list of all possible item value combinations
 * @return void
 */
function initTaRels(ids, rels) {
    for(var node, c=0; c < ids.length; c++) {
	node=document.getElementById(ids[c]);
	//alert(node.tagName+'[@id='+node.id+']:: ('+(typeof node.value)+') '+node.value+', '+node.selectedIndex+', '+node.options[node.selectedIndex].value);
	if (!node) {
	    alert('relations.js: Element with ID "'+ids[c]+'" not found!');
	} else {
	    node.onchange=function() {
		applyTaRels(ids, rels);
	    }
	    node.onfocus=function() {
		applyTaRels(ids, rels, this.id);
	    }
	    node.onclick=function() {
		applyTaRels(ids, rels, this.id);
	    }
	}
    }
    applyTaRels(ids, rels);
}

/**
 * Every call to this method will cycle all SELECT's by the ID and hide
 * all values that cannot be selected given the current combination of
 * selected values.
 *
 * @param array ids Array of SELECT box' IDs
 * @param array rels Array ordered list of all possible item value combinations
 * @param string chooseFromBoxId Ignore the value set on this box - pretend that it has "ANY"
 * @return void
 */
function applyTaRels(ids, rels, chooseFromBoxId) {
    var c;
    var elements=[];


    for(c=0; c < ids.length; c++) {
	// Add to the list of SELECT boxes
	elements.push(document.getElementById(ids[c]));       
	elements[c].possibleValues={}; // reset list of possible values
	
	// Backup every item
	if (typeof elements[c].optionsBackup == 'undefined') {
	    elements[c].optionsBackup=[];
	    for (var optNum=0; optNum < elements[c].options.length; optNum++) {
		elements[c].optionsBackup.push(elements[c].options[optNum]);
	    }
	} else { // Restore all options
	    for (var optNum=0; optNum < elements[c].optionsBackup.length; optNum++) {
		elements[c].options[optNum]=elements[c].optionsBackup[optNum];
	    }
	}
    }

    // Find possible relations
    for (var relNum=0; relNum < rels.length; relNum++) { // for every relation
	var can=0;
	for(var elemNum=0; elemNum < elements.length; elemNum++) { // every select box
	    if (elements[elemNum].id == chooseFromBoxId || elements[elemNum].value == '' || elements[elemNum].value == rels[relNum][elemNum]) { // Possible combination	    
		can++;
	    } else { // Impossible combination
		break;
	    }
	}
	if (can == elements.length) { // Possible relation
	    for(var elemNum=0; elemNum < elements.length; elemNum++) { // every select box
		elements[elemNum].possibleValues['x'+rels[relNum][elemNum]]=true;
	    }
	}
    }

    // Remove hidden things    
    for(var elemNum=0; elemNum < elements.length; elemNum++) {
	// if (chooseFromBoxId && elements[elemNum].id != chooseFromBoxId) continue;
	for (var optNum=elements[elemNum].options.length - 1; optNum >= 0 ; optNum--) {
	    if (elements[elemNum].options[optNum].value && typeof elements[elemNum].possibleValues['x'+elements[elemNum].options[optNum].value] == 'undefined') {
		elements[elemNum].options[optNum]=null;
	    }
	}
    }
}

// Init the Relations
// initTaRels(['s1', 's2', 's3'], [[1, 1, 8], [1, 5, 7], [2, 5, 9], [3, 5, 7]]); 






///////////////////////////////////////////////////////
// by sergey                                         //
// 						     //
// refer to http://wiki.project.cvs/Cascading_Select //
///////////////////////////////////////////////////////

//////////////////////////////////////////////////////////
// MSIE6 requires all OPTIONS to have @value attribute! //
//////////////////////////////////////////////////////////
// If the @value is not used then SELECTBOX.value is empty string.
// There is only SELECTBOX.text available but it is difficult to
// distinguish if the @value is empty or simply not set. We need to
// check the OPTION.hasAttribute('value') ... but it is simply better to
// have value all the time. (Maybe in the future I will change it if it
// causes problms.

/**
 * This class must be instantiated in order to have relations work.
 * It hooks the CascadeSelector::filter() on "change" event of the select boxes.
 *
 * Constructor
 * @param array ids Array of SELECT box' IDs
 * @param array rels Array ordered list of all possible item value combinations
 * @example new CascadeSelector(['s1', 's2', 's3'], [[1, 1, 1], [1, 1, 2], [1, 2, 2], [2, 1, 1]]);
 */
function CascadeSelector(selectorIds, relations) {
	// Selector instances
	this.selectors = [];
	// Element ID => Index map
	this.selectorIndexes = {};
	// all options pool
	this.pool = [];

	function filter(selectorId) {
		var selectorIndex = this.selectorIndexes[selectorId];


		for (var i = selectorIndex+1; i < this.selectors.length; i++) {
			var setIndex = 0;
			var savedVal = this.selectors[i].value;
			this.selectors[i].selectedIndex = -1;
			this.selectors[i].options.length = 0;
			
			var cnt = 0;
			for (var k = 0; k < this.pool[i].length; k++) {
				if (this.pool[i][k].value == '' || this.pool[i][k].IsCascadeParent[this.selectors[i-1].value]) {
					this.selectors[i].options[cnt++] = this.pool[i][k];
					if (this.pool[i][k].value == savedVal) {
						setIndex = cnt - 1;
					}

				}
			}
			/* Safari workaround */
			this.selectors[i].selectedIndex = setIndex;

		}


	}


	for (var i = 0; i < selectorIds.length; i++) {
		// get selector
		var sel = document.getElementById(selectorIds[i]);
		if (!sel) { alert('Missing '+selectorIds[i]+' selector!'); return; }

		// Bind to casacade selector instance
		sel.CascadeSelector = this;
		this.selectors.push(sel);
		this.selectorIndexes[sel.id] = this.selectors.length - 1;
		this.pool.push([]);
		
		// this code puts all options to the option pool
		// and resolves immediate parent ids from relations
		for (var k = 0; k < sel.options.length; k++) {
			var opt = sel.options[k];

			opt.IsCascadeParent = {};
			// first selector (index 0) cannot have cascade parents.
			if (i>0) {
				for (var j = 0; j < relations.length; j++) {
					if (relations[j][i] == opt.value) {
						opt.IsCascadeParent[relations[j][i-1]] = 1;
					}
				}
			}

			this.pool[i].push(opt);
		}

		sel.onchange=function() {
			this.CascadeSelector.filter(this.id);
		}

	}


	this.filter = filter;

	this.filter(this.selectors[0].id);
}

