function XmlRead() {
	// setup variables
	this.xmlScript = false;
	this.requestMethod = 'POST';
	this.getData = new Array();
	this.postData = new Array();
	this.dataError = false;
	this.rawXml = false;
	// data variables
	this.xmlRows = new Array();
	this.currentRow = new Array();
	this.savePointer = -1;
	this.readPointer = 0;
	
	// define class functions
	this.SetXmlScript = SetXmlScript;
	this.SetRequestMethod = SetRequestMethod;
	this.AddParameterField = AddParameterField;
	this.SetError = SetError;
	this.GetError = GetError;
	this.AddNewRow = AddNewRow;
	this.StoreField = StoreField;
	this.GetXmlRows = GetXmlRows;
	this.Read = Read;
	this.f = f;
}

// sets the xml script
function SetXmlScript(xmlScript) {
	this.xmlScript = xmlScript;
}

// sets the request method
function SetRequestMethod(requestMethod) {
	this.requestMethod = requestMethod.toUpperCase();
}

// adds a parameter to the GET/POST data
function AddParameterField(fieldName, fieldData) {
	if (this.requestMethod == 'GET') {
		this.getData.push(fieldName+'='+fieldData);
	} else {
		this.postData.push(fieldName+'='+fieldData);
	}
}

// sets the current error
function SetError(errorMessage) {
	alert(errorMessage);
	this.dataError = errorMessage;	
}

// returns the current error
function GetError() {
	return this.dataError;	
}

// set pointer ready to save a new row
function AddNewRow() {
	this.savePointer++;
	this.xmlRows[this.savePointer] = new Array();
}

// add a field to the current save row
function StoreField(fieldName, fieldData) {
	// restore 'safe' strings to thier origional form
	fieldData = replaceAll('__AMP__', '&', fieldData);
	fieldData = replaceAll('__TO__', '<', fieldData);
	fieldData = replaceAll('__TC__', '>', fieldData);

	// add the field data	
	this.xmlRows[this.savePointer][fieldName] = fieldData;
}

// get the xml data and store it within the class (returning if there was data)
function GetXmlRows() {
	// create a local variable which is a pointer to this class
	var thisPointer = this;
	
	// if a script is defined
	if (this.xmlScript) {
		// if there are get parameters, add them to the xml script
		if (this.getData.length > 0) {
			this.xmlScript += '?'+this.getData.join('&');
		}
		// set up the xml request
		var xmlhttp = new XMLHttpRequest();
		xmlhttp.open(this.requestMethod, this.xmlScript, false);
		
		// define the callback function
		xmlhttp.onreadystatechange = function() {
			if (xmlhttp.readyState == 4) {
				// check if data has been received ok
				if (xmlhttp.status == 200) {
					try {
						// get an the 'xmlrows' tag (should only be 1 row)
						var xmlData = xmlhttp.responseXML.getElementsByTagName('xmlrows');
						// copy the response text to the local class for debug purposes
						thisPointer.rawXml = xmlhttp.responseText;
						
						// if there is data
						if (xmlData.length > 0) {
							// get an array of all the actual records
							var xmlRows = xmlData[0].getElementsByTagName('xmlrow');
							// loop through each of the rows and add field data to the class
							for (rowId = 0; rowId < xmlRows.length; rowId++) {
								// add a row to the class
								thisPointer.AddNewRow();
								// store each field
								for (fieldId = 0; fieldId < xmlRows[rowId].childNodes.length; fieldId++) {
									fieldData = xmlRows[rowId].childNodes[fieldId];
									try {
										thisPointer.StoreField(fieldData.tagName, fieldData.firstChild.data);
									} catch (er) {
										// do nothing
									}
								}
							}
						}
						// abort the connection
						xmlhttp.abort();
					} catch (e) {
						this.SetError('Error: '+e);
						return;
					}
				} else {
					this.SetError('Read Error');
					return;
				}
			}
		}
		
		// Send the message via POST request
		xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
		xmlhttp.send(this.postData.join('&'));
	}
	
	// if there was data, return true, otherwise return false
	if (this.xmlRows.length > 0) {
		return true;
	} else {
		return false;
	}
}

// reads a row from the loaded xml data
function Read() {
	// if there is data at the current pointer
	if (typeof(this.xmlRows[this.readPointer]) != 'undefined') {
		// copy the pointed row into the currentRow variable
		this.currentRow = this.xmlRows[this.readPointer];
		// unset the row from the main data set (hopefully will free up memory)
		this.xmlRows[this.readPointer] = null;
		// advance the read pointer
		this.readPointer++;
		// return true
		return true;
	// if no data return false
	} else {
		return false;	
	}
}

// returns the data for a specified field
function f(fieldName) {
	// check the field exists, return it
	if (typeof(this.currentRow[fieldName]) != 'undefined') {
		return this.currentRow[fieldName];
	// if not return an empty string
	} else {
		return '';
	}
}

