/**
*		XMLRequest
*
*	Object to submit, recieve and parse xml.
*
*	Pass asynch flag to set whether this object will access data 
*	from server asynchronously, default is true.
*	 
*/


function XMLRequest(container,url,asynch){
	//	Establish superclass and inherit methods, StageElement contains 
	//	helper methods for objects that work with the screen
	this.inheritFrom = StageElement;
	this.inheritFrom(container);
	
	this.id="XMLRequest";
	
	this.loadingMessage="<p><b>Loading data, please wait...</b></p>";
	
	//	Url to post data to
	this.url=url;
	
	this.target=null;
	this.callbacks={};
	
	this.requestQue=null;
	
	this.sendTimeout=null;
	
	this.dataDef=null;
	this.request=null;
	
	//	Variable that holds parameter string and 
	//	param count before submittal
	this.params="";
	this.paramsLen=0;
	
	//	Sets whether the response content
	//	logged and available in the debug window
	this.debugResponse=false;
	
	//	Sets whether when/if the contents of the response 
	//	are inserted into an existing tag, the response is 
	//	inserted as xml, or as html/string, response can
	//	then be formatted with xsl stylesheet defined by
	//	server.
	this.insertAsXml=true;
	
	//	Default return type from server is xml
	this.dataType="xml";
	
	this.attempts = 0;
	this.maxAttempts = 3;
	
	if(!asynch){this.asynch = true;}
	else {this.asynch = false;}
	
	this.send=xmlrequest_send;
	this.createAndSend=xmlrequest_createAndSend;
	this.cancel=xmlrequest_cancel;
	this.onload=xmlrequest_onload;
	this.failedLoad=xmlrequest_failedLoad;
	this.retryLoad=xmlrequest_retryLoad;
	this.processXmlResponse=xmlrequest_processXmlResponse;
	this.processHtmlResponse=xmlrequest_processHtmlResponse;
	this.clearTarget=xmlrequest_clearTarget;
	this.clearFormField=xmlrequest_clearFormField;
	this.getDataAsObject=xmlrequest_getDataAsObject;
	this.parseDataObj_List=xmlrequest_parseDataObj_List;
	this.parseNode=xmlrequest_parseNode;
	this.parseDataObj_Map=xmlrequest_parseDataObj_Map;
	this.parseDataObj_String=xmlrequest_parseDataObj_String;
	this.getFirstXmlEleOfType=xmlrequest_getFirstXmlEleOfType;
	this.loadDataIntoForm=xmlrequest_loadDataIntoForm;
	this.loadDataIntoField=xmlrequest_loadDataIntoField;
	this.loadDataIntoSelect=xmlrequest_loadDataIntoSelect;
	this.setTarget=xmlrequest_setTarget;
	this.addCallback=xmlrequest_addCallback;
	this.broadcastEvent=xmlrequest_broadcastEvent;
	this.setDebugResponse=xmlrequest_setDebugResponse;
	this.buildParamStr=xmlrequest_buildParamStr;
	this.setDataDefinition=xmlrequest_setDataDefinition;
	this.addParamValue=xmlrequest_addParamValue;
	this.setDataType=xmlrequest_setDataType;
	this.getXmlRequestObj=getXmlRequestObj=xmlrequest_getXmlRequestObj;
	
	//	Create array variable for xml req objects in doc,
	//	unless variable already exists, then add reference to 
	//	this req object to array
	if(!document._xmlReqRegistry){document._xmlReqRegistry=new Array();}
	this.id=document._xmlReqRegistry.length;
	document._xmlReqRegistry[this.id]=this;
	
	//	load xmlhttprequest object
	this.request=this.getXmlRequestObj();
}	//	XMLRequestClass


/**
*	send
*	
*	Configures the data contained in the associative array data
*	and this object's data definition, then calls createAndSend() 
*	to create the xml request object and send to the server, 
*	this object will then parse it when it returns, and do the 
*	actions in the onload function after parsing.
*/
function xmlrequest_send(data){
	if((typeof this.request=="object") && (this.request.readyState > 0) && (this.request.readyState < 4)){
		this.log.info("Submitting to " + this.url + " when previous attempt not finished, queing new request.");
		this.requestQue = {data:data};
		return;
		//this.log.warn("Submitting to " + this.url + " when previous attempt not finished, aborting previous attempt and continueing with this send.");
		//this.cancel();
		}
	this.log.info("----------- Send begin to url " + this.url + "-----------"); 
	
	this.clearTarget();
	this.attempts=0;
	
	//	Build params string starting with passed data
	if(data){
		//this.log.debug(" ---Adding passed data " + data + " to params...");
		this.buildParamStr(data);
	}
	//	Add in any data defined in data definition
	if(this.dataDef&&(typeof this.dataDef=="object")){
		if(this.dataDef.contants){this.buildParamStr(this.dataDef.constants);}
		if(this.dataDef.objects){
			for(obj in this.dataDef.objects){
				this.buildParamStr(this.dataDef.objects[obj]);
				}
			}
		if(this.dataDef.forms){
			for(obj in this.dataDef.forms){
				this.log.debug("Adding values for form "+ obj + " in data def ----- ");
				this.buildParamStr(this.dataDef.forms[obj]);
				}
			}
		}
	this.createAndSend();
}	//	send


function xmlrequest_createAndSend(){
	this.broadcastEvent("beginload");
	
	if(!this.request){this.getXmlRequestObj();}
	
	//alert("Sending with params : " + this.params);
	
	this.request.open('POST', this.url, true);
	this.request.onreadystatechange=new Function("document._xmlReqRegistry["+this.id+"].onload();");
    this.request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    this.request.setRequestHeader("Content-length", this.paramsLen);
    this.request.setRequestHeader("Connection", "close");
    
    this.log.info("\n-----------\nXML Request Sending to: " + this.url + " \nwith params= " + this.params + "\n-----------");
    
    this.request.send(this.params);
    this.attempts++;
    //	Clear params
    this.params="";
    this.paramsLen=0;
}	//	createAndSend

/**
*	cancel
*	Aborts xmlrequest
*/
function xmlrequest_cancel(){
	if(typeof this.request=="object"){
		this.log.warn("Canceling request " + this.url);
		this.request.abort();
		//this.target = null;
		this.request == null;
		}
}	//	cancel

/**
*	onload
*	Called when response has come back from request, processes response
*	and handles the response based on the value of the target property.
*/
function xmlrequest_onload(){
	if(this.request.readyState == 4) {
		var status=null;
        // only if "OK"
        try{status=this.request.status}
        catch(e){this.log.error("Error occurred in xml req " + this.url + ", could not get status from request object.");}
        
        this.log.info("Returned response for " + this.url+", dataType=" + this.dataType +", status = " + status);
        if(status == 200) {
        	//	if another request has been queued, do 
        	//	not process this one, just send next one
        	if(this.requestQue != null){
        		this.log.info("Another request queued, sending queued request...");
        		this.send(this.requestQue.data);
        		this.requestQue=null;
        		return;
        		}
        	if(this.dataType=="xml"){
        		//var test=this.request.responseText.replace(/</g,'&lt;');
        		//test=test.replace(/>/g,"&gt;");
        		//test=test.replace(/$/g,"<br>");
        		//this.log.debug(test);
        		this.processXmlResponse();
        	}
        	else if(this.dataType=="html"){
        		//alert(this.request.responseText);
        		this.processHtmlResponse();
        	}
        	else {
	        	this.broadcastEvent("onerror");
        		this.log.error("Don't know how to handle data type " + this.dataType + " for request " + this.url + ", skipping response.");
        		}
        	this.broadcastEvent("onload");
        	}
        else {
       		
			//this.broadcastEvent("onerror");
			
            this.log.warn("There was a problem retrieving the XML data for url " + this.url);
            this.failedLoad();
        	}
    	}
}	//	onload

/**
*	failedLoad
*	Called when a load returns an error, to handle error, will retry 
* 	request if attempts < maxAttempts.
*/
function xmlrequest_failedLoad(){
	this.log.warn("Submit failed with " + this.attempts + "  out of " + this.maxAttempts + " tries.");
	
	if(this.attempts < this.maxAttempts){
		this.log.warn("Submit failed, submitting attempt " + this.attempts);
		this.cancel();
		var retryHold="_ajaxRetry";
		this.log.debug("Saving reference in variable " +  retryHold);
		document[retryHold]=this;
		window.setTimeout("document."+retryHold+".retryLoad();",4200);
		}
	else{
		this.broadcastEvent("onerror");
		this.log.error("Error: Could not load data from " + this.url + " after " + this.maxAttempts + " tries. Canceling.");
		}
}	//	failedLoad

function xmlrequest_retryLoad(){
	if(this.attempts >= this.maxAttempts){return;}
	this.log.info("Retrying ajax submit to " + this.url + ", attempt " + this.attempts);
	this.createAndSend();
}


/**
*	processXmlResponse
*/
function xmlrequest_processXmlResponse(){
	var response=this.request.responseXML;
	var message=response.getElementsByTagName('message')[0].firstChild.data;
	var success=response.getElementsByTagName('status')[0].firstChild.data;
    
    this.log.info("\n-----------\nXML Request Received from: " + this.url + "\n  Status: " + this.request.status + "\n  Status text="+this.request.statusText + "\n  Success = " + success + "\n  message text="+ message +"\n-----------" );
    
    if(success == "false"){
    	this.log.error("XML Request returned failed status, message returned in xml is " + message);
    	this.failedLoad();
    	}
    
    if(typeof this.target == "string"){
		//	Try to find target one last time
		this.setTarget(this.target);
		}
	if(!this.target || (typeof this.target!="object")){this.log.warn("No target for response returned, ignoring response.");return;}
    
	if(this.target){
		if(typeof this.target=="object"){
			var xmldata=response.getElementsByTagName('data')[0];
			//this.log.debug("processXmlResponse() target tagname= " + this.target.tagName);
			if(this.target.tagName){
				switch(this.target.tagName.toLowerCase()){
					case "form":
						this.loadDataIntoForm(this.target,this.parseNode(this.getFirstXmlEleOfType(xmldata,"map")));
						break;
					case "input":
						this.loadDataIntoField(this.target,this.parseNode(this.getFirstXmlEleOfType(xmldata,"string")),true);
						break;
					case "select":
						//	See if there is a default selected element
						var selected=this.parseNode(this.getFirstXmlEleOfType(xmldata,"string"));
						this.log.debug(" ==== processXmlResponse() selected = " + selected);
						this.loadDataIntoSelect(this.target,this.parseNode(this.getFirstXmlEleOfType(xmldata,"list")),true,selected);
						break;
					case "div":
					case "span":
					case "p":
						//prompt("","response target is an html element = " + this.request.responseText);
						//	simply write content of first string data element to html element
						this.target.innerHTML=this.parseNode(this.getFirstXmlEleOfType(xmldata,"string"));
						break;
					default:
						this.log.warn("Couldn't find target object for url " + this.url + ", ignoring response.");
					}
				}
				else{
					//	Need to add handling of object targets, defining several objects
					//	on screen to receive matching elements from the returned data
					}
				}
		else {this.log.error("Target is not object or function for url " + this.url + ", ignoring response.");}
	}
}	//	processXmlResponse


/**
*	processHtmlResponse
*/
function xmlrequest_processHtmlResponse(response){
	
	this.log.info("\n-----------\nHTL Request Received: Status: " + this.request.status + "\n  Status text="+this.request.statusText + "\n -----------" );
	
	if(typeof this.target == "string"){
		//	Try to find target one last time
		this.setTarget(this.target);
		}
	if(!this.target || (typeof this.target!="object")){this.log.warn("No target for response returned, ignoring response for url=" + this.url + ", target="+this.target);return;}
	var text=this.request.responseText;
	
	if(this.target.tagName){
		switch(this.target.tagName.toLowerCase()){
			case "div":
			case "span":
			case "p":
				//this.log.info("Adding " + text.substring(0,50) + " to " + this.target.innerHTML.substring(0,50));
				if(this.request!=null){this.target.innerHTML=text;}
				break;
			}
		}
}	//	processHtmlResponse


/**
*	clearTarget
*	Called to clear a target while processing a request, if target is 
*	defined, this method is called from send function.
*/
function xmlrequest_clearTarget(){
	if(!this.target || (typeof this.target!="object")){this.log.warn("Can't clear target, no target defined or is null.");return;}
	//this.log.debug("Clearing target object " + this.target + " with tagname " + this.target.tagName);
	if(this.target.tagName){
		switch(this.target.tagName.toLowerCase()){
			case "form":
				for(var i=0; i<this.target.elements.length; i++){
					this.clearFormField(this.target.elements[i]);
					}
				break;
			case "input":
			case "select":
				this.clearFormField(this.target);
				break;
			case "div":
			case "span":
			case "p":
				//this.target.innerHTML=this.loadingMessage;
				break;
			}
		}
}	//	clearTarget

/**
*	clearFormField
*	Helper function for clearTarget, clears the form field
*	that is passed as field.
*/
function xmlrequest_clearFormField(field){
	if(field.options){
		field.options.length=0;
		field.options[0] = new Option("Loading...","");
		}
	else if(field.value){
		field.value="";
		}
	this.log.info("Cleared " + field.name);
	//	Revalidate field to make sure its marked as incomplete
	if(typeof handler == "object"){
		handler.validateField(field.form.name,field.name,false,false);
		}
}	//	clearFormField


/**
*	getDataAsObject
*	Gets the contents of the returned xml data element as a javascript
*	tree structure, converting hashes, lists, and strings as needed.
*/
function xmlrequest_getDataAsObject(xmldata){
	//	Get data element (1st item of array of elements named 'data'
	var xmldata=response.getElementsByTagName('data')[0];
	return this.parseDataObj_List(xmldata);
}	//	getDataAsObject


/**
*	parseDataObjList
*/
function xmlrequest_parseDataObj_List(xmldata){
	//this.log.debug("Have list = " + typeof xmldata.childNodes);
	var xmleles=xmldata.childNodes;
	var jsdata={};
	for(var i=0; i<xmleles.length; i++){
		if(xmleles[i].nodeType==1){
			var id=((xmleles[i].attributes.getNamedItem("id"))?(xmleles[i].attributes.getNamedItem("id")).nodeValue:i);
			jsdata[id]=this.parseNode(xmleles[i],jsdata);
			}
		}
	return jsdata;
}	//	parseDataObjList


/**
*	parseNode
*/
function xmlrequest_parseNode(xmldata){
	if((xmldata==null) || (xmldata.attributes.getNamedItem("type") == null)){
		this.log.error("parseNode() While parsing xml node '" + xmldata + "' could not find 'type' attribute.");return;
		}
	//this.log.debug("parse node with " + xmldata.getAttribute("type"));
	switch(xmldata.getAttribute("type")){
		case "list":
			return this.parseDataObj_List(xmldata);
			break;
		case "map":
			return this.parseDataObj_Map(xmldata);
			break;
		default: //string or anything else
			return this.parseDataObj_String(xmldata);;
			break;
	}
	return null;
}	//	parseNode


/**
*	parseDataObj_Map
*/
function xmlrequest_parseDataObj_Map(xmldata){
	//this.log.debug("have map");
	var xmlele=xmldata.childNodes;
	var jsdata={};
	for(var i=0; i<xmlele.length; i++){
		if(xmlele[i].nodeType==1){
			var key=xmlele[i].tagName;
			var value=this.parseDataObj_String(xmlele[i]);
			//this.log.debug("found " + key + " : " + value);
			jsdata[key]=value;
			}
		}
	return jsdata;
}	//	parseDataObj_Map

/**
*	parseDataObj_String
*/
function xmlrequest_parseDataObj_String(xmldata){
	//this.log.debug("String first child node name is " + xmldata.firstChild.nodeName + ", node type is " + xmldata.firstChild.nodeType);
	if(xmldata.firstChild.hasChildNodes()){
		return xmldata.firstChild.firstChild.nodeValue;
	}
	return xmldata.firstChild.nodeValue;
}	//	parseDataObj_String


/**
*	getFirstXmlEleOfType
*	Shortcut method, returns the first data element 
*	that matches the specified type.
*/
function xmlrequest_getFirstXmlEleOfType(xmldata, type){
	if((typeof xmldata !="object") || (xmldata.nodeType!=1)){/*this.log.warn("Don't have element node, quiting.");*/return null;}
	var node=null;
	if(xmldata.getAttribute("type")==type){
		//this.log.debug("first Data element " + typeof xmldata + ", that matches " + type + " is " + xmldata.getAttribute("id"));
		return xmldata;
		}
	var xmlele=xmldata.childNodes;
	for(var i=0; i<xmlele.length; i++){
		if(xmlele[i].nodeType==1){
			var node=this.getFirstXmlEleOfType(xmlele[i], type);
			if(node!=null){break;}
			}
		}
	return node;
}	//	getFirstXmlEleOfType


/**
*	loadDataIntoForm
*/
function xmlrequest_loadDataIntoForm(form,data){
	//this.log.debug("data loading into form " + form.id);
	for(ele in data){
		if(form[ele]){
			if(form[ele].tagName=="select"){
				this.loadDataIntoSelect(form[ele],data[ele],false);
				}
			else{
				this.loadDataIntoField(form[ele],data[ele],false);
				}
			}
		else {this.log.warn("Couldn't find form element " + ele + " in form " + form.id + ", skipping element.");}
	}
	if([handler]){handler.isComplete(form.id,null,true,false);}
	//this.log.debug("data loaded into form.");
}	//	loadDataIntoForm 


/**
*	loadDataIntoField
*/
function xmlrequest_loadDataIntoField(field,data,fireChange){
	field.value=data;
	if(fireChange&&field.onchange){
		var codeVal="document.forms."+field.form.name+"['"+field.name+"'].onchange();";
		//this.log.debug("Calling field.onchange with " + codeVal);
		var timeout=window.setTimeout(codeVal,1000);
		}
}	//	loadDataIntoField


/**
*	loadDataIntoSelect
*/
function xmlrequest_loadDataIntoSelect(select,data,fireChange,selectValue){
	//this.log.debug("Loading data " + data + " into select object " + select);
	select.options.length=0;
	//select.options[0]=new Option("select a county","");
	for(opt in data){
		select.options[select.options.length]=new Option(data[opt].text,data[opt].value,null,((selectValue==data[opt].value)?true:false));
		}
	select.disabled=false;
	if(fireChange&&select.onchange){
		//select.onchange();
		var codeVal="document.forms."+select.form.name+"['"+select.name+"'].onchange();";
		//this.log.debug("Calling select.onchange with " + codeVal);
		var timeout=window.setTimeout(codeVal,300);
		
		}
}	//	loadDataIntoSelect


/**
*	setTarget
*	Sets a target definition for request, this determines how the
*	data will be handled when it is returned. 
*/
function xmlrequest_setTarget(targetName){
	//	if target is string, see if we can find a screen
	//	element to match
	//this.log.debug(" --- typeof [targetName] for " + targetName + " = " + typeof [targetName]);
	if(typeof targetName=="object"){target=targetName;}
	if(typeof targetName=="string"){
		target=this.findObj(targetName);
		}
	//	If we don't have an object yet, skip
	if(typeof target!="object"){
		this.log.warn("Could not find the target " + targetName + ", found " + (target?target:"undefined") + ", saving target name will try again after loading");
		this.target = targetName;
		return;
	}
	
	this.target=target;	
}	//	setTarget
	
/**
*	addCallback
*	Adds a callback function that will be called when the specified event
*	occurs, the allowed actions are "onload", "beginload", and "onerror".
*	If a callback other than those allowed are specified, no error is reported,
*	the event might not be called. If params object is passed, it will be saved
*	and returned to the event callback handler as the second parameter.
*/
function xmlrequest_addCallback(event,functionObj,params){
	if(!this.callbacks[event]){
		this.callbacks[event]=new Array();
		}
	//this.log.info("adding event " +event);
	this.callbacks[event].push({fun:functionObj,params:params});
}	//	addCallback

/**
*	broadcastEvent
*	Broadcast events to functions passed to addCallback, or to objects
*	passed that have methods of the same name as the event.
*/
function xmlrequest_broadcastEvent(event){
	if((typeof this.callbacks[event]=="object")&&this.callbacks[event].length){
		this.log.info("broadcasting event "  + event + " to " + this.callbacks[event].length + " callback handlers.");
		for(var i=0; i<this.callbacks[event].length; i++){
			//this.log.info("call back function is " + typeof this.callbacks[event][i].fun + " params object is " + typeof this.callbacks[event][i].params);
			switch(typeof this.callbacks[event][i].fun){
				case "function":
					this.callbacks[event][i].fun(this,this.callbacks[event][i].params);
					break;
				case "object":
					//this.log.debug("broadcasting to object");
					if(typeof this.callbacks[event][i].fun[event]=="function"){
						this.callbacks[event][i].fun[event](this,this.callbacks[event][i].params);
						}
					break;
				default:
					this.log.error("The callback object #"+ i + " for event " + event + " wasn't a function or object, skipping callback.");
				}
			}
		}
}	//	broadcastEvent


/**
*	setDebugResponse
*	Controls whether the response is logged to the debug window.
*/
function xmlrequest_setDebugResponse(debug){
	this.debugResponse=debug;
}	//	setDebugResponse


/**
*	buildParamStr
*	Builds the parameter data needed for submitting the request,
*	by cycling through the passed data object and calling the 
*	addParamValue function to add the data to this objects params string.
*	The passed data may be a simple string, form object, individual field, 
*	associative array, or a reference to any htmlElement. If it is a
*	form the values of the form fields will be added to params, if its a 
*	string or an htmlElement with an id, one param named "data" will  
*	be added, which will be the value of the string or id of the html 
*	element (to support 'click'ing or other interaction with screen elements
*	causing data to be posted/returned from server), if it is a assoc. array, 
*	key/value pairs will be added, if it is a htmlElement, and doesn't have an 
*	id,	the html contents of the html element will be added (using innerHtml).
*	See notes on setDataDefinition();
*/
function xmlrequest_buildParamStr(data,id){
	if(typeof data=="string"){
		if(!id){id="data";}
		this.addParamValue(id,data);
		return;
		}
	else if(!data||(typeof data!="object")){this.log.error("buildParamStr() Data is not an object, can not add to parameters.");return;}
	if(data.tagName){
		//this.log.debug("Adding data for " + data.tagName);
		if(data.tagName.toLowerCase()=="form"){
			var elements=data.elements;
			//	step through form fields and add their values
			for(var i=0; i<elements.length; i++){
				var inp=elements[i];
				//this.log.debug("Adding field " + inp.name);
				if(inp.value){
					this.addParamValue(inp.name,inp.value);
					}
				else if(inp.tagName=="select"){
					this.addParamValue(inp.name,inp.options[inp.selectedIndex].value);
					}
				}
			}
		else if(data.tagName.toLowerCase()=="select"){
			//this.log.debug("Adding select value for " + data.name);
			this.addParamValue(data.name,data.options[data.selectedIndex].value);
			}
		else if(data.value){
			//this.log.debug("Adding field value for " + data.name);
			this.addParamValue(data.name,data.value);
			}
		else if(data.id){
			this.addParamValue("data",data.id);
			}
		else if(data.innerHtml){
			this.addParamValue(data.tagName,data.innerHtml);
			}
		}
	else{
		//	Assume a generic data object and pass parameter 
		//	values as param string
		for(ele in data){this.buildParamStr(data[ele],ele);}
		}
}	//	buildParamStr


/**
*	setDataDefinition 
*	This method sets a data definition object for this
*	request object, which defines some values to be submitted
*	whenever this object is submitted. This object can be 
*	string id's of objects on the page, or fixed name/value
*	pairs to be included with the submittal. If id's of page
*	items, the references will be resolved with findObj, and
*	references will be saved, then when submitted, the values
*	of these objects will be obtained and submitted with any
*	other data that is passed. The data definition should be
*	an object, with the optional properties:
*		.constants  An object containing name/value pairs of 
*					fixed values to be submitted.
*		.objects	Screen objects to be resolved, which will
*					be sent to buildParamStr() at submittal
*		.forms		Object whose properties are named for the
*					forms id's, that contain objects whose
*					properties are fields whose values need to
*					be obtained. form/fields will be resolved to
*					references, and values will be obtained at
*					submittal time.
*	Sample data structure:
*		definition:{
*			constants:{key1:"value1"},
*			objects:{divId1:null,paragraphId2:null},
*			forms:{
*				myForm:{
*					myFormFieldId1:null,
*					myFormFieldId2:null
*					}
*				}
*			}
*/
function xmlrequest_setDataDefinition(dataDef){
	if(!dataDef||(typeof dataDef!="object")){return;}
	//	any fixed values in constants don't need processing
	if(dataDef.objects){
		//	Cycle through and get and save references to objects
		for(obj in dataDef.objects){
			dataDef.objects[obj]=this.findObj(document,obj);
			}
		}
	if(dataDef.forms){
		//	Cycle through forms and get references to named fields
		for(f in dataDef.forms){
			var fData=dataDef.forms[f];
			//	find form
			var formRef=this.container[f];
			if((formRef===null)||(formRef.tagName.toLowerCase()!="form")){
				this.log.warn("Couldn't find form " + f + " : " + formRef.tagName + " in XMLRequestClass data definition, found " +formRef + ", skipping form.");
				continue;
				}
			//this.log.debug("form Ref = " + formRef);
			//	If form data is null, then get whole form
			if(fData==null){dataDef.forms[f]=formRef;}
			else {
				//	Cycle through fields listed in form def, and get references
				//	to cooresponding fields in form element
				for(fld in fData){
					fldname=fld.replace("_",".");
					if(formRef[fldname]){fData[fld]=formRef[fldname];}
					else{this.log.warn("Couldn't find form field " + fldname + " in form " + f + " for XMLRequestClass data definition, skipping field.");}
					}
				}
			}
		}
	this.dataDef=dataDef;
}	//	setDataDefinition


/**
*	addParamValue
*	Helper function called from buildParamStr to build
*	and incode one param name value pair and save to 
*	params string .If passed params is not empty, it adds 
*	the needed "&" to separate the values, also increments
*	the paramsLen counter.
*/
function xmlrequest_addParamValue(key,value){
	if(this.params!=""){this.params+="&";}
	this.params+=key+"="+escape(value);
	this.paramsLen++;
}	//	addParamValue


/**
*	setDataType
*	Sets the data type that will be returned from server, 
*	default is xml, may also be set to html.
*/
function xmlrequest_setDataType(dataType){
	this.dataType=dataType.toLowerCase();
}	//	setDataType

/**
*	getXmlRequestObj
*	Creates the XMLHttpRequest object for this object, or null if can't create one.
*/
function xmlrequest_getXmlRequestObj(){
	// gecko, konquer, safari
	if (window.XMLHttpRequest) {
		this.request = new XMLHttpRequest();
		this.request.parent=this;
		if (this.request.overrideMimeType) {
			// Set mime type to xml as default, html if not xml
			if(this.dataType=="xml")this.request.overrideMimeType('text/xml');
			else if(this.dataType=="html")this.request.overrideMimeType('text/html');
			else this.request.overrideMimeType(this.dataType);
		}
	}
	//	For ie
	else if (window.ActiveXObject) {
		try{this.request = new ActiveXObject("Msxml2.XMLHTTP");}
		catch(e){
			try{this.request = new ActiveXObject("Microsoft.XMLHTTP");}
			catch(e){
				this.log.fatal("getXmlRequestObj() Can't create request object for Internet Explorer, system error.  Browser id= " + window.navigator.userAgent);
				}
			}
	}
}	//	getXmlRequestObj
