/**
 * handling of multivalue fields of the following types:
 *	1 numeric
 *	2 text
 *	3 date
 *	5 phone
 *	9 textarea
 *	email
 */

// -- multivalue field object definition
/**
 * formId: id of the form 
 * name: field name as indicated in field definition in section xml
 * options: a list of options
 *	- type: field type. used for indication textarea types to set the value in innerText rather than value attribute
 *	- minCardinality: defaulted to -1 => can be none
 *	- maxCardinality: defaulted to -1 => unlimited
 * 	- expandHorizontal: defaulted to 1 => one input per line
 *	- addHTML: html of add link as constructed on the server side (taking into consideration the image and localized text)
 *	- deleteHTML: html of delete link as constructed on the server side (taking into consideration the image and localized text)
 *	- pointer: name of the instance of this class. used to access the add and delete methods
 */
 var mvSeparator = ":";
 var PR = null;

function MultiValueField(formId, name, options) {
	this.formId = formId;
	this.name = name;
	this.pointer = options.pointer;
	this.type    = options.type;
	
	this.isTextarea = (this.type == "9");
	this.isPicker   = false;
	
	this.id   = this.formId + mvSeparator +this.name;
	this.maxCardinality   = options.maxCardinality;
	this.minCardinality   = options.minCardinality;
	this.expandHorizontal = options.expandHorizontal;
	this.deleteLinkHTML   = options.deleteHTML;
	this.addLinkHTML      = options.addHTML;
	this.addLinkPosition  = options.addLinkPosition;
	this.fieldSize		  = options.fieldSize;
	this.fieldWidth		  = options.fieldWidth;
	this.allowDuplicate = options.allowDuplicate;
	
	this.mvElements = [];					/* array of containing elements that constitutes this multivalu */
	
	
	// public methods
	this.render      = renderMVField;			/* called when the object is constructed and on each add and delete value methods */
	this.addValue    = addValue;
	this.deleteValue = deleteValue;
	this.editValue	 = editValue;
	
	// private methods
	this.add    = appendElementToField;
	this.constructAddLink = constructAddLink;
	this.updateMvElements = updateMvElements;
	
	this.addLink = this.constructAddLink();
}

function constructAddLink() {
	var div = document.createElement("DIV");
	
	if(this.addLinkHTML != '') {
    	div.innerHTML = this.addLinkHTML;	
    	div.childNodes[0].setAttribute("onclick", "javascript:"+this.pointer+".addValue();return false;");
    	div.childNodes[0].setAttribute("href", "#");
	}

	return div;
}


function addValue() {
	if(this.maxCardinality > -1 && this.mvElements.length >= this.maxCardinality) {
		alert(formatMessage('Can not add more than {0} value(s) for {1}',this.maxCardinality,this.name));
		return;
	}
	
	// update inputElement by the latest HTML
	this.updateMvElements();
	
	new MultiValueElement(this, this.mvElements.length+1, "");
	
	this.render();
}

function editValue (chainKey, pointer, titleFieldName, pName, pWidth, pHeight, pProps) {
	var formUrl = "/autoforms/doc/" + chainKey + "?AF_renderParam_portlet=portlet_addNewPortlet&AF_renderParam_embed=true";
	formUrl = escape(encodeURIComponent(formUrl));
	var popupUrl = "/autoforms/view/FSDoc?formUrl=" + formUrl + "&pointer=" + pointer + "&FSaction=edit&isFSDocAtt=true" + "&docTitleFieldName=" + titleFieldName;
	
	if (this.popupName == null || this.popupName == "null")
		this.popupName = "EditDocument";
		
	var popped = AF_popupUrl(popupUrl, pName, pWidth, pHeight, pProps, true);
}

function deleteByCKey(cKey) {
	var delIndex = -1;
	for (var i = 0 ; i < this.mvElements.length ; i++) {
		if (this.mvElements[i].value == cKey) {
			delIndex = i;
			break;
		}
	}
	
	if (delIndex != -1) {
		this.deleteValue("", delIndex);
		return false;
	}
}

function deleteValue(fileDeleteRef, index) {
	
	var ajaxDeleteRequest;
		
	var ajaxKey = '--afdelajx--';
	var keyIndex = fileDeleteRef.indexOf(ajaxKey);
		
	if (keyIndex == -1) {
		// no ajax call for document attachments since we don't actually want to delete the document, we 
		// just want to deselect it	
	}
	else{		
		// remove  --afdelajx-- from the fileDeletRef
		fileDeleteRef = fileDeleteRef.substring(keyIndex + ajaxKey.length, fileDeleteRef.length);
		  
		try
		{
			// firefox, safari, opera
			ajaxDeleteRequest = new XMLHttpRequest();
		}
		catch (e)
		{
			// Internet Explorer
		    try
		      {
		      	ajaxDeleteRequest=new ActiveXObject("Msxml2.XMLHTTP");
		      }
	    	catch (e)
	     	 {
		      	try
		       	 {
		        	ajaxDeleteRequest=new ActiveXObject("Microsoft.XMLHTTP");
		         }
		      	catch (e)
		        {
		        	alert("Your browser does not support AJAX!");
		        	return false;
		        }
		     }
		} // initialize the ajax request
		
		ajaxDeleteRequest.onreadystatechange = function()
		{
			// ajax code, process response from server
			if (ajaxDeleteRequest.readyState == 4)
			{
				// response is complete and we can get our data
				ajaxDeleteRequest.responseText;	
				try{				
					// remove the file from the popup window as well..								
					AF_popupAttachmentPickerWindow.location.reload();
					AF_popupAttachmentPickerWindow = null;
				}catch (e){				
				}	
			}
		}
		// send a request to the servlet to delete the file
		ajaxDeleteRequest.open ("GET", fileDeleteRef, true);
		ajaxDeleteRequest.send (null); 
	}
	
	// if deleting the last available input, delete its value and keep the input

	/* fha: there is no need to deny the user from removing existing elements even if the total count is less than minCardinality
		    cz in all cases we have a validate on submit */
	/*
	if(this.minCardinality > -1 && this.mvElements.length <= this.minCardinality) {
		if(!this.isPicker)
			document.getElementById(this.mvElements[index-1].id).childNodes[0].value = "";
		alert(formatMessage('Should have at least {0} value(s) for {1}',this.minCardinality,this.name));
		return;
	}
	*/
	
	// update inputElement by the latest HTML
	this.updateMvElements();	
	
	// shift mvElements[] to remove the deleted element
	// update the index and field_name of the containing inputElement HTML 
	for(var i=index-1; i<this.mvElements.length-1; i++) {
		this.mvElements[i] = this.mvElements[i+1]
		this.mvElements[i].updateIndex(this.mvElements[i].index, i+1)
	}
	
	this.mvElements.pop();
	
	eval(this.onChange);		/* Call the onChange if value is deleted */
	
	this.render();

/* alert ('issuing reload for: ' + pickerWindow + ' on location: ' + pickerWindow.location); */
/*pickerWindow.location.reload();*/
	
	return false;


}

// update inputElement by the latest HTML
function updateMvElements() {

	for(var i=0; i<this.mvElements.length; i++) {
		// for Gecko, the value/innerHTML of input/textarea is not presisted in attribute value/innerHTML but implicitly
		// in the .value 
		// so we need to set it explicitly so that the value will not be lost
		if(is_gecko) {
			if(!this.isTextarea) {
				var inputValue = document.getElementById(this.mvElements[i].id).childNodes[0].value;
				document.getElementById(this.mvElements[i].id).childNodes[0].setAttribute("value", inputValue);
			}
			else {
				var inputValue = document.getElementById(this.mvElements[i].id).childNodes[0].value;
				document.getElementById(this.mvElements[i].id).childNodes[0].innerHTML = inputValue;
			}
		}
		this.mvElements[i].inputElement = document.getElementById(this.mvElements[i].id).innerHTML;		
	}
}

function appendElementToField(element) {
	this.mvElements[this.mvElements.length] = element;
}

function renderMVField() {

	var abcontainer = document.getElementById(this.id+mvSeparator+"container");
	abcontainer.innerHTML = "";
	var newhtml = "<table border=0 cellspacing=0 cellpadding=0><tr><td><table border=0 cellspacing=0 cellpadding=0>\n";
	if(!this.addLinkPosition || this.addLinkPosition == 'top')
		newhtml += "<tr><td>"+this.addLink.cloneNode(true).innerHTML+"</td></tr>";
	newhtml += "<tr>";
	
	for(var i=0; i<this.mvElements.length; i++) {
		newhtml += "<td><span id='"+this.mvElements[i].id+"'>"+(this.mvElements[i].inputElement)+ "</span>";
		if(this.mvElements.length != 1) {
			newhtml += "&nbsp;" + this.mvElements[i].deleteLink().innerHTML;
			if (this.FSDocAtt) {
				newhtml += "&nbsp;" + this.mvElements[i].editLink().innerHTML;
			}
			newhtml += "</td>";
		}
		
		//add empty cells till we reach the expandHorizontal
		if(i==this.mvElements.length-1) {
			var remainingCellCount = (this.expandHorizontal - this.mvElements.length % this.expandHorizontal)%this.expandHorizontal;
			for(var j=1; j <= remainingCellCount;j++) {
				newhtml += "<td></td>"
			}
		}		
			
		if(i+1 < this.mvElements.length)
		if((i+1) % this.expandHorizontal == 0) newhtml += "</tr><tr>\n";
	}
	
	newhtml += "</tr>";
	if(this.addLinkPosition && this.addLinkPosition =='bottom')
		newhtml += "<td>&nbsp;"+this.addLink.cloneNode(true).innerHTML+"</td></tr>";
	newhtml += "</table></td>\n";
	if(this.addLinkPosition =='inlineFirst')
		newhtml += "<td valign='top'>&nbsp;"+this.addLink.cloneNode(true).innerHTML+"</td></tr></table>";
	else if(this.addLinkPosition =='inlineLast')
		newhtml += "<td valign='bottom'>&nbsp;"+this.addLink.cloneNode(true).innerHTML+"</td></tr></table>";
		
	abcontainer.innerHTML = newhtml;
}

// -- multivalue element object definition
function MultiValueElement(mvField, index, value) {
	this.mvField = mvField;
	
	this.index  = index
	this.value  = value;
	this.id     = this.mvField.id   + mvSeparator + this.index;
	
	this.getMVInput = getMVInput
	this.deleteLink = constructDeleteLink;
	this.editLink 	= constructEditLink
	
	this.getIndex = getIndex;
	
	this.inputElement = this.getMVInput();			/* get the HTML of the mv input according to the template; 
								   get it on the onload and update it using the updateIndex method 
								   can not recreate it every time (add/delete) the mv field is to be rendered
								   as to keep it's value as edited by the user */
	
	this.updateIndex = updateIndex;				/* called when a value is deleted to update this.index, this.id and any innerHTML that 
								   has mvSeparatorfield_namemvSeparator according to new position */
	
	this.mvField.add(this);
}

function getIndex(index) {
	return index;
}

function updateIndex(from, to) {
	this.index  = to;
	this.id     = this.mvField.id   + mvSeparator + this.index;
	
	while(this.inputElement.indexOf(this.mvField.name+mvSeparator+from+mvSeparator) > -1)
	this.inputElement = this.inputElement.replace(this.mvField.name+mvSeparator+from+mvSeparator, this.mvField.name+mvSeparator+to+mvSeparator);
}

function getMVInput() {
	var template = document.getElementById(this.mvField.id+mvSeparator+"template");

	var mvHTML = template.innerHTML;
	// replace the input name
	mvHTML = mvHTML.replace("template"+mvSeparator+this.mvField.name, this.mvField.name + mvSeparator + this.index + mvSeparator);
	
	// replace mvSeparatorfield_namemvSeparator used for fields of type date
	mvHTML = mvHTML.replace(mvSeparator+"field_name"+mvSeparator, this.mvField.name + mvSeparator + this.index + mvSeparator);

	var myelement = document.createElement("span");
	myelement.innerHTML = mvHTML;
	
	if(template.childNodes[0].getAttribute("mvf_disabled") == "true")
		myelement.childNodes[0].disabled = true;
	else
		myelement.childNodes[0].disabled = false;

	if(this.mvField.isTextarea) {
		if(is_gecko)   myelement.childNodes[0].innerHTML = this.value;
		else if(is_ie) myelement.childNodes[0].innerText = this.value;
		else           myelement.childNodes[0].innerHTML = this.value; 
		
	}
	else myelement.childNodes[0].setAttribute("value", this.value);
	
	return myelement.innerHTML;
}

function attachmentEditLink(html, url) {
		var span = document.createElement("SPAN");
		span.innerHTML = html;
		span.childNodes[0].setAttribute("onclick", "javascript: AF_popupUrl('"+url+"');return false;");					
		span.childNodes[0].setAttribute("href", "#");		
	return span.innerHTML;
}

function constructEditLink() {
	var span = document.createElement("SPAN");

	if (this.mvField.editLinkHTML != '') {
		span.innerHTML = this.mvField.editLinkHTML;
		
		var editString = this.mvField.editPrefix + '/' + this.value + this.mvField.editSuffix;
		span.childNodes[0].setAttribute("onclick", "javascript: editValue(\""+this.value+"\", \""+this.mvField.pointer+"\", \""+this.mvField.docTitleFieldName+"\", \""+PR.popupName+"\", \""+PR.popupWidth+"\", \""+PR.popupHeight+"\", \""+PR.popupProps+"\");return false;");		
		span.childNodes[0].setAttribute("href", "#");		
	}
	return span;
}

function constructDeleteLink() {
	var span = document.createElement("SPAN");
	prefix = "";
	suffix = "";
	if(this.mvField.deleteLinkHTML != '') {	
		/* fha replace href by onlick*/		
		var prefix = "";
		var suffix = "";
		if(this.mvField.hideDeleteButton == "true"){
			prefix = "<div style='display:none'>";
			suffix = "</div>";
		}
    	span.innerHTML = prefix + this.mvField.deleteLinkHTML + suffix;

		var deletionString = this.mvField.deletionPrefix + '/' + addSlashes(encodeURIComponent(this.value)) + this.mvField.deletionSuffix + "&resultId=" + this.mvField.pointer;    	
    	span.childNodes[0].setAttribute("onclick", "javascript:"+this.mvField.pointer+".deleteValue('"+deletionString+"',"+this.getIndex(this.index)+");return false;");
		span.childNodes[0].setAttribute("href", "#");
	}
	return span;
}



/**
 * handling of multivalue fields of types
 *	- addressbook
 *	- fileAttachment
 *
 */

// -- multivalue field object definition
/**
 * formId: id of the form 
 * name: field name as indicated in field definition in section xml
 * options: a list of options
 *	- minCardinality: defaulted to -1 => can be none
 *	- maxCardinality: defaulted to -1 => unlimited
 * 	- expandHorizontal: defaulted to 1 => one input per line
 *	- pickerHTML: html of pick link as constructed on the server side (taking into consideration x-the image-x and localized text)
 *	- pickerURL: url of the directory to be concatinated with url parameters in method 'drawPickerHTML' 	
 *	- deleteHTML: html of delete link as constructed on the server side (taking into consideration the image and localized text)
 *	- pointer: name of the instance of this class. used to access the picker and delete methods
 */
 function PickerResult(formId, name, options){
	this.formId = formId;
	this.name   = name;
	this.id     = this.formId + mvSeparator +this.name;
	
	this.isTextarea = false;
	this.isPicker   = true;
	
	this.deletionPrefix = options.deletionPrefix;	// GET's for when you click the redX to delete a file..
	this.deletionSuffix = options.deletionSuffix;
	
	this.pointer        = options.pointer;
	this.pickerHTML     = options.pickerHTML;
	this.pickerURL      = options.pickerURL;
	this.deleteLinkHTML = options.deleteHTML;
	this.editLinkHTML   = options.editHTML;
	this.addPickerHTML  = options.addPickerHTML;
	this.addPickerURL   = options.addPickerURL;
	
	this.dockey 		= options.dockey;
	this.formName		= options.formName;
	this.showThumbnailInstead = options.showThumbnailInstead;
	if(this.thumbnailField != null){
		this.thumbnailField = options.thumbnailField;
	}else{
		this.thumbnailField = this.name;	
	}
	this.usingAurigmaThumbnailSuffix = options.usingAurigmaThumbnailSuffix;
	this.maxCardinality   = options.maxCardinality;
	this.minCardinality   = options.minCardinality;
	this.expandHorizontal = options.expandHorizontal;
	this.onChange		  = options.onChange;
	this.disableOnChange  = true;					/* the onChange content should not be called when first accessing the form or when accessing a view with a field containing an onChange*/
	this.fieldType		  = options.fieldType;

	this.isFSDocAtt  	  = options.isFSDocAtt;
	
	this.docTitleFieldName = options.docTitleFieldName;
	
	// Popup window settings	
	this.popupName			= options.popupName;	
	this.popupHeight		= options.popupHeight;
	this.popupWidth			= options.popupWidth;
	this.popupProps			= options.popupProps;

	this.getIndex = getIndex;
	
	this.mvElements = [];
	
	// private methods
	this.render           = renderPicker;			/* called with every setResult call */
	this.updateMvElements = updateMvABPElements;		/* called with every deleteValue call [not useful for this object] */
	this.drawPickerHTML   = drawPickerHTML;			/* called with every render call
								   builds the html of picker based on options and on current selections */
	this.drawAddPickerHTML  = drawAddPickerHTML;
	this.generateAttachmentPreviewLink = generateAttachmentPreviewLink;
	
	
	// public methods
	this.deleteValue  = deleteValue;
	this.setResult    = setResult;				/* accessed onload and from the directory-picker window */
	this.addResult	  = addResult;
	this.editResult	  = editResult;
	this.deleteByCKey = deleteByCKey; 
	
	PR = this;
	
}

function generateAttachmentPreviewLink(fileName){
	var field = this.name;
	if(this.showThumbnailInstead == 'true'){
		field = this.thumbnailField;
	}
	return "/autoforms/attachments/view/"+this.dockey+"/"+field+"/"+fileName+this.usingAurigmaThumbnailSuffix+"?var="+this.dockey+"&AF_UIID="+this.formId+"&form="+this.formName;
}

function updateMvABPElements() {}

// result is a 2 dimentional array of value and display values
function setResult(result){

	// reset current selection
	this.mvElements = [];
	
	for(var s=0; s<result.length; s++) {	
		this.mvElements[s] = new PickerSelection(this, result[s][0], result[s][1], s+1);
	}
	
	if((!this.disableOnChange) && result.length != 0 && this.fieldType == "addressbook")		/* Check if this setResult is called on access of a view or first access of a form */
		eval(this.onChange);
	
	this.disableOnChange = false;	/* Here the conditions for not calling the onChange are no longer valid. */
	this.render();
}

function addResult(result) {
	var resultA = new Array();
	
	var blehb = [];

	// First copy the old ones across..
	for (var i = 0 ; i<this.mvElements.length; i++) {
		blehb[i] = this.mvElements[i];
	}
	this.mvElements = [];

	for (var s = 0 ; s < blehb.length; s++) {
		this.mvElements[s] = new PickerSelection (this, blehb[s].value, blehb[s].displayValue, s+1);
	}
	
	// Then create the newest one..
	this.mvElements[this.mvElements.length] = new PickerSelection (this, result[0], result[1], this.mvElements.length + 1);
	this.render();
}

function editResult(cKey, title) {

	// first find the result being edited..
	var foundIndex = null;
	for (var i = 0 ; i <this.mvElements.length ; i++) {
		if (cKey == this.mvElements[i].value) {
			foundIndex = i;
			break;
		}
	}
	
	// update the title of the found element
	if (foundIndex != null) {
		this.mvElements[foundIndex].displayValue = title;
		// rerender with the updated value;
		this.render();
	}
}

function renderPicker(recordIndex) {

	//used for multi-value field groups containing file attachments
	if(!recordIndex) {
		var recordIndex = 0;
	}

	var abcontainer = document.getElementById(this.id+mvSeparator+"container");
	abcontainer.innerHTML = "";
	
	var elt = document.getElementById(this.formId).elements["template"+mvSeparator+this.name];
	var isFieldHidden = "false";
	var isFieldDisabled = "false";
	if(elt != null) {
		isFieldHidden = elt.getAttribute("mvf_hidden");
		isFieldDisabled = elt.getAttribute("mvf_disabled");
	}
	
	var newhtml = "<table border=0 cellpadding=0 cellspacing=0><tbody><tr>";
	if (this.isFSDocAtt == true) {
		newhtml += "<td valign=\"top\">"+this.drawPickerHTML()+"</td>";
		newhtml += "<td valign=\"top\">"+this.drawAddPickerHTML()+"</td>";
		newhtml += "</tr><tr>";
	}
	
	for(var i=0; i<this.mvElements.length; i++) {
		if(i==0) {
			newhtml += "<td><table border=0 cellpadding=0 cellspacing=0><tbody><tr>\n";
		}
		
		newhtml += "<td id=\""+this.mvElements[i].id+"\" >";
		newhtml += "	<input type=\"hidden\" name=\""+this.name+mvSeparator+(i+1+recordIndex)+mvSeparator+"\" value=\""+this.mvElements[i].value+"\"";
		
		if(isFieldDisabled == "true")
			newhtml += " disabled=\"true\"";
		newhtml +=">"
		
		if(isFieldHidden != "true") {
			if(this.showThumbnailInstead == "true") {
				newhtml += "<img src='"+this.generateAttachmentPreviewLink(this.mvElements[i].displayValue) + "' title='"+this.mvElements[i].displayValue+"' />";
			}
			else {
				fieldName = this.name;
				fileName = this.mvElements[i].value;
				formName = this.formName;
				fileName = encodeURIComponent(fileName);
				fieldName = encodeURIComponent(fieldName);
				formName = encodeURIComponent(formName);				
				
				if (this.mvElements[i].mvField.fieldType == "docAttachment") {
					dockey = this.mvElements [i].value;
					url = "/autoforms/doc/"+dockey;
					newhtml += "<A HREF="+url+" TARGET=\"_blank\">"+this.mvElements[i].displayValue+"</A>";
				}
				else if (this.mvElements[i].mvField.fieldType == "fileAttachment") {
					dockey = this.dockey;
					url = "/autoforms/attachments/view/"+dockey+"/"+fieldName+"/"+fileName+this.usingAurigmaThumbnailSuffix+"?var="+dockey+"&AF_UIID="+this.formId+"&form="+formName;
					newhtml += "<A HREF="+url+" TARGET=\"_blank\">"+this.mvElements[i].displayValue+"</A>";
				}
				else if(this.mvElements[i].mvField.fieldType == "addressbook") {
					newhtml += this.mvElements[i].displayValue;
				}
				else {
					//If it's none of the above just do this.
					dockey = this.dockey;
					url = "/autoforms/attachments/view/"+dockey+"/"+fieldName+"/"+fileName+this.usingAurigmaThumbnailSuffix+"?var="+dockey+"&AF_UIID="+this.formId+"&form="+formName;
					newhtml += "<A HREF="+url+" TARGET=\"_blank\">" + this.mvElements[i].displayValue; + "</A>";
				}
			}
		}//IF
		
		newhtml += "</td>\n";
		newhtml += "<td>&nbsp;"+this.mvElements[i].deleteLink().innerHTML+"</td>\n";
		
		if (this.isFSDocAtt == true) {
			newhtml += "<td>&nbsp;"+this.mvElements[i].editLink().innerHTML+"</td>\n";
		}
		
		if(i+1 < this.mvElements.length)
		if((i+1) % this.expandHorizontal == 0) newhtml += "</tr><tr>\n";
		
		if(i == this.mvElements.length -1) {
			newhtml += "</tr></tbody></table></td>";
		}
		
	}//FOR
	
	if (this.isFSDocAtt == true) {
		newhtml += "</tr></tbody></table>\n";
	}
	else {
		if(isFieldDisabled != "true") {
			if(this.mvElements.length > this.expandHorizontal) {
				newhtml += "<td valign=\"middle\">"+this.drawPickerHTML()+"</td></tr></tbody></table>\n";
			}
			else {
				newhtml += "<td>"+this.drawPickerHTML()+"</td></tr></tbody></table>\n";
			}
		}
	}
	
	abcontainer.innerHTML = newhtml;
}

//vic: used to build the add new form link for FormSpecificDocAttachment fields
function drawAddPickerHTML() {
	if(this.addPickerHTML == '') return '';
	var span = document.createElement("SPAN");
		span.innerHTML = this.addPickerHTML;
		
	addPickerHref = this.addPickerURL;
	
	
	if (addPickerHref.indexOf("?") == -1) addPickerHref += "?";
	else addPickerHref += "&";
	
	addPickerHref += "resultId="+this.pointer;
	
	
	
	if(is_ie) {
		span.childNodes[0].setAttribute("href", "#");	
		span.childNodes[0].setAttribute("onclick", "javascript: injectPortlet(\""+addPickerHref+"\", \""+this.pointer+"\", \""+this.docTitleFieldName+"\", \""+this.popupName+"\", \""+this.popupWidth+"\", \""+this.popupHeight+"\", \""+this.popupProps+"\");return false;");
	} 
	
	else {
		span.childNodes[0].setAttribute("href", "javascript: injectPortlet(\""+addPickerHref+"\", \""+this.pointer+"\", \""+this.docTitleFieldName+"\", \""+this.popupName+"\", \""+this.popupWidth+"\", \""+this.popupHeight+"\", \""+this.popupProps+"\");");
	}
	
	
	return span.innerHTML;
}

function injectPortlet(formUrl, pointer, titleFieldName, pName, pWidth, pHeight, pProps) {	
	
	formUrl = escape(encodeURIComponent(formUrl));
	var popupUrl = "/autoforms/view/FSDoc?formUrl=" + formUrl + "&pointer=" + pointer + "&FSaction=add" + "&docTitleFieldName=" + titleFieldName;
	
	if (this.popupName == null || this.popupName == "null")
		this.popupName = "AddNew";
		
	var popped = AF_popupUrl(popupUrl, pName, pWidth, pHeight, pProps, true);	
}

function addSlashes(str) {		
	str=str.replace(/\\/g,'\\\\');
	str=str.replace(/\0/g,'\\0');
	str=str.replace(/\'/g,'\\\'');
	str=str.replace(/\"/g,'\\"');
	return str;
}

function drawPickerHTML() {
	if(this.pickerHTML == '') return '';
	var span = document.createElement("SPAN");
	    span.innerHTML = this.pickerHTML;
	
	var pickerHref = this.pickerURL;
	
	if(pickerHref.indexOf("?") == -1) pickerHref += "?";
	else pickerHref += "&";
	
	pickerHref += "resultId="+this.pointer;
	pickerHref += "&maxCardinality="+this.maxCardinality;
	pickerHref += "&minCardinality="+this.minCardinality;
	
	if(this.isMemberOfFieldGroup) {
		pickerHref += "&fieldGroup=true"
	}
	
	
	
	pickerHref += "&currentSelection=";
	for(var i=0; i<this.mvElements.length; i++) {
		/* fha: we need to escape selection names cz special chars get wrongly interpreted */
		// pickerHref += escape(this.mvElements[i].value);
		var entryNameEscaped = encodeURIComponent(this.mvElements[i].value);
		//encodeURICompinent is also escaping.
		//entryNameEscaped = escape(entryNameEscaped); //no need for fixing the ' at this level - we can simply replace 'by " when calling the AF_popup()
		
		if(is_gecko) {
			
			 			 			 			 			 			 									
			//entryNameEscaped = escape(entryNameEscaped);
		} 		
				
		entryNameEscaped = addSlashes(entryNameEscaped);
		pickerHref += entryNameEscaped;
		if(i+1 < this.mvElements.length) pickerHref += ",;,";
	}
	
	
			
	
	if (this.popupName == null || this.popupName == "null")
		this.popupName = "SelectUsers";
	
	if(is_ie) {
		span.childNodes[0].setAttribute("href", "#");	
		span.childNodes[0].setAttribute("onclick", "javascript: AF_popupUrl('" + pickerHref + "', '" + this.popupName + "', '" + this.popupWidth + "', '" + this.popupHeight + "', '" + this.popupProps + "');return false;");
	} 
	
	else {
		span.childNodes[0].setAttribute("href", "javascript: AF_popupUrl('" + pickerHref + "', '" + this.popupName + "', '" + this.popupWidth + "', '" + this.popupHeight + "', '" + this.popupProps + "')");
	}

	return span.innerHTML;
}

function PickerSelection(mvField, value, displayValue, index) {
	this.value = value;
	this.displayValue = displayValue;
	this.index = index;
	
	
	this.mvField = mvField;
	this.id = this.mvField.id   + mvSeparator + this.index;
	
 	this.updateIndex  = updateIndexPicker;				/* called when a value is deleted to update this.index and this.id according to new position */
	this.getIndex = this.mvField.getIndex;
	this.deleteLink   = constructDeleteLink
	this.editLink 	= constructEditLink
}

function updateIndexPicker(from, to) {
	this.index  = to;
	this.id     = this.mvField.id   + mvSeparator + this.index;
}

var is_gecko = /Gecko/i.test(navigator.userAgent)
var is_ie    = /msie/i.test(navigator.userAgent)


/******************************************************************************************************************************************/
/***************************************************** Field Group specific code **********************************************************/
/******************************************************************************************************************************************/
/* @author fhassan*/
/****************************************************/
/************** Field Group Definition **************/
/****************************************************/


function MultiValueFieldGroup(formId, groupName, options) {
	this.formId = formId;
	this.name = groupName;
	this.pointer = options.pointer;
	
	this.id   = this.formId + mvSeparator +this.name;
	this.maxCardinality   = options.maxCardinality;
	this.minCardinality   = options.minCardinality;
	this.expandHorizontal = options.expandHorizontal;
	this.deleteLinkHTML   = options.deleteHTML;
	this.addLinkHTML      = options.addHTML;
	this.addLinkPosition  = options.addLinkPosition;
	this.editLinkHTML     = options.editHTML;
	this.editLinkUrl      = options.editURL;
	if(this.editLinkHTML == null || this.editLinkHTML == "" || this.editLinkUrl == null || this.editLinkUrl == ""){
		this.editLinkHTML = null;
		this.editLinkUrl = null;
	}
	
	this.mvRecords = [];					/* array of containing elements that constitutes this multivalu */
	
	
	// public methods
	this.render      = renderMVFieldGroup;
	this.addRecord    = addRecord;
	this.deleteRecord = deleteRecord;
	this.addRecordWithValue = addRecordWithValue;
	
	// private methods
	this.add    = appendRecordToFieldGroup;
	this.constructAddLink = constructAddLinkGroup;
	this.updateMvRecords = updateMvRecords;
	this.deleteAttachments = deleteRelatedAttachments;
	
	this.addLink = this.constructAddLink();
	
	this.init = initializeFieldGroup;
}

function constructAddLinkGroup() {
	var div = document.createElement("DIV");
	
	if(this.addLinkHTML != '') {
    	div.innerHTML = this.addLinkHTML;	
    	div.childNodes[0].setAttribute("onclick", "javascript:"+this.pointer+".addRecord();return false;");
    	div.childNodes[0].setAttribute("href", "#");
	}

	return div;
}

function addRecord() {
	if(this.maxCardinality > -1 && this.mvRecords.length >= this.maxCardinality) {
		alert(formatMessage('Can not add more than {0} value(s) for {1}',this.maxCardinality,this.name));
		return;
	}
	
	// update inputElement by the latest HTML
	this.updateMvRecords();
	
	var newRecord = new MultiValueRecord(this, this.mvRecords.length+1);
	newRecord.cloneTemplateRecord();
	
	this.render();
}

function addRecordWithValue(values) {
	if(this.maxCardinality > -1 && this.mvRecords.length >= this.maxCardinality) {
		alert(formatMessage('Can not add more than {0} value(s) for {1}',this.maxCardinality,this.name));
		return;
	}
	
	// update inputElement by the latest HTML
	this.updateMvRecords();
	
	var newRecord = new MultiValueRecord(this, this.mvRecords.length+1);
	newRecord.cloneTemplateRecord(values);
	this.render();
}

function initializeFieldGroup() {
	for(var i=0; i<this.mvRecords.length; i++) {
		this.mvRecords[i].init();
	}
}

function updateMvRecords() {
	for(var i=0; i<this.mvRecords.length; i++) {
		this.mvRecords[i].updateContent();
	}
}

function deleteRecord(index) {
	if(this.minCardinality > -1 && this.mvRecords.length <= this.minCardinality) {
		alert(formatMessage('Should have at least {0} value(s) for {1}',this.minCardinality,this.name));
		return;
	}
	// update inputElement by the latest HTML
	this.updateMvRecords();	
	
	// delete any file attachments
	this.deleteAttachments(index);
	
	// shift mvRecords[] to remove the deleted element
	// update the index and field_name of the containing inputElement HTML 
	for(var i=index-1; i<this.mvRecords.length-1; i++) {
		this.mvRecords[i] = this.mvRecords[i+1]
		this.mvRecords[i].updateIndex(this.mvRecords[i].index, i+1)
	}
	this.mvRecords.pop();
	
	this.render();
}

function deleteRelatedAttachments(index) {
	this.mvRecords[index-1].deleteAttachments(index);	
}

function renderMVFieldGroup() {
	var abcontainer = document.getElementById(this.id+mvSeparator+"container");
	abcontainer.innerHTML = "";
	editLink = "";
	if(this.editLinkHTML != null || this.editLinkUrl !=null ){
		editLink = "<td>"+attachmentEditLink(this.editLinkHTML, this.editLinkUrl	)+"</td>";
	}
	
	var newhtml = "<table border=0 cellspacing=0 cellpadding=0><tr><td><table border=0 cellspacing=0 cellpadding=0 >\n";
	
	if(!this.addLinkPosition || this.addLinkPosition == 'top')
		newhtml += "<tr><td>"+this.addLink.cloneNode(true).innerHTML+"</td>"+editLink+"</tr>";
	else{
		if(editLink != "")
			newhtml += "<tr>"+editLink+"</tr>"
	}
	newhtml += "<tr>";
	
	
	for(var i=0; i<this.mvRecords.length; i++) {
		newhtml += "<td><table cellspacing='0' cellpadding='0'><tr><td>"+(this.mvRecords[i].getHTML(i==this.mvRecords.length-1)) + "</td>";
		if(this.mvRecords.length != 1)
			newhtml += "<td>" + this.mvRecords[i].deleteLink().innerHTML + "</td>";
		newhtml += "</td></tr></table></td>"
		//add empty cells till we reach the expandHorizontal
		if(i==this.mvRecords.length-1) {
			var remainingCellCount = (this.expandHorizontal - this.mvRecords.length % this.expandHorizontal)%this.expandHorizontal;
			for(var j=1; j <= remainingCellCount;j++) {
				newhtml += "<td></td>"
			}
		}		
			
		if(i+1 < this.mvRecords.length)
		if((i+1) % this.expandHorizontal == 0) newhtml += "</tr><tr>\n";
	}
	
	newhtml += "</tr>";
	if(this.addLinkPosition && this.addLinkPosition =='bottom')
		newhtml += "<td>&nbsp;"+this.addLink.cloneNode(true).innerHTML+"</td></tr>";
	newhtml += "</table></td>\n";
	if(this.addLinkPosition =='inlineFirst')
		newhtml += "<td valign='top'>&nbsp;"+this.addLink.cloneNode(true).innerHTML+"</td></tr></table>";
	else if(this.addLinkPosition =='inlineLast')
		newhtml += "<td valign='bottom'>&nbsp;"+this.addLink.cloneNode(true).innerHTML+"</td></tr></table>";
		
	abcontainer.innerHTML = newhtml;
	//alert(newhtml);
	this.init();
	// in case we have newly added textareas to the existing html structure we need to add the textarea checker object to it
	AF_initTextareaMaxLengthChecker();
}

function appendRecordToFieldGroup(record) {
	this.mvRecords[this.mvRecords.length] = record;
}

/****************************************************/
/********** Field Group's Record Definition *********/
/****************************************************/

function MultiValueRecord(mvFieldGroup, index) {
	this.mvFieldGroup = mvFieldGroup;
	this.mvLines = [];
	this.index  = index
	this.id     = this.mvFieldGroup.id   + mvSeparator + this.index;
	
	this.deleteLink = constructGroupDeleteLink;
	this.getHTML      = getRecordHTML;
	this.add    = appendLineToRecord;
	this.updateContent = updateMvRecordLines;
	this.deleteAttachments = deleteRecordAttachments;
	this.cloneTemplateRecord = cloneTemplateRecord;
	
	this.init = intializeRecord;
	
	this.updateIndex = updateRecordIndex;				/* called when a record is deleted to update this.index, this.id and any innerHTML that 
								   has [mvSeparator][field_name][mvSeparator] according to new position */
	
	this.mvFieldGroup.add(this);
}


var mvfgeDefaultValue = "";
var fieldGroupRecordIncrementer = 0; // a global variable is used just to make sure that every new element created will have its own unique id
function cloneTemplateRecord(values) {
	if(values == null)
		value = mvfgeDefaultValue;//this is weird, but i kept for when someone decides to actually do soemthing about the default value
			//it is not correct in anyway, since it even assumes the same default for all fields in the record
	fieldGroupRecordIncrementer++;
	var template = document.getElementById(this.mvFieldGroup.id+mvSeparator+"template");
	var lineDivs = template.getElementsByTagName("div");
	var lineCounter = 0;
	for(var l=0; l< lineDivs.length; l++) {
		var inputDivs = lineDivs[l].getElementsByTagName("div");
		var doesThisDivDefineRow = lineDivs[l].getAttribute("af_mvf_line");
		if(doesThisDivDefineRow) {
			lineCounter++;
    		var newRecord = new MultiValueRecordLine(this,lineCounter) ;
			var fieldCounter = 0;
    		for(var i=0; i< inputDivs.length; i++) {
        		var element = inputDivs[i];
				var doesThisDivDefineField = inputDivs[i].getAttribute("af_mvf_field");
				if(doesThisDivDefineField) {
					fieldCounter++;
        			var name = element.id.split(mvSeparator)[2];
        			if(values != null){
	        			if(values[name] != null){
    	    				value = values[name];
	        			}
        				else{
        					value = mvfgeDefaultValue;
        				}
        			}
        			var varName = this.mvFieldGroup.pointer + "_" + (this.mvFieldGroup.maxCardinality + fieldGroupRecordIncrementer) + "_" + lineCounter + "_" + fieldCounter;
        			eval(varName + " = new MultiValueRecordElement(newRecord,name,fieldCounter,value,varName)");

//        			alert(eval(varName + ".name"));alert(eval(varName + ".pointer"));
				}
    		}
		}
	}
}

function intializeRecord() {
	for(var i=0; i<this.mvLines.length; i++) {
		this.mvLines[i].init();
	}
}

function updateMvRecordLines() {
	for(var i=0; i<this.mvLines.length; i++) {
		this.mvLines[i].updateContent();
	}
}

function deleteRecordAttachments(index) {
	for(var i=0; i<this.mvLines.length; i++) {
		this.mvLines[i].deleteAttachments(index);
	}
}

function updateRecordIndex(from, to) {
	this.index  = to;
	this.id     = this.mvFieldGroup.id   + mvSeparator + this.index;
	for(var i=0; i<this.mvLines.length; i++) {
		this.mvLines[i].updateIndex(from,to);
	}
}

function constructGroupDeleteLink() {	
	var span = document.createElement("SPAN");
	
	if(this.mvFieldGroup.deleteLinkHTML != '') {	
    	span.innerHTML = this.mvFieldGroup.deleteLinkHTML;
		/* fha replace href by onlick*/
    	span.childNodes[0].setAttribute("onclick", "javascript:"+this.mvFieldGroup.pointer+".deleteRecord("+this.index+");return false;");
		span.childNodes[0].setAttribute("href", "#");
	}
	return span;
}

function getRecordHTML(isLast) {
	var newhtml = "<table";
	if(isLast) {
		//fhassan: commented to fix field group records alignment.
		//newhtml += " style='margin-bottom:0px'";
	}
	newhtml += " class='record' cellspacing=0 cellpadding=0>\n";
	for(var i=0; i<this.mvLines.length; i++) {
		newhtml += "<tr><td class='input-cell'><span id='"+this.mvLines[i].id+"'>"+(this.mvLines[i].getHTML((i==this.mvLines.length-1)))+ "</span></td></tr>";				
	}
	newhtml += "</table>";
	return newhtml;
		
}
function appendLineToRecord(line) {
	this.mvLines[this.mvLines.length] = line;
}

/****************************************************/
/***** Field Group Record's Line Definition ******/
/****************************************************/
function MultiValueRecordLine(mvRecord, index) {
	this.mvRecord = mvRecord;
	this.mvElements = [];
	this.index  = index
	this.id     = this.mvRecord.id   + mvSeparator + this.index;
	
	this.add    = appendElementToLine;
	this.updateContent = updateMvLineElements;
	
	this.getHTML      = getLineHTML;
	
	this.deleteAttachments = deleteLineAttachments;
	
	this.updateIndex = updateLineIndex;	
	
	this.init = initializeLine;
	
	this.mvRecord.add(this);
}

function appendElementToLine(element) {
	this.mvElements[this.mvElements.length] = element;
}

function initializeLine() {
	for(var i=0; i<this.mvElements.length; i++) {
		this.mvElements[i].init();
	}
}

function updateMvLineElements() {
	for(var i=0; i<this.mvElements.length; i++) {
		this.mvElements[i].updateContent();
	}
}

function deleteLineAttachments(index) {
	for(var i=0; i<this.mvElements.length; i++) {
		if(this.mvElements[i].isPicker) {
			var deletionString = this.mvElements[i].deletionPrefix + '/' + addSlashes(encodeURIComponent(this.mvElements[i].value)) + this.mvElements[i].deletionSuffix + "&resultId=" + this.mvElements[i].pointer;
			this.mvElements[i].deleteValue(deletionString,index);
		}
	}
}

function updateLineIndex(from, to) {
	this.id     = this.mvRecord.id   + mvSeparator + this.index;
	for(var i=0; i<this.mvElements.length; i++) {
		this.mvElements[i].updateIndex(from,to);
	}
}

function getLineHTML(isLast) {
	var newhtml = "<table";
	if(isLast) {
		// if this is the last line in the record then we should disable the margin-bottom coming from the class recordline
		// since that there is already a bottom margin from the record table
		newhtml += " style='margin-bottom:0px'";
	}
	newhtml += " class='recordline' cellspacing=0 cellpadding=0><tr>\n";
	for(var i=0; i<this.mvElements.length; i++) {
		newhtml += "<td><div";
		if(this.mvElements[i].captionWidth != "") 
			newhtml += " style=\"width:" + this.mvElements[i].captionWidth + "px;\"";
		newhtml += ">";
		if(this.mvElements[i].captionText != "") 
			newhtml += this.mvElements[i].captionText;
		newhtml += "</div></td><td class='input-cell'><span id='"+this.mvElements[i].id+"'>"+ (this.mvElements[i].inputElement)+ "</span></td>";
	}
	newhtml += "</tr></table>";
	//alert(newhtml);
	return newhtml;
}



/****************************************************/
/***** Field Group Record's Element Definition ******/
/****************************************************/

function MultiValueRecordElement(mvLine, name, index, value, pointer) {
	this.mvLine = mvLine;
	this.name = name;
	this.index  = index;
	this.pointer = pointer;
	
	this.formId = this.mvLine.mvRecord.mvFieldGroup.formId;
	
	this.getTemplate = getInputTemplateDiv;
	
	this.defaultValue = getTemplateAttribute(this,"defaultValue");
	this.dockey = getTemplateAttribute(this,"dockey");
	this.formName = getTemplateAttribute(this,"formName");
	this.showThumbnailInstead = getTemplateAttribute(this,"showThumbnailInstead");
	this.hideDeleteButton = getTemplateAttribute(this,"hideDeleteButton");
	this.thumbnailField = getTemplateAttribute(this,"thumbnailField");
	this.usingAurigmaThumbnailSuffix = getTemplateAttribute(this,"usingAurigmaThumbnailSuffix");
	//this.thumbnailHeight = getTemplateAttribute(this,"thumbnailHeight");
	//this.thumbnailWidth = getTemplateAttribute(this,"thumbnailWidth");

	this.showThumbnailsInstead = getTemplateAttribute(this,"showThumbnailsInstead");
	this.value  = (value != null && value != ""?value:this.defaultValue);
	
	this.type = this.getTemplate().getAttribute("type");
	
	this.getFieldType = getFieldType;
	
	this.id     = this.mvLine.mvRecord.mvFieldGroup.id   + mvSeparator + this.name + mvSeparator + this.mvLine.mvRecord.index + mvSeparator + this.mvLine.index + mvSeparator;
	
	this.getMVInput = getMVInputGroup;
	
	/* get the HTML of the mv input according to the template; 
	   get it on the onload and update it using the updateIndex method 
	   can not recreate it every time (add/delete) the mv field is to be rendered
	   as to keep it's value as edited by the user */
	   
	this.inputElement = this.getMVInput();			
	
	/* called when a value is deleted to update this.index, this.id and any innerHTML that 
								   has mvSeparatorfield_namemvSeparator according to new position */
								   
	this.updateIndex = updateRecordElementIndex;	
	
	this.updateContent = updateElementContent;
	
	this.captionText = getTemplateAttribute(this,"captionText");
	this.captionWidth = getTemplateAttribute(this,"captionWidth");
	
	this.isPicker = isPickerField(this);
	this.onChange = "";
	this.deleteValue = deleteValue;
	
	this.setResult = setFieldGroupPickerResult;
	
	this.deletionPrefix = getTemplateAttribute(this,"deletionPrefix");
	this.deletionSuffix = getTemplateAttribute(this,"deletionSuffix");
	this.deleteLinkHTML = getTemplateAttribute(this,"deleteHTML");
	
	this.pickerURL = getTemplateAttribute(this,"pickerURL");
	this.pickerHTML = getTemplateAttribute(this,"pickerHTML");
	
	this.popupName = getTemplateAttribute(this,"popupName");
	this.popupHeight = getTemplateAttribute(this,"popupHeight");
	this.popupWidth = getTemplateAttribute(this,"popupWidth");
	this.popupProps = getTemplateAttribute(this,"popupProps");
	
	this.generateAttachmentPreviewLink = generateAttachmentPreviewLink;
	
	this.drawPickerHTML = drawPickerHTML;
	this.mvElements = [];
	this.expandHorizontal = 0;
	this.maxCardinality = 1;
	this.minCardinality = -1;
	this.isMemberOfFieldGroup = true;
	
	this.updateMvElements = updateFieldGroupMvElements;
	
	this.render = renderPicker;
	
	this.getIndex = getFieldIndexInFieldGroup;
	
	this.mvLine.add(this);
	
	this.init = intializeFieldGroupPicker;
	
}

function getFieldIndexInFieldGroup(index) {
	return this.mvField.mvLine.mvRecord.index;
}

function updateFieldGroupMvElements() {
	// for this case we will just reset the list
	this.mvElements = [];
	// reset the objet value
	this.value = "";
}

function intializeFieldGroupPicker() {
	if(this.isPicker) {
		var resultArray = new Array();
		var tmpArray = new Array();
		tmpArray[0] = this.value;
		tmpArray[1] = this.value;
		resultArray[0] = tmpArray;
		this.setResult(resultArray);
	}
}

function setFieldGroupPickerResult(jsResult) {
	//alert("setting remote result " + jsResult.length);
	// reset current selection
	this.mvElements = [];
	
	for(var s=0; s<jsResult.length; s++) {
		if(jsResult[s][0] != '')
			this.mvElements[s] = new PickerSelection(this, jsResult[s][0], jsResult[s][1], s+1);
	}
	this.render(this.mvLine.mvRecord.index -1);
}

function isPickerField(obj) {
	return (obj.getFieldType() == "PICKER");
}

function getTemplateAttribute(obj,attName) {
	var attValue = obj.getTemplate().getAttribute(attName);
	if(attValue) {
		attValue = attValue.replace(/@''@/g,"\"");
		return attValue;
	} else {
		return "";
	}
}

function getInputTemplateDiv() {
	return document.getElementById(this.mvLine.mvRecord.mvFieldGroup.id+mvSeparator+this.name+mvSeparator+"template");
}

function updateElementContent() {
	var fieldName = this.name + mvSeparator + this.mvLine.mvRecord.index + mvSeparator;
	var formId = this.mvLine.mvRecord.mvFieldGroup.formId;
	var formEln = document.getElementById(formId).elements[fieldName];
	if(this.getFieldType() == "RADIO") { // radio box field
		for(var i=0; i<formEln.length; i++) {
			if(formEln[i].checked) {
				this.value = formEln[i].value;
				break;
			}
		}
	} else if(this.getFieldType() == "TEXT" || this.getFieldType() == "TEXTAREA" ) { // text fields
		this.value = formEln.value;
	} else if(this.getFieldType() == "LIST") { // select box field
		this.value = formEln.value;
	} else if(this.getFieldType() == "PICKER") { // file attachments
		if(formEln != null)
			this.value = formEln.value;
	} else { 
		alert('This type is not supported yet :' + this.type);
	}
	this.inputElement = this.getMVInput();
}

function getMVInputGroup() {
	var template = this.getTemplate();
	var mvHTML = template.innerHTML;
	// replace the input name
	var reg = new RegExp("template" + mvSeparator + this.name,"g");
	mvHTML = mvHTML.replace(reg, this.name + mvSeparator + this.mvLine.mvRecord.index + mvSeparator);
	
	// replace [mvSeparator][field_name][mvSeparator] used for fields of type date or dav picker types
	var regdate = new RegExp(mvSeparator+"field_name"+mvSeparator,"g");
	mvHTML = mvHTML.replace(regdate, this.name + mvSeparator + this.mvLine.mvRecord.index + mvSeparator);
	
	// replace [formId][mvSeparator][field_name][mvSeparator][container] used for fields of type file attachment
	var regContainer = new RegExp(this.formId + mvSeparator+ this.name + mvSeparator + "container","g");
	mvHTML = mvHTML.replace(regContainer, this.id + mvSeparator + "container");
	
	var myelement = document.createElement("span");
	myelement.innerHTML = mvHTML;
	
	var inputs = myelement.getElementsByTagName("input");
	
	var textareas = myelement.getElementsByTagName("textarea");
	
	if(this.getFieldType() == "RADIO") { // this is a radio box field
		for(var i=0; i<inputs.length; i++) {
			var val = inputs[i].getAttribute("value");
			if (val != null && val == this.value) {
				if(is_ie) inputs[i].checked = true;
				if(is_gecko) inputs[i].setAttribute("checked","true");
			} else {
				// even if the template's options/radios are preselected we remove them here to make sure we have only 1 selected value
				if(is_ie) inputs[i].checked = false;
				if(is_gecko) inputs[i].removeAttribute("checked","false");
			}
            inputs[i].disabled = false;
		}		
	} else if(this.getFieldType() == "TEXT") { // this is a text field
        for(var i=0; i<inputs.length; i++) {
            var val = inputs[i].value;
            inputs[i].setAttribute("value", this.value);
            inputs[i].disabled = false;
        }
	} else if(this.getFieldType() == "LIST") { // this is a select box field
		var select = myelement.getElementsByTagName("select")[0];
        var name = select.name;
        if(name.indexOf(this.name) >=0) {
			// loop on options to find the correct one and preselect it
			for(var i=0; i < select.length; i++) {
				var option = select.options[i];
				if(option.value == this.value) {
					 if(is_ie) option.selected = true;		
					 if(is_gecko) option.setAttribute("selected","selected");	
				} else {
					 if(is_ie) option.selected = false;		
					 if(is_gecko) option.removeAttribute("selected",false);
				}
			}
        }
        select.disabled = false;
    } else if(this.getFieldType() == "PICKER" )	{
    	// here we are reconstructing the input html - nothing extra to do to the original template
    } else if(this.getFieldType() == "TEXTAREA" )	{
    	for(var i=0; i<textareas.length; i++) {
			textareas[i].value = this.value;//please do not change this to innerHTML since the \n wont work on IE
            textareas[i].disabled = false;
        }
	} else {
		alert('This type is not supported yet :' + this.type);
	}
	
	return myelement.innerHTML;
}

function updateRecordElementIndex(from, to) {	
	this.id     = this.mvLine.mvRecord.mvFieldGroup.id   + mvSeparator + this.name + mvSeparator + this.mvLine.mvRecord.index + mvSeparator + this.mvLine.index + mvSeparator;
	var reg = new RegExp(this.name+mvSeparator+from+mvSeparator,"g");
	this.inputElement = this.inputElement.replace(reg, this.name+mvSeparator+to+mvSeparator);
}

function getFieldType() {
	if(this.type == "4" || this.type == "radiobutton")
		return "RADIO";
	else if(this.type == "2" || this.type == "1" || this.type == "3" || this.type == "davPicker" || 
			this.type == "numeric" || this.type == "string" || this.type == "date")
		return "TEXT";
	else if(this.type == "6" || this.type == "listbox")
		return "LIST";
	else if(this.type == "fileAttachment" || this.type == "addressBook")
		return "PICKER";
	else if(this.type == "textarea" || this.type == "9") 
		return "TEXTAREA";
	return "";
}



/********************************************************************************************************************/
/************************************** Document Attachment Handler *************************************************/
/********************************************************************************************************************/


function DocumentAttachmentHandler(formId,options) {

	/**************************** class fields *************************************/
	this.allItems = [];
	this.selectedItems = [];
	
	this.formId = formId;
	this.options = options;
	
	if(isNaN(options.maxCardinality) || options.maxCardinality <= 0) 
		this.maxCardinality = 1;
	else 
		this.maxCardinality   = options.maxCardinality;

	if(isNaN(options.minCardinality) || options.minCardinality < 0) 
		this.minCardinality = 0;
	else 
		this.minCardinality   = options.minCardinality;
	
	this.expandHorizontal = options.expandHorizontal;
	this.deleteHtml = options.deleteHtml;
	this.pointer = options.pointer;
	
	this.fieldTitle = options.fieldTitle;
	
	this.varName = options.variableName; /* keep track of the current variable name */
	
	/*************************** private methods *********************************/
	
	
	this.generateSelection = generateSelectionAsString; 
	
	
	this.reverseUpdate = synchronizeCheckbox;
	
	
	this.deleteLink = builDeleteLink;
	
	
	this.getSelectedItemsCount = getCountSelected;
	
	
	this.getAllItemsCount = getCountAll;
	
	
	this.isSelected = checkIfItemSelected;
	
	
	this.removeFromList = removeItemFromList;
	
	
	this.render = renderSelection;
	
	this.updateIndicators = updateIndicators;
	
	/*************************** public methods *********************************/
	
	
	this.addSelected = addSelectedItem;
	
	
	this.addToAll	= addToAllItems;
	
	
	this.deleteItem = deleteItem;
	
		
	this.appendSelection = appendSelectionToForm;
	
	
	this.navigate = navigateToUrl;
	
	
	this.persist = persistSelecion;
	
	
	this.selectDeselectAll = selectDeselectAllPickerMode;
	
	
	this.selectDeselectOne = selectOnePickerMode;
	
	this.changeStyle = changeStyle;
}

function checkIfItemSelected(key) {
	return this.selectedItems[key] != null;
}

function removeItemFromList(list,item) {
	if(list[item] != null) {
		list[item] = null;
	}
}

function generateSelectionAsString() {
	var selectionAsString = ""; // string concatinated by ,;,
	for(selectedItem in this.selectedItems) {
		if(this.isSelected(selectedItem)) {
			selectionAsString = selectionAsString + ",;," + selectedItem;
		}
	}
	return selectionAsString;
}


function navigateToUrl(href) {
	var newhref = ""; 
	var selectionStr = this.generateSelection();
	if(href.indexOf('currentSelection') > 0) {
		var reg = new RegExp("currentSelection=[^&]*"); // get the parameter value
		newhref = href.replace(reg, "currentSelection=" + selectionStr);
		//alert("href already contains the currentSelection so replace it with the latest one \n" + newhref);
	} else if(href.indexOf('?') > 0) {
		newhref = href 	+ "&currentSelection=" + selectionStr;
		//alert("href doesnt contain currentSelection param but contains other params \n" + newhref);
	} else {
		newhref = href + "?currentSelection=" + selectionStr;
		//alert("href doesnt contain currentSelection param neither other params \n" + newhref);
	}
	window.location.href = newhref;
}
 
function appendSelectionToForm(form) {
	var elmt = form.elements['currentSelection'];
	elmt.value = this.generateSelection();
}


function selectDeselectAllPickerMode(state) {
	var selectors = document.getElementsByName("AF_documentSelector");
	var affectedItemsCount = 0;
	var error = false;
	for(var i =0; selectors!= null && i < selectors.length; i++) {
		if(!this.selectDeselectOne(selectors[i],state)) {
			error = true;
			break;
		} else {
			affectedItemsCount++;
		}
	}
	if(state) {
		// this is a check all event call , check it only when all items were added to selected (i.e. no error)
		return !error;
	} else {
		// this is an uncheck all event call, uncheck it only when at least 1 item was removed from the selected list (i.e. affectedItemsCount > 0)
		return (affectedItemsCount > 0);
	}
}

// forceState = true -> check the corresponding checkbox
// forceState = false -> uncheck the corresponding checkbox
// forceState = null -> this func is called from a click on a checkbox 
//                      thus take the state from the element itself
function selectOnePickerMode(elt,forceState){
	var key = elt.value;
	var actionSucceeded = true;
	// if forceState not null then we are forcing checking/unchecking (check all clicked!)
	if(forceState != null) 
		state = forceState;
	else
		state = elt.checked;
	if(state) {
		// user has checked an item so get caption from all items then add it to the selected items list
		actionSucceeded = this.addSelected(key,this.allItems[key]);
	} else {
		// user has un-checked an item so remove it from selected items if already exists there
		actionSucceeded = this.deleteItem(key,false);
	}
	if(actionSucceeded) {
		if(forceState != null)
			this.reverseUpdate(key,forceState);
		AF_selectOne(state);
		this.changeStyle(key,state);
		this.render();
	}
	return actionSucceeded;
}

function changeStyle(key,state) {
	var row = document.getElementById("row_" + key);
	//alert(key);alert(state);alert(row);
	if(row) {
		if(state) {
			row.className = "doc-selected";
		} else {
			row.className = "doc-not-selected";
		}
	}
}



function getCountSelected() {
	var count = 0;
	for(selectedItem in this.selectedItems) {
		if(this.isSelected(selectedItem))
			count++;
	}
	return count;
}

function getCountAll() {
	var count = 0;
	for(item in this.allItems) {
		if(this.allItems[selectedItem] != null)
			count++;
	}
	return count;
}



function builDeleteLink(key) {	
	var span = document.createElement("SPAN");
	
	if(this.deleteHtml != '') {	
    	span.innerHTML = this.deleteHtml;
		/* fha replace href by onlick*/
    	span.childNodes[0].setAttribute("onclick", "javascript:" + this.varName + ".deleteItem('"+key+"',true);return false;");
		span.childNodes[0].setAttribute("href", "#");
	}
	return span;
}


function deleteItem(key,sychCheckbox) {
	if(this.isSelected(key)) { // if selected remove it otherwise do nothing
		var count = this.getSelectedItemsCount();
		if(this.minCardinality != null && this.minCardinality >= count) {
			alert(formatMessage('Should have at least {0} value(s) for {1}',this.minCardinality,this.fieldTitle));
			return false;
		}
		this.removeFromList(this.selectedItems,key);
		if(sychCheckbox)
			this.reverseUpdate(key,false);
		this.changeStyle(key,false);
		AF_selectOne(false);
		this.render();
	}
	return true;
}


function persistSelecion() {
	var result = new Array();
	for(selectedItem in this.selectedItems) {
		if(this.isSelected(selectedItem)) {
			var tmpArray = new Array();
			tmpArray[0] = selectedItem;
			tmpArray[1] = this.selectedItems[selectedItem];
			result[result.length] = tmpArray;
		}
	}
	eval("window.opener." + this.pointer + ".setResult(result)");
	window.close();
}


function synchronizeCheckbox(key,checked) {
	var selectors = document.getElementsByName("AF_documentSelector");
	for(var i =0; selectors!= null && i < selectors.length; i++) {
		var ele = selectors[i];
		var removedKey = ele.value;
		if(removedKey == key) {
			ele.checked = checked
		}
	}
}

function addToAllItems(key,value) {
	this.allItems[key] = value;
}

function addSelectedItem(key,value) {
	if(!this.isSelected(key)) { // if not selected then add it
		var count = this.getSelectedItemsCount();
		//alert("count is = " + count + " - max cardinality = " + this.maxCardinality + " for [" + value + "]	");
		if(count  >= this.maxCardinality) {
			alert(formatMessage('Can not add more than {0} value(s) for {1}',this.maxCardinality,this.fieldTitle));
			return false;
		}
		this.selectedItems[key] = value;
	}
	return true;
}
/*
function renderSelection() {
	var abcontainer = document.getElementById("selcontainer");
	abcontainer.innerHTML = "";
	var newhtml = "<table class='docs-container'><tr>\n";
	var i = 0;
	var selectedItemsCount = this.getSelectedItemsCount();
	if(selectedItemsCount > 0) {
		for(selectedItem in this.selectedItems) {
			if(!this.isSelected(selectedItem)) {
				continue;
			}
			newhtml += "<td class='docs-container-border'>"+ this.selectedItems[selectedItem] + "&nbsp;" + this.deleteLink(selectedItem).innerHTML +"</td>";
			
			//add empty cells till we reach the expandHorizontal
			if(i==selectedItemsCount-1) {
				var remainingCellCount = (this.expandHorizontal - selectedItemsCount % this.expandHorizontal)%this.expandHorizontal;
				for(var j=1; j <= remainingCellCount;j++) {
					newhtml += "<td class='docs-container-borderless'></td>"
				}
			}		
			if(i+1 < selectedItemsCount)
				if((i+1) % this.expandHorizontal == 0) 
					newhtml += "</tr><tr>\n";
			i++;
		}
	} else {
		newhtml +="<td class='docs-container-border'>" + formatMessage('You are allowed to add at least {0} item(s) and at max {1} item(s)',this.minCardinality,this.maxCardinality)+ "</td>";
	}
	newhtml += "</tr></table></td>\n";
	abcontainer.innerHTML = newhtml;
	
	this.updateIndicators();
}
*/
function renderSelection() {
	var abcontainer = document.getElementById("selcontainer");
	abcontainer.innerHTML = "";
	var selectedItemsCount = this.getSelectedItemsCount();
	if(selectedItemsCount > 0) {
		var newhtml = "<table class='docs-container'><tr>\n";
		var i = 0;
		for(selectedItem in this.selectedItems) {
			if(!this.isSelected(selectedItem)) {
				continue;
			}
			newhtml += "<td class='docs-container-border'>"+ this.selectedItems[selectedItem] + "&nbsp;" + this.deleteLink(selectedItem).innerHTML +"</td>";
			
			//add empty cells till we reach the expandHorizontal
			if(i==selectedItemsCount-1) {
				var remainingCellCount = (this.expandHorizontal - selectedItemsCount % this.expandHorizontal)%this.expandHorizontal;
				for(var j=1; j <= remainingCellCount;j++) {
					newhtml += "<td class='docs-container-borderless'></td>"
				}
			}		
			if(i+1 < selectedItemsCount)
				if((i+1) % this.expandHorizontal == 0) 
					newhtml += "</tr><tr>\n";
			i++;
		}
		newhtml += "</tr></table></td>\n";
	} else {
		newhtml = "<span class='docAttach_selectionMsg'>" + formatMessage('You are allowed to add at least {0} item(s) and at max {1} item(s)',this.minCardinality,this.maxCardinality)+ "</span>";
	}
	abcontainer.innerHTML = newhtml;
	this.updateIndicators();
}

function updateIndicators() {
	var counterContainer = document.getElementById("docAttach_counterMsg");
	if(counterContainer)
		counterContainer.innerHTML = formatMessage('{0} out of {1}',this.getSelectedItemsCount(),this.maxCardinality);
}
