/**
 * Método construtor do HTMLDualList. Responsável por criar o componente Lista Dupla.
 * @param sys - Indica o código do sistema.
 * @param formID - Indica o código do formulário.
 * @param posX - Posição do componente na tela em relação ao eixo X.
 * @param posY - Posição do componente na tela em relação ao eixo Y.
 * @param width - Largura do componente.
 * @param heigth - ALtura do componente.
 * @param descriptionLeft - Descricao dos itens do lado esquerdo (PRINCIPAL).
 * @param descriptionRighh - Descricao dos itens do lado direito (SELECIONADOS).
 * @param labels - Array com os valores do campo LISTA do Select PRINCIPAL.
 * @param values - Array com os valores do campo CHAVE do Select PRINCIPAL.
 * @param labelsRIGHT - Array com os valores do campo LISTA do Select SELECIONADOS.
 * @param valuesRIGHT - Array com os valores do campo LISTA do Select SELECIONADOS.
 * @param duploClicar - TRUE se o evento 'Duplo Clicar' será criado.
 * @param btAddItem - TRUE se o evento 'Antes/Depois de Adicionar Item' será criado.
 * @param btAddAll - TRUE se o evento 'Antes/Depois de Adicionar Todos' será criado.
 * @param btRemItem - TRUE se o evento 'Antes/Depois de Remover Item' será criado.
 * @param btRemAll - TRUE se o evento 'Antes/Depois de Remover Todos' será criado.
 **/
function HTMLDualList(sys, formID, code, posX, posY, width, height,
		descriptionLeft, descriptionRight, labels, values, labelsRIGHT,
		valuesRIGHT, duploClicar, btAddItem, btAddAll, btRemItem, btRemAll) {
	this.create(sys, formID, code, posX, posY, width, height, descriptionLeft,
			descriptionRight, labels, values, labelsRIGHT, valuesRIGHT,
			duploClicar, btAddItem, btAddAll, btRemItem, btRemAll);

	this.labels = labels;
	this.values = values;
	if (!this.values)
		this.values = this.labels;

	this.labelsRIGHT = labelsRIGHT;
	this.valuesRIGHT = valuesRIGHT;
	if (!this.valuesRIGHT)
		this.valuesRIGHT = this.labelsRIGHT;

	this.descPrincipal = descriptionLeft;
	this.descSelecionados = descriptionRight;
	this.duploClicar = duploClicar;
	this.btAddItem = btAddItem;
	this.btAddAll = btAddAll;
	this.btRemItem = btRemItem;
	this.btRemAll = btRemAll;
}

/**
 * Propriedades do componente HTMLDualList.
 **/
HTMLDualList.inherits(HTMLElementBase);
HTMLDualList.prototype.name = 'HTMLDualList';
HTMLDualList.prototype.tabable = true;
HTMLDualList.prototype.tagName = 'duallist';
HTMLDualList.prototype.zIndex = 301;

/**
 * Retorna o Select (objeto HTMLSelect) da Esquerda com seus itens.
 * @return Select (objeto HTMLSelect) da Esquerda.
 **/
HTMLDualList.prototype.fieldsLEFT = function() {
	return this.leftSelect;
}

/**
 * Retorna o Select (objeto HTMLSelect) da Direita com seus itens.
 * @return Select (objeto HTMLSelect) da Direita.
 **/
HTMLDualList.prototype.fieldsRIGHT = function() {
	return this.rightSelect;
}

/**
 * Move todos os itens de um Select (objeto HTMLSelect) da lista dupla para o outro.
 * @param target
 * @param event
 * @param side Indica o lado que os itens estão.
 * Caso seja LEFT os itens serão movidos do objeto HTMLSelect do lado LEFT para o lado RIGTH e virse-versa.
 **/
HTMLDualList.prototype.moveAllOptions = function(target, event, side, param) {
  if (!this.visible || !this.enabled || this.readonly) {
    return; 
  }
  
	var selectIN;
	var selectOUT;

	var arrElements = new Array();

	if (side == "LEFT") {
		selectIN = this.leftSelect;
		selectOUT = this.rightSelect;
	} else {
		selectIN = this.rightSelect;
		selectOUT = this.leftSelect;
	}

	if (selectIN.options.length > 0) {
		for (var i = 0; i < selectIN.options.length; i++) {
			var text = selectIN.options[i].text;
			var value = selectIN.options[i].value;

			var arrCurrentElement = new Array();
			arrCurrentElement[0] = i;
			arrCurrentElement[1] = value;
			arrCurrentElement[2] = text;

			arrElements.push(arrCurrentElement);
		}
	}

  // Como o elemento removido diminui a posição dos segunites a serem removidos,
  // foi criada essa variável para controlar o índice.
  var auxiliar = 0;
	for (var i = 0; i <= arrElements.length - 1; i++) {
		var element = arrElements[i];
		var index = element[0];
		var value = element[1];
		var text = element[2]
		if (this.includeOption(selectOUT, value, text, param)) {
			this.deleteOption(selectIN, index - auxiliar);
			auxiliar++;
		}
	}
}

/**
 * Move um item (objeto HTMLOption) de um Select (objeto HTMLSelect) da lista dupla para o outro.
 * @param target
 * @param event
 * @param side Indica o lado que os itens estão.
 * Caso seja LEFT o item será movido do lado LEFT do objeto HTMLSelect para o lado RIGTH e virse-versa.
 **/
HTMLDualList.prototype.moveOption = function(target, event, side, param) {
	if (!this.visible || !this.enabled || this.readonly) {		
    return; 
  }
  
  var selectIN;
	var selectOUT;

	var arrElements = new Array();

	if (side == "LEFT") {
		selectIN = this.leftSelect;
		selectOUT = this.rightSelect;
	} else {
		selectIN = this.rightSelect;
		selectOUT = this.leftSelect;
	}

	for (var i = 0; i < selectIN.options.length; i++) {
		if (selectIN.options[i].selected) {
			var text = selectIN.options[i].text;
			var value = selectIN.options[i].value;

			var arrCurrentElement = new Array();
			arrCurrentElement[0] = i;
			arrCurrentElement[1] = value;
			arrCurrentElement[2] = text;
			arrElements.push(arrCurrentElement);
		}
	}

	// Como o elemento removido diminui a posição dos segunites a serem removidos,
	// foi criada essa variável para controlar o índice.
	var auxiliar = 0;
	for (var i = 0; i < arrElements.length; i++) {
		var element = arrElements[i];
		var index = element[0];
		var value = element[1];
		var text = element[2];

		var canContinue = this.includeOption(selectOUT, value, text, param);
		if (canContinue) {
			this.deleteOption(selectIN, index - auxiliar);
			auxiliar++;
		}
	}
}

/**
 * Retorna LEFT caso seja passado RIGTH como parâmetro ou virse-versa.
 * @param Indica o lado (LEFT ou RIGTH) do objeto HTMLSelect da lista dupla.
 * @return LEFT ou RIGTH dependendo do valor passado como parâmetro.
 **/
HTMLDualList.prototype.invertSide = function(side) {
	if (side == "LEFT") {
		side = "RIGHT";
	} else {
		side = "LEFT";
	}
	return side;
}

/**
 * Inclui o item (objeto HTMLOption) passado como parâmetro em um Select (objeto HTMLSelect) da lista dupla.
 * @param select Indica o Select (objeto HTMLSelect) em que o item será incluido.
 * @param value Indica o valor da propriedade VALUE do item que será incluído.
 * @param text Indica o valor da propriedade TEXT do item que será incluído.
 * @return status Retorna TRUE se o item for adicionado com sucesso e FALSE se n for possível adicionar o item.
 **/
HTMLDualList.prototype.includeOption = function(select, value, text, param) {
	document.hasRuleException = false;
	var side = this.invertSide(select.getAttribute("SIDE"));
	var status = false;

	if (param == "double") {
		this.invokeEventsDoubleClick(value, text);
		if (!document.hasRuleException) {
			this.addItem(select, value, text);
			status = true;
		}
	} else {
		if (side == "LEFT") {
			// ADD item.
			this.invokeEventsBeforeAdd(value, text, param);
			// if (!document.hasRuleErrors){
			if (!document.hasRuleException) {
				this.addItem(select, value, text);
				status = true;
			}
			this.invokeEventsAfterAdd(value, text, param);
		} else {
			// REMOVE item.
			this.invokeEventsBeforeRem(value, text, param);
			if (!document.hasRuleException) {
				this.addItem(select, value, text);
				status = true;
			}
			this.invokeEventsAfterRem(value, text, param);
		}
	}
	return status;
}

/**
 * Cria e adiciona um item (objeto HTMLOption) em um Select (objeto HTMLSelect) da lista dupla.
 * @param select Indica o Select (objeto HTMLSelect) em que o item será incluido.
 * @param value Indica o valor da propriedade VALUE do item que será incluído.
 * @param text Indica o valor da propriedade TEXT do item que será incluído.
 **/
HTMLDualList.prototype.addItem = function(select, value, text) {
	var side = select.getAttribute("SIDE");
	var option = this.createOption(value, text, side);
	var length = select.options.length;
	select.options[length] = option;
	this.inputOption(value, this.invertSide(side));
}

/**
 * Recebe como parâmetro um valor e um ARRAY e verifica se no mesmo contém o valor.
 * @return Retorna TRUE se o array contém o valor, caso contrário FALSE.
 **/
HTMLDualList.prototype.contains = function(array, value) {
	return arrayIndexOf(array, value) >= 0;
}

HTMLDualList.prototype.getInputValue = function(array) {
	var first = true;
	var inputValue = "";

	if (array != null && array.length > 0) {
		for (index = 0; index < array.length; index++) {
			var value = array[index];
			if (first) {
				inputValue = value;
				first = false;
			} else {
				inputValue += ("|" + value);
			}
		}
	}
	return inputValue;
}

/**
 * Armazena em um dois ARRAYS os itens que serão INCLUÍDOS ou DELETADOS da Lista Dupla.
 * @param value Indica o valor da propriedade VALUE do item (objeto HTMLOption).
 * @param side Caso seja igual a LEFT o VALUE do item (objeto HTMLOption) será adicionado ao ARRAY que armazena os valores que serão DELETADOS.
 * Caso contrário o VALUE do item será adicionado ao ARRAY que armazena os valores que serão INCLUÍDOS.
 **/
HTMLDualList.prototype.inputOption = function(value, side) {
	// Adicionando
	if (side == "LEFT") {
		if (this.contains(this.elementsToRemove, value)) {
			arrayRemove(this.elementsToRemove, value);
		} else {
			this.elementsToAdd.push(value);
		}
	} else {
		if (this.contains(this.elementsToAdd, value)) {
			arrayRemove(this.elementsToAdd, value);
		} else {
			this.elementsToRemove.push(value);
		}
	}

	this.inputInclude.value = this.getInputValue(this.elementsToAdd);
	this.inputDelete.value = this.getInputValue(this.elementsToRemove);
}

HTMLDualList.prototype.deleteOption = function(select, index) {
	// Remove item.
	if (select.options.length > 0) {
		value = select.options[index].value;
		text = select.options[index].text;
		select.options[index] = null;

		/*
		Código antigo
		for (var i = 0; i <= array.length - 1; i++) {
			var element = array[i];
			if ((value == element[1]) && (text == element[2])) {
				select.options[index] = null;
				break;
			}
		}*/
	}
}

/**
 * Responsável por desenhar na tela o HTML do componente Lista Dupla.
 * @param doc - documento onde o componente será inserido.
 **/
HTMLDualList.prototype.designComponent = function(doc) {
	this.elementsToAdd = new Array();
	this.elementsToRemove = new Array();

	this.duallist = document.createElement("div");
	this.duallist.id = 'duallistLayer';
	this.duallist.name = 'duallistLayer';
	this.duallist.style.width = this.width;
	this.duallist.style.height = this.height;
	this.duallist.style.left = this.posX;
	this.duallist.style.top = this.posY;
	this.duallist.style.position = 'absolute';
	this.duallist.style.zIndex = this.zIndex;
	this.duallist.style.backgroundColor = this.bgColor;
	this.duallist.className = 'duallist';

	var table;
	table = '<table border="0" cellspacing="0" cellpadding="0" align="center" width="100%" height="100%"><tr><td align="center" valign="middle">';
	table += '<table border="0" cellspacing="0" cellpadding="0" align="center">';
	table += '<tr>';
	table += '<td width="5%"></td>'
	table += '<td width="42%" id="celDescPrincipal" valign="BOTTOM">' + this.descPrincipal + '</td>';
	table += '<td width="6%" valign="middle" align="center">';
	table += '<td width="42%" id="celDescSelecionados" valign="BOTTOM">' + this.descSelecionados + '</td>';
	table += '<td width="5%"></td>'
	table += '</tr>';
	table += '<tr>';
	table += '<td width="5%"></td>';
	table += '<td id="cel_WFRComponentLEFT' + this.code + '" valign="top" align="center"></td>';
	table += '<td valign="middle" align="center">';
	table += '<table cellspacing="5" cellpadding="0" border="0">';
	table += '<tr>';
	table += '<td id="btAddOption' + this.code + '" valign="middle" align="center"></td>';
	table += '</tr>';
	table += '<tr>';
	table += '<td id="btAddAllOptions' + this.code + '" valign="middle" align="center"></td>';
	table += '</tr>';
	table += '<tr>';
	table += '<td id="btRemAllOptions' + this.code + '" valign="middle" align="center"></td>';
	table += '</tr>';
	table += '<tr>';
	table += '<td id="btRemOption' + this.code + '" valign="middle" align="center"></td>';
	table += '</tr>';
	table += '</table>';
	table += '</td>';
	table += '<td id="cel_WFRComponentRIGHT' + this.code + '" valign="top" align="center"></td>';
	table += '<td width="5%"></td>';
	table += '</tr>';
	table += '</table>';
	table += '</td></tr></table>';

	this.duallist.innerHTML = table;
	doc.appendChild(this.duallist);

	// WFRInput
	this.inputInclude = document.createElement("input");
	this.inputInclude.setAttribute("type", "hidden");
	this.inputInclude.id = "WFRInputInclude" + this.code;
	this.inputInclude.name = "WFRInputInclude" + this.code;
	doc.appendChild(this.inputInclude);

	this.inputDelete = document.createElement("input");
	this.inputDelete.setAttribute("type", "hidden");
	this.inputDelete.id = "WFRInputDelete" + this.code;
	this.inputDelete.name = "WFRInputDelete" + this.code;
	doc.appendChild(this.inputDelete);

  // Scroll
  this.divWFRComponentRIGHT = document.createElement("div");
  this.divWFRComponentRIGHT.id = 'WFRComponentRIGHT' + this.code;
  this.divWFRComponentRIGHT.name = 'WFRComponentRIGHT' + this.code;
  //this.divWFRComponentRIGHT.style.overflow = "hidden";
  this.divWFRComponentRIGHT.style.width = ((this.width*42)/100);
  this.divWFRComponentRIGHT.style.height = ((this.height*80)/100);
  $("cel_WFRComponentRIGHT" + this.code).appendChild(this.divWFRComponentRIGHT);

  this.divWFRComponentLEFT = document.createElement("div");
  this.divWFRComponentLEFT.id = 'WFRComponentLEFT' + this.code;
  this.divWFRComponentLEFT.name = 'WFRComponentLEFT' + this.code;
  //this.divWFRComponentLEFT.style.overflow = "hidden";
  this.divWFRComponentLEFT.style.width = ((this.width*42)/100);
  this.divWFRComponentLEFT.style.height = ((this.height*80)/100);
  $("cel_WFRComponentLEFT" + this.code).appendChild(this.divWFRComponentLEFT);

  //this.attachEvent(this.divWFRComponentRIGHT, 'scroll', this.OnDivScroll, this, "RIGHT");
  //this.attachEvent(this.divWFRComponentLEFT, 'scroll', this.OnDivScroll, this, "LEFT");

	// Select
	this.leftSelect = this.createSelect("LEFT");
	this.setOptions(this.leftSelect, this.labels, this.values);
	$("WFRComponentLEFT" + this.code).appendChild(this.leftSelect);

	this.rightSelect = this.createSelect("RIGHT");
	this.setOptions(this.rightSelect, this.labelsRIGHT, this.valuesRIGHT);
	$("WFRComponentRIGHT" + this.code).appendChild(this.rightSelect);

	// Botões
	var addOption = document.getElementById("btAddOption" + this.code);
	var imgAddOption = this.createImageButton(skin + "dl_arrow_go.gif", "16",
			"16", this.btAddItem, this.moveOption, "LEFT", "item",
			getLocaleMessage("LABEL.ADD_ITEM"));
	addOption.appendChild(imgAddOption);

	var addAllOptions = document.getElementById("btAddAllOptions" + this.code);
	var imgAddAllOptions = this.createImageButton(skin + "dl_arrow_go_m.gif",
			"16", "16", this.btAddAll, this.moveAllOptions, "LEFT", "all",
			getLocaleMessage("LABEL.ADD_ALL"));
	addAllOptions.appendChild(imgAddAllOptions);

	var remAllOptions = document.getElementById("btRemAllOptions" + this.code);
	var imgRemAllOptions = this.createImageButton(skin + "dl_arrow_back_m.gif",
			"16", "16", this.btRemAll, this.moveAllOptions, "RIGHT", "all",
			getLocaleMessage("LABEL.REMOVE_ALL"));
	remAllOptions.appendChild(imgRemAllOptions);

	var remOption = document.getElementById("btRemOption" + this.code);
	var imgRemOption = this.createImageButton(skin + "dl_arrow_back.gif", "16",
			"16", this.btRemItem, this.moveOption, "RIGHT", "item",
			getLocaleMessage("LABEL.REMOVE_ITEM"));
	remOption.appendChild(imgRemOption);
}

/**
 * @deprecated
 **/
HTMLDualList.prototype.OnDivScroll = function(target, select, params) {
  var side = params;
  var lstCollegeNames = document.getElementById("WFRInput" + side + this.code);

  if (lstCollegeNames.options.length > 10)
  {
    lstCollegeNames.size=lstCollegeNames.options.length;
  }
  else
  {
    lstCollegeNames.size=10;
  }
}

/**
 * @deprecated
 **/
HTMLDualList.prototype.OnSelectFocus = function(target, select, params) {
  var side = params;
  if (document.getElementById("WFRInput" + side + this.code).scrollLeft != 0)
  {
    document.getElementById("WFRInput" + side + this.code).scrollLeft = 0;
  }

  var lstCollegeNames = document.getElementById("WFRInput" + side + this.code);
  if( lstCollegeNames.options.length > 10)
  {
    if (side == "LEFT"){
      this.onFocus(this, this.leftSelect);
    }else{
      this.onFocus(this, this.rightSelect);
    }
    lstCollegeNames.size=10;
  }
}

/**
 * Responsável por criar os Select's (objeto HTMLSelect) da lista dupla.
 * @param side Indica o lado do Select. LEFT ou RIGTH.
 * @return select objeto HTMLSelect.
 **/
HTMLDualList.prototype.createSelect = function(side) {
	var select = null;
	var selectId = "WFRInput" + side + this.code;
	if (IE) {
		select = document.createElement("<select "
				+ (this.readonly ? "readonly" : "") + ">");
	} else {
		try {
		  select = document.createElement("<select>");
		  if (this.readonly) {
			select.setAttribute('readonly', 'readonly');
		  }
		} catch(e) {
			var myDiv = document.createElement("DIV");
		    myDiv.innerHTML = "<select id='"+ selectId +"'></select>";
		  
			document.body.appendChild(myDiv)
			select = document.getElementById(selectId);
			document.body.removeChild(myDiv);
		}
	}

	select.id = selectId;
	select.name = selectId;
	select.size = 10;
	select.style.width = "100%";
	select.style.height = "100%";
	select.setAttribute("SIDE", side);
	select.setAttribute("multiple", "multiple");
	select.setAttribute("class", "duallist");

	// Decoration
	this.setDecorationObject(select);
	this.setDecorationLabelPrincipal(document.getElementById("celDescPrincipal"));
	this.setDecorationLabelSelecionados(document.getElementById("celDescSelecionados"));

	// Events
	if (this.duploClicar) { // Duplo Click
		this.attachEvent(select, "dblclick", this.doubleClickAction, this,
				[ side ]);
	}
	if (this.tabable) { // Tabulação
		this.attachEvent(select, "keypress", this.selectKeyPressAction, this,
				[ side ]);
	}

  this.attachEvent(select, "blur", this.onBlur, this);
	this.attachEvent(select, "focus", this.onFocus, this);
	//this.attachEvent(select, "focus", this.OnSelectFocus, this, [side]);

	return select;
}

/**
 * Exibe o valor da propriedade TEXT do item.
 * @param option Indica o objeto HTMLOption
 **/
HTMLDualList.prototype.onMouseOver = function(evt, option) {
  if (option) {
    option.title = option.text;
    option.alt = option.text;
  }
}

/**
 * Cria os procedimentos para os eventos keypress (TAB, SHIFT+TAB, Ctrl+A e Enter)
 * @param select Indica o objeto HTMLSelect.
 * @param side Indica o lado do Select.
 **/
HTMLDualList.prototype.selectKeyPressAction = function(select, evt, side) {

	var altKey = false;
	var ctrlKey = false;
	var shiftKey = false;
	var target = evt.target || evt.srcElement;
	var keyCode = evt.keyCode || evt.which;
	var targtype = target.type;
	var chr = String.fromCharCode(keyCode).toUpperCase();

	if (w3c) {
		if (document.layers) {
			altKey = ((evt.modifiers & Event.ALT_MASK) > 0);
			ctrlKey = ((evt.modifiers & Event.CONTROL_MASK) > 0);
			shiftKey = ((evt.modifiers & Event.SHIFT_MASK) > 0);
		} else {
			altKey = evt.altKey;
			ctrlKey = evt.ctrlKey;
			shiftKey = evt.shiftKey;
		}
	} else {
		altKey = evt.altKey;
		ctrlKey = evt.ctrlKey;
		shiftKey = evt.shiftKey;
	}

	var r = true;
	if (!shiftKey && keyCode == 9) { // TAB
		r = false;
		if (side == "LEFT") {
			this.rightSelect.focus();
		} else {
			controller.next(this);
		}
	} else if (shiftKey && keyCode == 9) { // Shif + TAB
		r = false;
		if (side == "LEFT") {
			controller.focusFirst();
		} else {
			this.leftSelect.focus();
		}
	} else if (!this.readonly && !altKey && ctrlKey && (chr == 'A')) { // Ctrl
		// + A:
		// Selecionar
		// todos.
		r = false;
		this.selectAll(target);
	}

	else if (!this.readonly && keyCode == 13) { // Enter.
		r = false;
		this.moveOption(target, evt, side, "enter");
	}

	if (!r) {
		document.disableEvents = true;
		if (evt.preventDefault) {
			evt.preventDefault();
			evt.stopPropagation();
		} else {
			evt.keyCode = 0;
			evt.returnValue = false;
		}
		return false;
	} else
		return true;
}

/**
 * Seleciona todos os itens que contém no Select (objeto HTMLSelect) da lista dupla.
 * @param select Indica o Select (objeto HTMLSelect) que terá todos os itens selecionados.
 **/
HTMLDualList.prototype.selectAll = function(select) {
	for (i = 0; i < select.options.length; i++) {
		select.options[i].selected = true;
	}
}

/**
 * Seta o style dos itens do Select.
 * @param obj Indica o objeto HTMLSelect da lista dupla.
 **/
HTMLDualList.prototype.setDecorationObject = function(obj) {
	if (this.font) {
		obj.style.fontFamily = this.font;
	}
	if (this.size) {
		obj.style.fontSize = this.size;
	}
	if (this.weight) {
		obj.style.fontWeight = "bold";
	}
	if (this.italic) {
		obj.style.fontStyle = "italic";
	}
	if (this.underline) {
		obj.style.textDecoration = "underline";
	}
	if (this.strikeout) {
		obj.style.textDecoration = "line-through";
	}
	if (!this.enabled) {
		obj.style.color = '#999999';
	} else {
		if (this.color) {
			obj.style.color = this.color;
		}
	}
}

/**
 * Seta o style do label Descricao PRINCIPAL.
 * @param obj célula <TD>.
 **/
HTMLDualList.prototype.setDecorationLabelPrincipal = function(obj) {
  if (this.fontPrincipal) {
    obj.style.fontFamily = this.fontPrincipal;
  }
  if (this.sizePrincipal) {
    obj.style.fontSize = this.sizePrincipal;
  }
  if (this.weightPrincipal) {
    obj.style.fontWeight = "bold";
  }
  if (this.italicPrincipal) {
    obj.style.fontStyle = "italic";
  }
  if (this.underlinePrincipal) {
    obj.style.textPrincipal = "underline";
  }
  if (this.strikeoutPrincipal) {
    obj.style.textPrincipal = "line-through";
  }
  if (!this.enabled) {
    obj.style.color = '#999999';
  } else {
    if (this.colorPrincipal) {
      obj.style.color = this.colorPrincipal;
    }
  }
}

/**
 * Seta o style do label Descricao SELECIONADOS.
 * @param obj célula <TD>.
 **/
HTMLDualList.prototype.setDecorationLabelSelecionados = function(obj) {
 if (this.fontSelecionados) {
    obj.style.fontFamily = this.fontSelecionados;
  }
  if (this.sizeSelecionados) {
    obj.style.fontSize = this.sizeSelecionados;
  }
  if (this.weightSelecionados) {
    obj.style.fontWeight = "bold";
  }
  if (this.italicSelecionados) {
    obj.style.fontStyle = "italic";
  }
  if (this.underlineSelecionados) {
    obj.style.textSelecionados = "underline";
  }
  if (this.strikeoutSelecionados) {
    obj.style.textSelecionados = "line-through";
  }
  if (!this.enabled) {
    obj.style.color = '#999999';
  } else {
    if (this.colorSelecionados) {
      obj.style.color = this.colorSelecionados;
    }
  }
}

/**
 * Seta as propriedades do style do objeto do label PRINCIPAL (objeto <TD>).
 * @param f Indica o tipo da fonte.
 * @param s Indica o tamanho da fonte.
 * @param w Indica a largura da fonte.
 * @param i Indica se a fonte sera Italico.
 * @param u Indica se a fonte será Sublinhado.
 * @param st Indica se a fonte será Tachado.
 * @param c Indica a cor da fonte.
 **/
HTMLDualList.prototype.setDecorationDescriptionLEFT = function(f, s, w, i, u, st, c) {
  this.fontPrincipal = f;
  this.sizePrincipal = s;
  this.weightPrincipal  = w;
  this.italicPrincipal  = i;
  this.underlinePrincipal  = u;
  this.strikeoutPrincipal  = st;
  this.colorPrincipal  = c;
}

/**
 * Seta as propriedades do style do label SELECIONADOS (objeto <TD>).
 * @param f Indica o tipo da fonte.
 * @param s Indica o tamanho da fonte.
 * @param w Indica a largura da fonte.
 * @param i Indica se a fonte sera Italico.
 * @param u Indica se a fonte será Sublinhado.
 * @param st Indica se a fonte será Tachado.
 * @param c Indica a cor da fonte.
 **/
HTMLDualList.prototype.setDecorationDescriptionRIGHT = function(f, s, w, i, u, st, c) {
  this.fontSelecionados = f;
  this.sizeSelecionados = s;
  this.weightSelecionados  = w;
  this.italicSelecionados  = i;
  this.underlineSelecionados  = u;
  this.strikeoutSelecionados  = st;
  this.colorSelecionados  = c;
}

/**
 * Chama a function 'moveOption' quando o evento 'dblClick' for disparado.
 * @param side Indica o lado da lista dupla onde o evento foi disparado.
 **/
HTMLDualList.prototype.doubleClickAction = function(target, event, side) {
	// Ao duplo clicar
	this.moveOption(target, event, side, "double");
}

/**
 * Checa se o Select (objeto HTMLSelect) é nulo ou 'undefined'.
 * @param select Indica o objeto HTMLSelect.
 **/
HTMLDualList.prototype.validateSelect = function(select) {
	if (select == null || (typeof select == "undefined")) {
		throw "Undefined " + this.name + ".";
	}
}

/**
 * Retorna o objeto HTMLOption criado.
 * @param value Indica o valor da propriedade VALUE do objeto.
 * @param text Indica o valor da propriedade TEXT do objeto.
 * @return Retorna o HTMLOption.
 **/
HTMLDualList.prototype.createOption = function(value, text, side) {
	var option = new Option(text, value);
	this.attachEvent(option, "mouseover", this.onMouseOver);
	return option;
}

/**
 * Cria e adiciona os itens (objetos HTMLOption) ao Select (objeto HTMLSelect).
 * @param select Objeto Select onde serão inseridos os Options.
 * @param labels Indica uma lista de valores que representa os valores da propriedade TEXT de cada HTMLOption que será criado.
 * @param values Indica uma lista de valores que represanta os valores da propriedade VALUE de cada HTMLOption que será criado.
 **/
HTMLDualList.prototype.setOptions = function(select, labels, values) {
	this.validateSelect(select);

	for ( var i = 0; i < values.length; i++) {
		// var option = this.createOption(select, values[i], labels[i],
		// select.getAttribute("SIDE"));
		var option = this.createOption(values[i], labels[i], select
				.getAttribute("SIDE"));
		select.options[i] = option;
	}
}

/**
 * Cria os botoes (objeto HTMLImage) da lista dupla.
 * @param src Indica o endereço da imagem.
 * @param heigth Indica a altura da imagem.
 * @param width Indica a largura da imagem.
 * @param visible Indica se a Imagem será visível.
 * @param fn Indica a function que será associado ao evento 'onclick' da imagem.
 * @param side
 * @param param
 * @param hint Indica o hint que será associado a imagem.
 * @return objeto HTMLImage.
 **/
HTMLDualList.prototype.createImageButton = function(src, height, width,
		visible, fn, side, param, hint) {
	this.img = new ImageObject().getImage(src, this.alt, null, height, width);
	this.img.style.visibility = visible ? "visible" : "hidden";
	this.img.setAttribute('border', 0);
	this.img.style.cursor = "pointer";
	// Hint.
	this.img.hint = hint;
	this.img.alt = hint;
	this.img.title = hint;
	// Evento.
	this.attachEvent(this.img, 'click', fn, this, [ side, param ]);
	return this.img;
}

/**
 * Seta o ReadOnly do componente.
 * @param v - TRUE indica que o componente será somente leitura e os eventos 'ondblClick' e 'onfocus' são removidos.
 **/
HTMLDualList.prototype.setReadOnly = function(v) {
	this.readonly = v;
	var attrib;
    // Itens da Select.
	if (IE) {
		attrib = true;
	} else {
		attrib = 'readonly';
	}
	// Readonly.
	this.leftSelect.setAttribute('readonly', attrib);
	this.rightSelect.setAttribute('readonly', attrib);

	// Removendo eventos.
	this.removeEvent(this.leftSelect, 'dblclick');
	this.removeEvent(this.rightSelect, 'dblclick');
	this.removeEvent(this.leftSelect, 'focus');
	this.removeEvent(this.rightSelect, 'focus');

	// Botões.
	this.setReadOnlyImgButton("btAddOption", attrib);
	this.setReadOnlyImgButton("btAddAllOptions", attrib);
	this.setReadOnlyImgButton("btRemOption", attrib);
	this.setReadOnlyImgButton("btRemAllOptions", attrib);

	if (this.readonly && !this.bgColor) {
		this.duallist.style.backgroundColor = '#FFFFE1';
	}
}

/**
 * Seta a propriedade ReadOnly dos botoes (objeto HTMLImage) da lista dupla.
 * @param v - TRUE indica que o botão é somente leitura e o evento 'onClick' é removido.
 **/
HTMLDualList.prototype.setReadOnlyImgButton = function(imgButton, attrib) {
	var img = document.getElementById(imgButton + this.code).firstChild;
	img.setAttribute('readonly', attrib);
	img.style.cursor = "";

	// Removendo evento.
	this.removeEvent(img, 'click');
}

/**
 * Seta a propriedade Enabled da lista dupla. Indica se o componente será habilitado ou não.
 * @param enable - FALSE desabilita os Select's (objeto HTMLSelect) e os botões. Também remove os oventos 'dblclick' e 'onfocus' dos mesmos.
 **/
HTMLDualList.prototype.setEnabled = function(enable) {
	this.enabled = enable;

	if (enable) {
	  this.leftSelect.removeAttribute('disabled');
	  this.rightSelect.removeAttribute('disabled');
	} else {
	  this.leftSelect.setAttribute('disabled', true);
    this.rightSelect.setAttribute('disabled', true);
	}

	this.setEnabledImgButton("btAddOption", enable);
	this.setEnabledImgButton("btAddAllOptions", enable);
	this.setEnabledImgButton("btRemOption", enable);
	this.setEnabledImgButton("btRemAllOptions", enable);

	if (!enable) {
		this.duallist.style.backgroundColor = '#CCCCCC';
	} else {
		this.duallist.style.backgroundColor = (this.bgColor || '#FFFFFF');
	}
}

/**
 * Seta a propriedade Enabled dos botões da lista dupla. Indica se os botões serão habilitados ou não.
 * @param enable - FALSE desabilita os botões. Também remove o ovento 'click' dos mesmos.
 **/
HTMLDualList.prototype.setEnabledImgButton = function(imgButton, enable) {
	var img = document.getElementById(imgButton + this.code).firstChild;
	
	if (enable) {
	  img.removeAttribute('disabled');
	  img.style.cursor = "pointer";
	} else {
	  img.setAttribute('disabled', true);
	  img.style.cursor = "default";
	}
}

/**
 * Seta a propriedade Visible da lista dupla. Indica se o componente será visível ou não.
 * @param v - TRUE torna os Select's (objeto HTMLSelect) e os botões visíveis.
 **/
HTMLDualList.prototype.setVisible = function(v) {
	this.visible = v;
	var visible = v ? "visible" : "hidden";
	this.duallist.style.visibility = visible;
	this.setVisibleButtons(visible);
}

/**
 * Seta a propriedade Visible dos botões da lista dupla. Indica se os botões serão visíveis ou não.
 * @param v - TRUE torna os botões visíveis.
 **/
HTMLDualList.prototype.setVisibleButtons = function(visible) {
	document.getElementById("btAddOption" + this.code).firstChild.style.visibility = visible;
	document.getElementById("btAddAllOptions" + this.code).firstChild.style.visibility = visible;
	document.getElementById("btRemOption" + this.code).firstChild.style.visibility = visible;
	document.getElementById("btRemAllOptions" + this.code).firstChild.style.visibility = visible;
}

/**
 * Evento onFocus do componente.
 **/
HTMLDualList.prototype.focus = function() {
	if (this.enabled && this.visible && (!this.readonly)) {
		this.timeout(this.onFocusTO, 0);
		return true;
	}
	return false;

}

/**
 * Evento onFocus do componente.
 **/
HTMLDualList.prototype.onFocusTO = function(e) {
  if (isVisibleDiv(this.leftSelect)){
    this.leftSelect.focus();
  }
}

/**
 * Evento onFocus do componente. Muda o style da lista dupla.
 **/
HTMLDualList.prototype.onFocus = function(target, select) {
	if (this.enabled && this.visible && !this.readonly) {
		select.setAttribute("class", "duallistMark");
	}
}

/**
 * Evento onBlur do componente. Muda o style da lista dupla.
 **/
HTMLDualList.prototype.onBlur = function(target, select) {
	if (this.enabled && this.visible && !this.readonly) {
		select.setAttribute("class", "duallist");
	}
}

/**
 * Limpa os objetos (HTMLInput) que armazenam os valores que serão INCLUÍDOS ou EXCLUÍDOS a cada navegação da página.
 **/
HTMLDualList.prototype.clearInput = function() {
	this.elementsToAdd = new Array();
	this.elementsToRemove = new Array();

	var inputInclude = document.getElementById("WFRInputInclude" + this.code);
	inputInclude.value = '';
	var inputDelete = document.getElementById("WFRInputDelete" + this.code);
	inputDelete.value = '';
}

/**
 * Limpa os Select (objetos HTMLSelect), antes de preenchê-los, a cada navegação da página.
 **/
HTMLDualList.prototype.clearBoth = function() {
	this.oldLeftSelect = this.backup(this.leftSelect);
	this.oldRightSelect = this.backup(this.rightSelect);

	this.clear(this.leftSelect);
	this.clear(this.rightSelect);
}

HTMLDualList.prototype.backup = function(select) {
	this.validateSelect(select);
	var selectSaved = new Array();

	for (i = select.options.length - 1; i >= 0; i--) {
		selectSaved.push(select.options[i].value);
	}

	return selectSaved;
}

/**
 * Limpa os Select (objetos HTMLSelect).
 * @param select Indica o objeto HTMLSelect.
 **/
HTMLDualList.prototype.clear = function(select) {
	this.validateSelect(select);

	for (i = select.options.length - 1; i >= 0; i--) {
		select.options[i] = null;
	}
}

/**
 * Executa o Evento 'Ao Duplo Clicar' do componente.
 * @param value Indica o Campo CHAVE do item (objeto HTMLOption).
 * @param text Indica o Campo LISTA do item (objeto HTMLOption).
 **/
HTMLDualList.prototype.invokeEventsDoubleClick = function(value, text) {
	// duplo clicar.
	if (this.ondblclick) {
		this.ondblclick(value, text);
	}
}

/**
 * Executa o Evento 'Antes de Adicionar' do componente.
 * @param value Indica o Campo CHAVE do item (objeto HTMLOption).
 * @param text Indica o Campo LISTA do item (objeto HTMLOption).
 * @param param - 'all' chama o evento 'Antes de Adicionar Todos', caso 'item' executa o evento 'Antes de Adicionar Item'.
 **/
HTMLDualList.prototype.invokeEventsBeforeAdd = function(value, text, param) {
	if (param == "all") {
		// Evento antes de adicionar todos.
		if (this.onBeforeAddAll) {
			this.onBeforeAddAll(value, text);
		}
	} else if ((param == "item") || (param == "enter")) {
		// Evento antes de adicionar item.
		if (this.onBeforeAddItem) {
			this.onBeforeAddItem(value, text);
		}
	}
}

/**
 * Executa o Evento 'Depois de Adicionar' do componente.
 * @param value Indica o Campo CHAVE do item (objeto HTMLOption).
 * @param text Indica o Campo LISTA do item (objeto HTMLOption).
 * @param param - 'all' chama o evento 'Depois de Adicionar Todos', caso 'item' executa o evento 'Depois de Adicionar Item'.
 **/
HTMLDualList.prototype.invokeEventsAfterAdd = function(value, text, param) {
	if (param == "all") {
		// Evento Após adicionar todos.
		if (this.onAfterAddAll) {
			this.onAfterAddAll(value, text);
		}
	} else if ((param == "item") || (param == "enter")) {
		// Evento Após adicionar item.
		if (this.onAfterAddItem) {
			this.onAfterAddItem(value, text);
		}
	}
}

/**
 * Executa o Evento 'Antes de Remover' do componente.
 * @param value Indica o Campo CHAVE do item (objeto HTMLOption).
 * @param text Indica o Campo LISTA do item (objeto HTMLOption).
 * @param param - 'all' chama o evento 'Antes de Remover Todos', caso 'item' executa o evento 'Antes de Remover Item'.
 **/
HTMLDualList.prototype.invokeEventsBeforeRem = function(value, text, param) {
	if (param == "all") {
		// Evento antes de remover todos.
		if (this.onBeforeRemAll) {
			this.onBeforeRemAll(value, text);
		}
	} else if ((param == "item") || (param == "enter")) {
		// Evento antes de remover item.
		if (this.onBeforeRemItem) {
			this.onBeforeRemItem(value, text);
		}
	}
}

/**
 * Executa o Evento 'Depois de Remover' do componente.
 * @param value Indica o Campo CHAVE do item (objeto HTMLOption).
 * @param text Indica o Campo LISTA do item (objeto HTMLOption).
 * @param param - 'all' chama o evento 'Depois de Remover Todos', caso 'item' executa o evento 'Depois de Remover Item'.
 **/
HTMLDualList.prototype.invokeEventsAfterRem = function(value, text, param) {
	if (param == "all") {
		// Evento Após remover todos.
		if (this.onAfterRemAll) {
			this.onAfterRemAll(value, text);
		}
	} else if ((param == "item") || (param == "enter")) {
		// Evento Após remover item.
		if (this.onAfterRemItem) {
			this.onAfterRemItem(value, text);
		}
	}
}

/**
 * Seta a propriedade Hint da lista dupla.
 * @param hint - valor da propriedade 'Dica' do componente no MAKER.
 **/
HTMLDualList.prototype.setHint = function(hint) {
  this.callMethod(HTMLElementBase, "setHint", [hint]);

  if (this.duallist && hint != null && typeof hint != "undefined") {
    this.duallist.title = hint;
    this.duallist.alt = hint;
  }
}

HTMLDualList.prototype.getPermissionDescription = function() {
  var componentDescription;

  if (!isNullable(this.descPrincipal)) {
    componentDescription = this.descPrincipal;
  } else {
    componentDescription = (this.code + " - " + this.id);
  }

  if (!isNullable(this.descSelecionados)) {
    componentDescription += (" / " + this.descSelecionados);
  }

  return componentDescription;
}

HTMLDualList.prototype.flush = function() {
  var i;
  if (this.oldLeftSelect && this.oldLeftSelect.options) {
    for (i = this.oldLeftSelect.options.length - 1; i >= 0; i--) this.oldLeftSelect.options[i] = null;
    this.oldLeftSelect = null;
  }
  if (this.oldRightSelect && this.oldRightSelect.options) {
    for (i = this.oldRightSelect.options.length - 1; i >= 0; i--) this.oldRightSelect.options[i] = null;
    this.oldRightSelect = null;
  }
  if (this.leftSelect && this.leftSelect.options) {
    for (i = this.leftSelect.options.length - 1; i >= 0; i--) this.leftSelect.options[i] = null;
    this.leftSelect = null;
  }
  if (this.rightSelect && this.rightSelect.options) {
    for (i = this.rightSelect.options.length - 1; i >= 0; i--) this.rightSelect.options[i] = null;
    this.rightSelect = null;
  }
  this.onMouseOver = null;
  this.img = null;
  this.inputInclude = null;
  this.inputDelete = null;
  this.elementsToAdd = null;
  this.elementsToRemove = null;
  this.duallist = null;
  this.divWFRComponentRIGHT = null;
  this.divWFRComponentLEFT = null;
  this.labels = null;
  this.values = null;
  this.labelsRIGHT = null;
  this.valuesRIGHT = null;
	this.callMethod(HTMLElementBase, "flush");
}