function FormProcessor(successURL,failureURL,errorHeader)
{
	// Instance Variables

	this.errorSeparator = "~~~";
	this.errorNumValSeparator = "~~";
	this.error_keyname = "formE";
	this.error_header = errorHeader;
	this.encryption = false;
	this.debug=0;

	this.validationRules = "";
	this.formErrors = "";
	this.formData = "";

	this.successURL = successURL;
	this.failureURL = failureURL;

	// Methods

	this.initialize = _initialize;
	this.createFormData = _createFormData;
	this.createFormErrors = _createFormErrors;
	this.populateForm = _populateForm;
	this.submitForm = _submitForm;
	this.readForm = _readForm;
	this.validateFormData = _validateFormData;
	this.getFormDataString = _getFormDataString;
	this.getFormErrorString = _getFormErrorString;
	this.hasError = _hasError;
	this.getValue = _getValue;
	this.getErrorHTML = _getErrorHTML;
	this.encrypt = _encrypt;
	this.decrypt = _decrypt;
	this.alert = _alert;

	// Code

	this.initialize();
}


// Initializes object trys to populate formData and formErrors from URL parameters
function _initialize() {
		this.alert("in _initialize()");

		// Check and set success and error URL if needed
		var myLocation = new String(document.location);
		if (myLocation.indexOf('?') != -1)
			myLocation = myLocation.substring(0,(myLocation.indexOf('?')));
		if (this.successURL == "_self")
			this.successURL = myLocation;
		if (this.failureURL == "_self")
			this.failureURL = myLocation;



		// Try to populate formData if they exists in URL
		var query = '' + document.location;
		query = query.substring((query.indexOf('?')) + 1);

		if (query.length > 1)
		{
			this.alert("Populting formData");
			this.formData = this.createFormData();
		}


		// Try to populate formErrors if they exists in URL
		query = query.substring((query.indexOf(this.error_keyname)) + this.error_keyname.length-1);

		if (query.length > 1)
		{
			this.alert("Populting formErrors");
			this.formErrors = this.createFormErrors();
			this.alert("formErrors length: " + this.formErrors.length);
		}
}




// Creates a formData array based on the current URL parameters
function _createFormData() {
	this.alert("in _createFormData()");

	var formData = new Array();

	var query = '' + document.location;

	if (query.length < 1) { return ""; }

	var keypairs = new Array();

	for(var numKP=0;query.indexOf('&') > -1;numKP++) {
		query = query.substring((query.indexOf(numKP==0?'?':'&')) + 1);
		keypairs[numKP] = query.substring(0,query.indexOf('&')==-1?query.length:query.indexOf('&'));
	}
	
	for (i in keypairs) {
		keyName = keypairs[i].substring(0,keypairs[i].indexOf('='));
		keyValue = keypairs[i].substring((keypairs[i].indexOf('=')) + 1);
		while (keyValue.indexOf('+') > -1) {
			keyValue = keyValue.substring(0,keyValue.indexOf('+')) + ' ' + keyValue.substring(keyValue.indexOf('+') + 1);
		}

		keyValue = this.decrypt(unescape(keyValue));
		keyName = unescape(keyName);

		if(keyName != (this.error_keyname.substring(0,this.error_keyname.length-1))) {
			if (formData[keyName]) {
				formData[keyName][formData[keyName].length] = keyValue;
			} else {
				formData[keyName] = new Array()
				formData[keyName] = [keyName,keyValue];
			}
		}
	}
	
	//alert("keypairs=" + keypairs);
	
	return formData;
}

// Creates an error array based on the current URL parameters
function _createFormErrors() {
	this.alert("in _createFormErrors()");

	var errors = new Array();

	var query = '' + document.location;

	query = this.errorSeparator + unescape(query.substring((query.indexOf(this.error_keyname)) + this.error_keyname.length + 1));

	if (query.length < 1) { return ""; }  // Perhaps we got some bad data?

	var keypairs = new Array();
	var numKP = 1;

	while (query.indexOf(this.errorSeparator) > -1) {
		keypairs[numKP] = query.substring(0,query.indexOf(this.errorSeparator));
		query = query.substring((query.indexOf(this.errorSeparator)) + this.errorSeparator.length);
		numKP++;
	}

	keypairs[numKP] = query;

	for (i in keypairs) {
		keyName = keypairs[i].substring(0,keypairs[i].indexOf(this.errorNumValSeparator));
		keyField = keypairs[i].substring((keypairs[i].indexOf(this.errorNumValSeparator)) + this.errorNumValSeparator.length,keypairs[i].lastIndexOf(this.errorNumValSeparator));
		keyValue = keypairs[i].substring((keypairs[i].lastIndexOf(this.errorNumValSeparator)) + this.errorNumValSeparator.length);
		while (keyValue.indexOf('+') > -1) {
			keyValue = keyValue.substring(0,keyValue.indexOf('+')) + ' ' + keyValue.substring(keyValue.indexOf('+') + 1);
		}

		keyName = this.decrypt(keyName);
		keyField = this.decrypt(keyField);
		keyValue = this.decrypt(keyValue);

		errors[keyName] = new Array();
		errors[keyName] = [keyName,keyField,keyValue];
	}
	return errors;
}

// Populates the form with the data from the formData array
function _populateForm(myForm)
{
	this.alert("in _populateForm()");

	for (x = 0; x < myForm.elements.length; x++)
	{
		this.alert("checking form element " + x + " : " + myForm.elements[x]);
		var value="";
		var name= "";
		if (myForm.elements[x].type == "text") {
			this.alert("text");
			if(((typeof this.formData[myForm.elements[x].name])!='undefined') && this.formData[myForm.elements[x].name].length > 1) {
				myForm.elements[x].value = this.formData[myForm.elements[x].name][1];
			}
		}
		else if (myForm.elements[x].type == "select-one") {
			this.alert("select-one");
			if(((typeof this.formData[myForm.elements[x].name])!='undefined') && this.formData[myForm.elements[x].name].length > 1) {
				for (i=0; i< myForm.elements[x].options.length; i++) {
					for (ii = 1; ii < this.formData[myForm.elements[x].name].length;ii++) {
						if(this.formData[myForm.elements[x].name][ii] == myForm.elements[x].options[i].text)
							myForm.elements[x].options[i].selected = true;
					}
				}
			}
		}
		else if (myForm.elements[x].type == "checkbox") {
			this.alert("checkbox");
			if(((typeof this.formData[myForm.elements[x].name])!='undefined') && this.formData[myForm.elements[x].name].length > 1) {
				if (this.formData[myForm.elements[x].name][1] == 'true')
					myForm.elements[x].checked = true;
				else
					myForm.elements[x].checked = false;
					
			}
		}
		else if (myForm.elements[x].type == "radio") {
			this.alert("radio");
			if((typeof this.formData[myForm.elements[x].name])!='undefined') {
				if(this.formData[myForm.elements[x].name][1] == myForm.elements[x].value) {
					myForm.elements[x].checked = true;
					if (typeof myForm.elements[x].onclick!='undefined' && myForm.elements[x].onclick!=null)
						eval(myForm.elements[x].onclick());
				}
			}
		}

	}
}



// Validates a supplied form against supplied validation rules and routes to success or failure URL based on results
function _submitForm(myForm, myValidation, preSubmitEvalString)
{
	this.alert("in _submitForm()");
	
	var formData = this.readForm(myForm);
	var errors = this.validateFormData(formData,myValidation);
	
	//alert("errors : " + errors);
	//alert("errors.length : " + errors.length);
	//alert("failureURL : " + this.failureURL);

	if (errors.length  > 0)
	{
		for (i=0; i < errors.length ; i++)
		{
			error = errors[i];
			
			//alert("error[" + i + "] : " + error);
			
			if (error[0] == 2)
			{
				document.location = "mp_error.html";
				return false;
			}
		}
		var myLocation = this.failureURL + "?" + this.getFormDataString(formData) + "&" + this.getFormErrorString(errors);
		this.alert(myLocation);
		document.location = myLocation;
		return false;
	}
	else
	{
		myForm.action = this.successURL;
		if (typeof preSubmit != "undefined"){
			preSubmit();
		}
		return true;
	}
}


// Reads the form data and returns a formData variable equal to an array containing all of the form's data
function _readForm(myForm)
{
	this.alert("in _readForm()");

	var formData = new Array();

	for (x = 0; x < myForm.elements.length; x++)
	{
		var value="";
		var name= "";
		if ((myForm.elements[x].type == "hidden")||(myForm.elements[x].type == "text")||(myForm.elements[x].type == "radio" && myForm.elements[x].checked == true)) {
			value = myForm.elements[x].value;
			name = myForm.elements[x].name;
			
			//alert(name + "=" + value);
		}
		else if (myForm.elements[x].type == "select-one") {
				value = myForm.elements[x].options[myForm.elements[x].selectedIndex].text;
				name = myForm.elements[x].name;
		}
		else if (myForm.elements[x].type == "checkbox") {
				value = (myForm.elements[x].checked==true?'true':'false');
				name = myForm.elements[x].name;
		}

		if (formData[name]) {
		  formData[name][formData[name].length] = value;
		}
		else {
		  formData[name] = new Array();
		  formData[name] = [name,value];
		}
	}
	
	
	
	return formData;
}

// Uses validationRules array to validate data in the formData array sets formErrors equal to the result
function _validateFormData(myFormData, myValidation)
{
	this.alert("in _validateFormData()");

	var blankString = new RegExp("^[ ]*$");
	var errorMessages = new Array();

	//for (i in myValidation) {
	for (i = 0; i < myValidation.length; i++) {
		depends = myValidation[i][3].split(",");
		validate = true;

		for (x in depends) {
			if (errorMessages[parseInt(depends[x])]) {
				validate = false;
				break;
			}
		}

		if (validate) {
			if(myValidation[i][0] == "req") {
				
				//alert(myValidation[i]);
				
				if(myFormData[myValidation[i][1]]) {
					values = myFormData[myValidation[i][1]][1].match(blankString);
					if ((typeof values) !="undefined" && values) {
						//alert("cond1 - " + myValidation[i]);
						//alert("cond1 - " + myValidation[i][1]);
						//alert("cond1 - " + myValidation[i][2]);
						//errorMessages[i] = new Array(i,myValidation[i][1],myValidation[i][2]);
						errorMessages.push ( new Array(i,myValidation[i][1],myValidation[i][2]) );
					}
				} else {
					//alert("cond2 - " + myValidation[i]);
					//errorMessages[i] = new Array(i,myValidation[i][1],myValidation[i][2]);
					errorMessages.push ( new Array(i,myValidation[i][1],myValidation[i][2]) );
				}


			}
			else {
				if (myValidation[i][0].charAt(0) == '!') {
					expressionFalse = true;
					myRegExp = new RegExp(myValidation[i][0].substr(1));
				} else {
					expressionFalse = false;
					myRegExp = new RegExp(myValidation[i][0]);
				}
				
				for (x=1; x < myFormData[myValidation[i][1]].length; x++) {
					
					expressionTest = myRegExp.test(myFormData[myValidation[i][1]][x]);	
					
					if ( (!expressionTest && !expressionFalse) || (expressionTest && expressionFalse)) {
						//errorMessages[i] = new Array(i,myValidation[i][1],myValidation[i][2]);
						errorMessages.push ( new Array(i,myValidation[i][1],myValidation[i][2]) );
					}
				}
			}
		}
	}
	
	//alert("errorMessages : " + errorMessages);
	
	return errorMessages;
}

// Encodes the formData array into a string of URL parameters (uses encryption to hide the data from the user)
function _getFormDataString(myFormData)
{
	this.alert("in _getFormDataString()");

	valueString = "";
		for (i in myFormData) {
			if (myFormData[i][0]) {
				name = myFormData[i][0];
				for (x=1; x < myFormData[i].length; x++) {
					valueString += "&" + escape(name) + "=" + escape(this.encrypt(myFormData[i][x]));
				}
			}
		}
	return valueString.substring(1);
}

// Encodes formErrors it into a string to transmit as a url parameter
function _getFormErrorString(myFormErrors)
{
	this.alert("in _getFormErrorString()");
	
	//alert("myFormErrors : " + myFormErrors);
	//alert("myFormErrors.length : " + myFormErrors.length);
	
	valueString = "";
		
		//for (i = 0; i < myFormErrors.length; i++) {
		for (i in myFormErrors) {
			//if (myFormErrors[i][0]) {
				//alert("myFormErrors[" + i + "][0] : " + myFormErrors[i][0]);
				valueString += this.errorSeparator;
				valueString += this.encrypt(myFormErrors[i][0]) + this.errorNumValSeparator + this.encrypt(myFormErrors[i][1]) + this.errorNumValSeparator + this.encrypt(myFormErrors[i][2]);
			//}
		}
	return this.error_keyname + "=" + escape(valueString.substring(this.errorSeparator.length));
}

// Accepts a formField name and returns true if the field has a corresponding error
function _hasError(inputName) {
	this.alert("in _hasError()");

	var foundError  = false;
	for(i in this.formErrors) {
		if (this.formErrors[i][1] == inputName)
			foundError = true;
	}
	return foundError;
}

// Accepts a formField name and returns the value or comma delimited values if the field has a corresponding value/values
function _getValue(inputName) {
	this.alert("in _getValue()");

	var value = "";
	//if (this.formData[inputName])alert("has value");
	
	//if(this.formData[inputName].length > 1)alert("more than one");
	if (this.formData[inputName] && this.formData[inputName].length > 1)
	{
		
		if (this.formData[inputName].length > 2){
			for(i=1;i<this.formData[inputName].length;i++)
			{
				value += this.formData[inputName][i] + ",";
			}
			value = value.substr(0,value.length-1);
		}
		else {
			value = this.formData[inputName][1];
		}
	}
	return value;
}

// Returns error messages in HTML format
function _getErrorHTML() {
	this.alert("in _getErrorHTML()");

	var myHTML = "";
	if (this.formErrors.length > 0)
	{
		this.alert("Found errors, producing error HTML");
		myHTML = this.error_header;
		for (i in this.formErrors) {
			this.alert("Error array index: " + i + " --- Error message: " + this.formErrors[i][2]);
			myHTML += this.formErrors[i][2]+ "<br>";
		}
	}
	return myHTML;
}

// Triggers an this.alert if the debug variable is set to true
function _alert(alertString) {
	if (this.debug > 0)
		alert(alertString);
}

// Calls external encryption if encryption is enabled
function _encrypt(input) {
	if (this.encryption)
	{
		input = encrypt(input,"a")
	}
	return input;
}

// Calls external decryption if decryption is enabled
function _decrypt(input) {
	if (this.encryption)
	{
		input = decrypt(input,"a")
	}
	return input;
}
