/** 
 * @class LinkedListbox
 * @package LinkedListbox
 * @version 1.1
 * @author Frédéric LECOINTRE<frederic.lecointre@burnweb.net>
 * 
 */
LinkedListbox = function(oSetup){
	
	function _default(name, defaultValue){
		if(typeof oSetup[name] == "undefined"){
			oSetup[name] = defaultValue;
		}//end if
	};
	
	_default('listener', null);
	
	if(!oSetup['listBoxId'] || !oSetup['leftListboxId'] || !oSetup['rightListboxId']){
		throw Error('LinkedListBox::construct(): Missing fields in setup object!');
		return null;
	}//end if
	
	this.id = oSetup.listBoxId;
	this.setup = oSetup;
	this.buttons = {'left': oSetup.leftButtonId, 'right': oSetup.rightButtonId}
	this.left = new ListBox(oSetup.leftListboxId, this);
	this.right = new ListBox(oSetup.rightListboxId, this);
	
	this.captionId = oSetup.listBoxId+"Caption";
	
	this.leftFilterMethod = null;
	this.rightFilterMethod = null;
	
	if(oSetup['leftFilterMethod']){
		this.leftFilterMethod = oSetup['leftFilterMethod'];
	}//end if
	
	if(oSetup['rightFilterMethod']){
		this.rightFilterMethod = oSetup['rightFilterMethod'];
	}//end if
	
	this.threaded = true;
	
}//end function

/**
 *
 * @return void
 */
LinkedListbox.prototype.itemsToLeft = function(bThread){
	
	if(this.threaded){
	
		if(!bThread){
			ModalFrame.waitAndCallback(Array(this, 'itemsToLeft'), 'Traitement en cours ...', 100);
			return;
		}//end if
		
	}//end if


	var i, aItem;
	var aRights = this.right.getSelectedItems();
	
	if(this.setup.listener && this.setup.listener.beforeMoveLeft && aRights.length > 0){
		aRights = this.setup.listener.beforeMoveLeft(aRights, this);
	}//end if	
	
	if(aRights.length && aRights.length > 0){

		for(i in aRights){
			aItem = this.right.getItem(aRights[i]);
			this.left.addItem(aItem[0], aItem[1]);
			this.right.removeItem(aItem[0]);
		}//end for
		
		this.left.unselectAllDom();
		this.right.unselectAllDom();
		
		this.left.sort();
		
		aItem = this.right.getItemAt(0);
		if(aItem != undefined){
			this.right.selectDom(aItem[0]);
		}//end if
		
		if(this.setup.listener && this.setup.listener.afterMoveLeft){
			this.setup.listener.afterMoveLeft(aRights, this);
		}//end if
		

	}//end if
	
	if(this.threaded){
		ModalFrame.stopWait();
	}//end if
	
}//end function

/**
 *
 * @return void
 */
LinkedListbox.prototype.itemsToRight = function(bThread){
	
	if(this.threaded){
	
		if(!bThread){
			ModalFrame.waitAndCallback(Array(this, 'itemsToRight'), 'Traitement en cours ...', 100);
			return;
		}//end if
		
	}//end if

	var i, aItem;
	var aLefts = this.left.getSelectedItems();
	
	if(this.setup.listener && this.setup.listener.beforeMoveRight && aLefts.length > 0){
		aLefts = this.setup.listener.beforeMoveRight(aLefts, this);
	}//end if
	
	if(aLefts.length > 0){
	
		for(i in aLefts){
			aItem = this.left.getItem(aLefts[i]);
			this.right.addItem(aItem[0], aItem[1]);
			this.left.removeItem(aItem[0]);
		}//end for
		
		this.left.unselectAllDom();
		this.right.unselectAllDom();
		
		this.right.sort();
		
		aItem = this.left.getItemAt(0);
		if(aItem != undefined){
			this.left.selectDom(aItem[0]);
		}//end if
		
		if(this.setup.listener && this.setup.listener.afterMoveRight){
			this.setup.listener.afterMoveRight(aLefts, this);
		}//end if
		
	}//end if
	
	if(this.threaded){
		ModalFrame.stopWait();
	}//end if
	
}//end function

LinkedListbox.prototype.filterLeft = function(bThread){
	
	if(this.threaded){
	
		if(!bThread){
			ModalFrame.waitAndCallback(Array(this, 'filterLeft'), 'Traitement en cours ...', 100);
			return;
		}//end if
		
	}//end if

	sSearch = elem(this.id + 'LeftFilter').value;
	oResult = this.leftFilterMethod(sSearch);
	this.left.clean(true);
	
	for(var i in oResult){
		this.left.addItem(i, oResult[i]);
	}//end for
	
	this.left.sort();
	
	if(this.threaded){
		ModalFrame.stopWait();
	}//end if

}//end function

LinkedListbox.prototype.filterRight = function(bThread){
	
	if(this.threaded){
	
		if(!bThread){
			ModalFrame.waitAndCallback(Array(this, 'filterRight'), 'Traitement en cours ...', 100);
			return;
		}//end if
		
	}//end if

	sSearch = elem(this.id + 'RightFilter').value;
	oResult = this.rightFilterMethod(sSearch);
	this.right.clean(true);
	
	for(var i in oResult){
		this.right.addItem(i, oResult[i]);
	}//end for
	
	this.right.sort();
	
	if(this.threaded){
		ModalFrame.stopWait();
	}//end if

}//end function

/**
 *
 * @return void
 */
LinkedListbox.prototype.onfocusListBox = function(oDobj){

	if(oDobj.id == this.left.dObj.id){
		this.right.unselectAllDom();
	}//end if
	else if(oDobj.id == this.right.dObj.id){
		this.left.unselectAllDom();
	}//end if
	else{
	
	}//end else
	
}//end function

/**
 *
 * @return void
 */
LinkedListbox.prototype.initialize = function(){

if(this.buttons['left'] != null) {
	window.document.getElementById(this.buttons['left']).controller = this;
	window.document.getElementById(this.buttons['left']).onclick = function(){ this.controller.itemsToLeft()};
}//End if

if(this.buttons['right'] != null) {	
	window.document.getElementById(this.buttons['right']).controller = this;
	window.document.getElementById(this.buttons['right']).onclick = function(){ this.controller.itemsToRight()};
}//End if
	
	this.left.initialize();
	this.right.initialize();
	
}//end function

/**
 *
 * @param  String sChaine
 * @return void
 */
LinkedListbox.prototype.setCaption = function(sChaine){	
	
	// Attetntion c'est une méthode de librairie tout le monde ne souhaite pas affiher la chaine nombre de résultats !!
	// Il faut donc attendre en paramètre la chaine complete à afficher.

	var oCaption = document.getElementById(this.captionId);
	
	if(oCaption.firstChild){
		var sCaption = oCaption.firstChild.nodeValue;
		iLengthCaption = sCaption.length;
		oCaption.firstChild.replaceData(0, iLengthCaption, sChaine);	
	}else{
		var sText = document.createTextNode(sChaine);
		oCaption.appendChild(sText);
	}//end else
	
}//end function

/** 
 * @class ListBox
 * @package LinkedListbox
 * @version 1.1
 * @author: Frédéric LECOINTRE<frederic.lecointre@burnweb.net>
 * 
 */
ListBox = function(sId, oParent){
	this.items = Array();
	this.dObj = null;
	this.id = sId;
	this.parent = oParent;
}//end function

ListBox.LIST_ID 	= 1;
ListBox.LIST_VALUES	= 0x2;
ListBox.LIST_ALL	= 0x4;

/**
 *
 * @param string sValue
 * @param string sText
 * @return void
 */
ListBox.prototype.addItem = function(sValue, sText){

	if(this.items[sValue] == undefined){
		this.items[sValue] = sText;
		this.appendDom(sValue);
	}//end if
	
}//end function

/**
 *
 * @param string sValue
 * @return array
 */
ListBox.prototype.getItem = function(sValue){
	if(this.items[sValue] != undefined){
		return Array(sValue, this.items[sValue]);
	}//end if
}//end function

/**
 *
 * @param integer iIndex
 * @return array
 */
ListBox.prototype.getItemAt = function(iIndex){
	var sValue, i = 0;
	
	for (sValue in this.items){
		if(this.items[sValue] != undefined){
			if(i == iIndex){
				return Array(sValue, this.items[sValue]);
			}//end if
			else{
				i++;
			}//end else
			
		}//end if

	}//end for
		
	return undefined;
	
}//end function

/**
 *
 * @param string sValue
 * @return void
 */
ListBox.prototype.removeItem = function(sValue){
	if(this.items[sValue] != undefined){
		this.removeDom(sValue);
		this.items[sValue] = undefined;
	}//end if
}//end function

/**
 *
 * @return void
 */
ListBox.prototype.countItems = function(){
	var i = 0;
	
	for (sValue in this.items){
		if(this.items[sValue] != undefined){
			i++;
		}//end if
	}//end for
	
	return i;
	
}//end function

/**
 *
 * @param integer iBehaviour
 * @return void
 */
ListBox.prototype.listItems = function(iBehaviour){

	if(iBehaviour == undefined || iBehaviour == null){
		iBehaviour = ListBox.LIST_ALL;
	}//end if
	
	var aReturn = Array();
	
	for (sValue in this.items){
		if(this.items[sValue] != undefined){
		
			switch(iBehaviour){
			
				case ListBox.LIST_ID:
					aReturn[aReturn.length] = sValue;
				break;
				
				case ListBox.LIST_VALUES:
					aReturn[aReturn.length] = this.items[sValue];
				break;
				
				case ListBox.LIST_ALL:
					aReturn[aReturn.length] = Array(sValue, this.items[sValue]);
				break;
				
			}//end switch

		}//end if
	}//end for
	
	return aReturn;
	
}//end function

/**
 *
 * @return void
 */
ListBox.prototype.initialize = function(){
	
	this.dObj = window.document.getElementById(this.id);
	var aOptions = this.dObj.getElementsByTagName('option');
	
	for (i = 0; i < aOptions.length; i++){
		this.addItem(aOptions[i].value, aOptions[i].text);
	}//end for
	
	this.clean();
	this.populate();
	
	this.dObj.controller = this.parent;
	this.dObj.onfocus = function(){this.controller.onfocusListBox(this);};
	
}//end function

/**
 *
 * @return void
 */
ListBox.prototype.clean = function(bCleanItems){
	
	if(this.dObj){
	
		var aOptions = this.dObj.getElementsByTagName('option');
		
		while (aOptions.length > 0){
			this.dObj.remove(aOptions.length -1);
		}//end for
		
	}//end if
	
	if(bCleanItems){
		this.items = Array();
	}//end if
		
}//end function

/**
 *
 * @return void
 */
ListBox.prototype.cleanAll = function(){
	
	if(this.dObj){
	
		var aOptions = this.dObj.getElementsByTagName('option');
		
		for (i = 0; i < aOptions.length; i++){
            if(aOptions[i].value != undefined){
                this.items[aOptions[i].value] = undefined;
            }//end if
            
        }//end for
		
		while (aOptions.length > 0){
			this.dObj.remove(aOptions.length -1);
		}//end for
		
	}//end if

}//end function

/**
 *
 * @return void
 */
ListBox.prototype.populate = function(){

	if(this.dObj){
		var sId;
		this.clean();
		
		for (sValue in this.items){
			this.appendDom(sValue);
		}//end for
	}//end if
	
}//end function


/**
 *
 * @return void
 */
ListBox.prototype.sort = function(){

	if(this.dObj){
		var sId;
		this.clean();

		var aTemp = this.items;
		var aSorted = Array();
		var sId;
		
		for (sId in aTemp){
			if(sId != undefined && sId != null && aTemp[sId] != null && aTemp[sId] != undefined){
				aSorted[aSorted.length] = aTemp[sId].toLowerCase() + '-+-' + sId;
			}//end if
		}//end for
		
		aSorted.sort();
		this.items = Array();
		
		var iLast = 0;
		var iIndex = 0;
		
		for(iIndex in aSorted){
		
			iLast = String(aSorted[iIndex]).lastIndexOf('-+-');
			if(iLast >= 0){
				sId = String(aSorted[iIndex]).substr(iLast +3);
				this.items[sId] = aTemp[sId];
			}//end if
			
		}//end for
		
		for (sValue in this.items){
			this.appendDom(sValue);
		}//end for
	}//end if
	
}//end function

/**
 *
 * @param string sValue
 * @return void
 */
ListBox.prototype.appendDom = function(sValue){

	if(this.dObj && this.items[sValue] != undefined){
	
		var aOptions = this.dObj.getElementsByTagName('option');
		var oOption = document.createElement('option');
		oOption.text = this.items[sValue];
		oOption.value = sValue;
		oOption.title = oOption.text;
		
		if(document.all){
			this.dObj.add(oOption, aOptions.length);
		}//end if
		else{
			this.dObj.add(oOption, null);
		}//end else
		
	}//end if
	
}//end function

/**
 *
 * @param string sValue
 * @return void
 */
ListBox.prototype.removeDom = function(sValue){

	if(this.dObj && this.items[sValue] != undefined){
	
		var aOptions = this.dObj.getElementsByTagName('option');

		for (i = 0; i < aOptions.length; i++){
			if(aOptions[i].value == sValue){
				this.dObj.remove(i);
			}//end if
			
		}//end for
		
	}//end if
	
}//end function

/**
 *
 * @return array
 */
ListBox.prototype.getSelectedItems = function(){

	var aRetval = Array();
	
	if(this.dObj){
	
		var aOptions = this.dObj.getElementsByTagName('option');
		
		for (i = 0; i < aOptions.length; i++){
			
			if(aOptions[i].selected){
				aRetval[aRetval.length] = aOptions[i].value;
			}//end if
			
		}//end for
		 
	}//end if
	
	return aRetval;
	
}//end function

/**
 *
 * @param string sValue
 * @return void
 */
ListBox.prototype.selectDom = function(sValue){

	if(this.dObj){
	
		var aOptions = this.dObj.getElementsByTagName('option');
		
		for (i = 0; i < aOptions.length; i++){
			if(aOptions[i].value == sValue){
				aOptions[i].selected = true;
			}//end if
		}//end for
		
	}//end if
	
}//end function

/**
 *
 * @param string sFilter
 * @return void
 */
ListBox.prototype.selectMatchDom = function(sFilter){

	if(this.dObj){
	
		this.unselectAllDom();
		
		if(sFilter.length > 0){
			var aOptions = this.dObj.getElementsByTagName('option');
			var oReg = new RegExp('^' + sFilter + '.*');
			
			for (i = 0; i < aOptions.length; i++){
				if(oReg.test(aOptions[i].text)){
					aOptions[i].selected = true;
				}//end if
			}//end for		
		}//end if
		
	}//end if
	
}//end function

/**
 *
 * @param string sFilter
 * @return void
 */
ListBox.prototype.filterMatchDom = function(sFilter){

	if(this.dObj){
	
		this.clean();
		
		if(sFilter.length > 0){
		
			var oReg = new RegExp('^' + sFilter + '.*');
			
			for (sValue in this.items){
				if(oReg.test(this.items[sValue])){
					this.appendDom(sValue);
				}//end if
			}//end for

		}//end if
		else{
			this.populate();
		}//end else
		
	}//end if
	
}//end function

/**
 *
 * @param string sValue
 * @return void
 */
ListBox.prototype.selectAllDom = function(){

	if(this.dObj){
	
		var aOptions = this.dObj.getElementsByTagName('option');
		
		for (i = 0; i < aOptions.length; i++){
			aOptions[i].selected = true;
		}//end for
		
	}//end if
	
}//end function

/**
 *
 * @param string sValue
 * @return void
 */
ListBox.prototype.invertSelectionDom = function(){

	if(this.dObj){
	
		var aOptions = this.dObj.getElementsByTagName('option');
		
		for (i = 0; i < aOptions.length; i++){
			aOptions[i].selected = !aOptions[i].selected;
		}//end for
		
	}//end if
	
}//end function

/**
 *
 * @param string sValue
 * @return void
 */
ListBox.prototype.unselectDom = function(sValue){

	if(this.dObj){
	
		var aOptions = this.dObj.getElementsByTagName('option');
		
		for (i = 0; i < aOptions.length; i++){
			if(aOptions[i].value == sValue){
				aOptions[i].selected = false;
			}//end if
		}//end for
		
	}//end if
	
}//end function

/**
 *
 * @return void
 */
ListBox.prototype.unselectAllDom = function(){

	if(this.dObj){
	
		var aOptions = this.dObj.getElementsByTagName('option');
		
		for (i = 0; i < aOptions.length; i++){
			aOptions[i].selected = false;
		}//end for
		
	}//end if
	
}//end function