// utility functions
function makeAssocArray(indArray) {
	retArray = new Array();
	for (ai=0;ai<indArray.length;ai+=2) {
		retArray[indArray[ai].toString()] = indArray[ai+1].toString();
		}
	return retArray;
	}

// simple XML implementation
// XML ELEMENT OBJECT
function ELEMENT(name,attrib,cont) {
	// properties
	this.name = name;
	this.nodeType = 1;
	this.attributes = makeAssocArray(attrib);
	this.attribList = attrib;
	this.contentArray = new Array(cont); // cont is a string
	this.depth = 0;
	this.text = "";
	// collections
	this.children = new Array();	
	// methods
	this.addElement = addElement;
	this.addAttributes = addAttributes;
	this.toXML = toXML;
	this.toText = toText;
	this.clone = clone;
	}
function addElement(elem) { //elem should be an ELEMENT object or XML as a plain text string
	if (elem.toString().indexOf("[object") == 0) { // we've been passed an object
		this.contentArray[this.contentArray.length] = elem.toXML();
		this.children[this.children.length] = elem;
		}
	else if (elem.toString().indexOf("<") == 0) { // we've been passed an XML tag as a text string
		this.contentArray[this.contentArray.length] = elem; 
		//this.children[this.children.length] = this.parseXML(elem);
		this.children[this.children.length] = parseXML(elem);
		}
	else { // we've been passed plain text
		this.text += elem;
		this.contentArray[this.contentArray.length] = elem;
		}
	}
function addAttributes(indArray) {
	this.attribList = (this.attribList.length>0)?(this.attribList.join('"')+'"'+indArray.join('"')).split('"'):indArray.join('"').split('"');
	this.attributes = makeAssocArray(this.attribList);
	}
function toXML() {
	var str='';
	if (this.nodeType==9) {	str+='<?xml version="1.0"?>';}
	str+='<'+this.name;
	if (this.attribList.length>0) { for(i=0;i<this.attribList.length;i+=2) { str+=" "+this.attribList[i]+"=\""+this.attribList[i+1]+"\""; } }
	if (this.contentArray[0]==null) { str +="/>"; }
	else { str +=">"+this.contentArray.join("")+"</"+this.name+">"; }
	return str;
	}
function toText() {
	return this.text;
	}
function clone() {
	retElem = new ELEMENT(this.name,this.attribList,this.content)
	}
	

function parseXML(xmlstr) {
	var offset = 0;
	var depth = 0;
	var DOC = new ELEMENT('DOC',new Array(),xmlstr);
	DOC.parent = DOC;
	DOC.nodeType = 9;
	var thiselem = null;
	var curParent = DOC;
	while (offset!=-1) {
		if (xmlstr.charAt(offset)!='<') {
			thiselem.text += xmlstr.substring(offset,xmlstr.indexOf('<',offset));
			// I would seem to need the following line to add text nodes, but it produces duplicate element nodes in the contentArray
			//thiselem.contentArray[thiselem.contentArray.length] = xmlstr.substring(offset,xmlstr.indexOf('<',offset));
			offset = xmlstr.indexOf('<',offset);
			}
		else if (xmlstr.charAt(offset+1) == '/') {
			curParent = thiselem.parent;
			thiselem = curParent;
			--depth;
			offset = xmlstr.indexOf('>',offset)+1;
			}
		else if (xmlstr.charAt(offset+1) == '?') {
			offset = xmlstr.indexOf('>',offset)+1;
			}
		else {	
			thiselem = new ELEMENT('',new Array(),'');
			thiselem.depth = ++depth;
			thisname = xmlstr.substring(xmlstr.indexOf('<',offset)+1,xmlstr.indexOf('>',offset)); // now working with new element
			var attribs = new Array();
			
			if (thisname.indexOf('=') != -1) {
				attribstr = thisname.substring(thisname.indexOf(' ')+1, thisname.length);
				thisname = thisname.substring(0,thisname.indexOf(' '));
				if (attribstr.charAt(attribstr.length - 1) == '/') {
					attribstr = attribstr.substring(0,attribstr.length - 1);
					thiselem.contentArray[thiselem.contentArray.length] = null;
					}
				var attarray = attribstr.split('=');
				for (var ai=0;ai<attarray.length;ai+=2) {
					attribs[ai] = attarray[ai].substring(attarray[ai].lastIndexOf(' ')+1,attarray[ai].length);
					attribs[(ai+1)] = new String(attarray[(ai+1)]).substring(new String(attarray[(ai+1)]).indexOf('"')+1,new String(attarray[(ai+1)]).lastIndexOf('"'));
					}
				}
			thiselem.name = thisname;
			//thiselem.attributes = attribs;
			thiselem.attributes = makeAssocArray(attribs);
			thiselem.attribList = attribs;
			
			thiselem.parent = curParent;
			
			if (xmlstr.indexOf('/>',offset)!=-1 && (xmlstr.indexOf('/>',offset)<xmlstr.indexOf('>',offset))) { //empty tag				
				// THIS LINE COMMENTED OUT 11/13/2000 TO MATCH SIMILAR SITUATION BELOW, IN "else" CLAUSE
				// thiselem.content = null;
				// REPLACED WITH THIS LINE:
				thiselem.contentArray[thiselem.contentArray.length] = null;
				if (thiselem.name.charAt(thiselem.name.length-1)=='/') { thiselem.name = thiselem.name.substring(0,thiselem.name.length-1); } // an empty tag without attributes would still have the end slash attached to the name
				thiselem.parent.children[thiselem.parent.children.length] = thiselem;
				offset = xmlstr.indexOf('>',offset)+1;
				}
			else {
				// FOLLOWING LINE COMMENTED OUT 11/13/2000 - SEEMS OBSOLETE
				//thiselem.content = xmlstr.substring(xmlstr.indexOf('>',offset)+1,xmlstr.indexOf('</'+thiselem.name,offset));
				// REPLACED WITH THIS LINE:
				thiselem.contentArray[thiselem.contentArray.length] = xmlstr.substring(xmlstr.indexOf('>',offset)+1,xmlstr.indexOf('</'+thiselem.name,offset));
				thiselem.parent.children[thiselem.parent.children.length] = thiselem;
				curParent = thiselem;
				}
			//alert(thiselem.depth + " " + thiselem.name);
			offset = xmlstr.indexOf('>',offset+1)+1;
			}
		
		}
	return DOC;
	}



// ############## converts form data to XML
function form2XML(frmrf,attrib) { // takes reference to form and an attributes array for root element of returned XML document.
	var mu = new ELEMENT(frmrf.name,attrib,''); 
	for (i=0; i<frmrf.elements.length; i++) {
		if (frmrf.elements[i].type=='radio' || frmrf.elements[i].type=='checkbox') {
			if (frmrf.elements[i].checked) {
				mu.addElement(new ELEMENT(frmrf.elements[i].name,new Array(),escspcchar(frmrf.elements[i].value)));
				}
			}
		else {
			mu.addElement(new ELEMENT(frmrf.elements[i].name,new Array(),((frmrf.elements[i].value==null)? escspcchar(frmrf.elements[i].options[frmrf.elements[i].selectedIndex].value):escspcchar(frmrf.elements[i].value))));
			}
		}
	//return mu.toXML();
	return mu;
	}

function escspcchar(str) {
	var retstr=str;
	// escape ampersands
	while (retstr.indexOf('&')!=-1 && retstr.indexOf('&amp;')!=retstr.indexOf('&')) {
		retstr=retstr.substring(0,retstr.indexOf('&')) + '&amp;' + retstr.substring(retstr.indexOf('&')+1,retstr.length);
		}
	return retstr;
	}
