// @name	selectUtils
// @desc	an object containing utility functions for select box and multi-select operations
// @param 	srcField a fully referenced form element, i.e., document.main_form_main.mysrc
// @param 	destField a fully referenced form element, i.e., document.main_form_main.mydest
// @param 	spacer used for keeping the width of the form fields constant (defaults to a new Option object with 20 chars whitespace text and an empty value)
// @returns	void
function selectUtils(srcField,destField,spacer)
{
	this.srcField = srcField;
	this.destField = destField;
	this.spacer = spacer || new Option('                    ','');
	
	// @name	copy
	// @desc	copies selected options from one select box to another -- differs from paste in that it leaves the selected options in the source field as well as putting them in the destination
	// @param 	s fully referenced source form field (defaults to this.srcField property)
	// @param 	d fully referenced destination form field (defaults to this.destField property)
	// @returns	void
	this.copy = function(s,d)
	{
		src = s || this.srcField;
		dest = d || this.destField;
		this.moveFromTo(src, dest, 'copy');
	}

	// @name	paste
	// @desc	pastes selected options from one select box to another -- differs from copy in that it removes the options from the source field
	// @param 	s fully referenced source form field (defaults to this.srcField property)
	// @param 	d fully referenced destination form field (defaults to this.destField property)
	// @returns	void
	this.paste = function(s,d)
	{
		src = s || this.srcField;
		dest = d || this.destField;
		this.moveFromTo(src, dest, 'paste');
	}	

	// @name	copyAll
	// @desc	copies all selected options from field a to field b, and from field b to field a
	// @param 	s fully referenced source form field (defaults to this.srcField property)
	// @param 	d fully referenced destination form field (defaults to this.destField property)
	// @returns	void
	this.copyAll = function(s,d)
	{
		src = s || this.srcField;
		dest = d || this.destField;
		this.moveFromTo(dest, src, 'copy');
		this.moveFromTo(src, dest, 'copy');
	}

	// @name	pasteAll
	// @desc	pastes all selected options from field a to field b, and from field b to field a
	// @param 	s fully referenced source form field (defaults to this.srcField property)
	// @param 	d fully referenced destination form field (defaults to this.destField property)
	// @returns	void
	this.pasteAll = function(s,d)
	{
		src = s || this.srcField;
		dest = d || this.destField;
		this.moveFromTo(dest, src, 'paste');
		this.moveFromTo(src, dest, 'paste');
	}	

	// @name	setSelected
	// @desc	selects an option if that option's value matches the input value
	// @param 	fld the fully referenced select to be operated upon
	// @param 	val the value to be matched by an option's value if it is to be selected
	// @returns	void
	this.setSelected = function(fld,val)
	{
		for(i=0; i<fld.options.length; i++)
			if(fld.options[i].value == val)
				fld.options[i].selected = true;
	}	

	// @name	selectAll
	// @desc	selects all options within a select box if the value of that option is not empty
	// @param 	fld the fully referenced select to be operated upon
	// @returns	void
	this.selectAll = function(fld)
	{
		for(i=0; i<fld.options.length; i++)
			if(fld.options[i].value.length > 0)
				fld.options[i].selected = true;
	}	

	// @name	deSelectAll
	// @desc	deselects all options within a select box
	// @param 	fld the fully referenced select to be operated upon
	// @returns	void
	this.deSelectAll = function(fld)
	{
		for(i=0; i<fld.options.length; i++)
			fld.options[i].selected = false;
	}	

	// @name	removeAll
	// @desc	removes all options within a select box
	// @param 	fld the fully referenced select to be operated upon
	// @returns	void
	this.removeAll = function(fld)
	{
		for(i=fld.options.length; i>=0; i--)
			fld.options[i] = null;
	}	

	// @name	reorder
	// @desc	performs ordering logic for options within a select -- moves selected options up or down
	// @param 	dir the direction to move selected options -- 'up' or 'down' (defaults to 'up')
	// @param 	fld the fully referenced select to be operated upon
	// @returns	void
	this.reorder = function(dir,fld)
	{
		direction  = dir || 'up';
		field = fld || this.destField;

		this.removeSpacers(field);
		
		if(direction == 'up')
		{
			dirval = -1;
			for(i=1; i<field.options.length; i++)
			{
				if(field.options[i].selected && !field.options[i+dirval].selected)
				{
					this.swap(field.options[i+dirval], field.options[i]);
					field.options[i].selected = false;
					field.options[i+dirval].selected = true;
				}
			}
		}
		else
		{
			dirval = 1;
			for(i=field.options.length-2; i>=0; i--)
			{
				if(field.options[i].selected && !field.options[i+dirval].selected)
				{
					this.swap(field.options[i+dirval], field.options[i]);
					field.options[i].selected = false;
					field.options[i+dirval].selected = true;
				}
			}
		}
		
		this.addSpacers(field);
	}
	
	//private internal method
	this.moveFromTo = function(s,d,a)
	{
		src = s || this.srcField;
		dest = d || this.destField;
		action = a || 'paste';
		temp = [];
		
		this.removeSpacers(this.srcField);
		this.removeSpacers(this.destField);

		for(i=src.options.length-1; i>=0; i--)
		{
			inDest = false;
			if(src.options[i].selected)
			{
				for(j=dest.options.length-1; j>=0; j--)
				{
					if(src.options[i].value == dest.options[j].value)
					{
						inDest = true;
						break;
					}
				}
				for(k=temp.length-1; k>=0; k--)
				{
					if(src.options[i].value == temp[k].value)
					{
						inDest = true;
						break;
					}
				}
				if(!inDest)
					temp[temp.length] = new Option(src.options[i].text,src.options[i].value);
				if(action == 'paste')
					src.options[i] = null;
			}
		}
		for(m=temp.length-1; m>=0; m--)
		{
			dest.options[dest.options.length] = temp[m];
			if(action == 'paste')
				temp[m] = null;
		}
		
		this.addSpacers(src);
		this.addSpacers(dest);
	}

	//private internal method
	this.removeSpacers = function(fld)
	{
		for(i=fld.options.length-1; i>=0; i--)
			if(fld.options[i] != null && (fld.options[i].value.length == 0 || fld.options[i].value == -1))
				fld.options[i] = null;
	}
	
	//private internal method
	this.addSpacers = function(fld)
	{
		fld.options[fld.options.length] = new Option(this.spacer.text,this.spacer.value);
	}
	
	//private internal method
	this.swap = function(o1,o2)
	{
		tempOption = new Option(o1.text,o1.value)
		o1.text = o2.text;
		o1.value = o2.value;
		o2.text = tempOption.text;
		o2.value = tempOption.value;
		tempOption = null;
	}
	
	//private internal method
	this.init = function()
	{
		if(this.srcField != null)
		{
			this.removeSpacers(this.srcField);
			this.addSpacers(this.srcField);
		}
		if(this.destField != null)
		{
			this.removeSpacers(this.destField);
			this.addSpacers(this.destField);
		}
	}

	//call the initialization routine to work with more function-friendly spacer options
	this.init();
}			
