// based off http://www.xs4all.nl/~ppk/js/importxml.html
// doesn't like xhtml-1.0-strict, text/xml files
function importXML (file, func)
{
	if (document.implementation && document.implementation.createDocument)
	{
		xmlDoc = document.implementation.createDocument("", "", null);
		xmlDoc.onload = func;
	}
	else if (window.ActiveXObject)
	{
		xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
		xmlDoc.onreadystatechange = function()
		{
			if (xmlDoc.readyState == 4)
			{
				func();
			}
		};
	}
	else
	{
		return;
	}
	xmlDoc.load(file);
}

// from scottandrew.com via simon.incutio.com
function addEvent (obj, evType, fn, useCapture)
{
	if (obj.addEventListener)
	{
		obj.addEventListener(evType, fn, useCapture);
		return true;
	}
	else if (obj.attachEvent)
	{
		var r = obj.attachEvent("on" + evType, fn);
		return r;
	}
	else
	{
		// alert('Handler could not be attached');
		return false;
	}
}

// called when xml document is imported
function parseFormXml ()
{
	form = document.getElementById(xmlDoc.documentElement.getAttribute('id'));

	// onsubmit, form is checked
	addEvent(form, 'submit', checkForm, false);
	validators = new Array();
	elements = xmlDoc.getElementsByTagName('element');

	// create element validator objects and add to array
	for (var i = 0; i < elements.length; i++)
	{
		val = new ElementValidator(elements[i]);
		validators[val.id] = val;

		// onblur check validity
		addEvent(val.element, 'blur', onblurCheck, false);
	}
}

// called on form submit; cycle through make sure all elements are valid
function checkForm (event)
{
	var pass = true;
	for (var i in validators)
	{
		validators[i].check();
		if (validators[i].valid == false)
		{
			pass = false;
		}
	}
	if (pass == false)
	{
		message = 'You have not completed this form correctly.\n';
		message += 'Please go back and review your answers.';
		alert(message);

		// stop form submittal
		if (document.all) // ie event model
		{
			event.returnValue = false;
		}
		else // standard w3c model - moz
		{
			event.preventDefault();
		}
	}
}

// get document name and determine xml document to be imported
function getXmlUrl ()
{
	return '/pub1/xmlregform.xml';
/*
	var url = window.location.href;

	// if it ends with a get query, remove the query
	url = url.split('?')[0];

	// grab the filename
	url = url.match(/\w+\.[a-zA-Z0-9]+$/).toString();

	// replace filename.extension with filename.xml
	var dot = url.lastIndexOf('.');
	url = url.substring(0, dot);
	url = url + '.xml';

	return url;
*/
}

function onblurCheck (event)
{
	if (document.all) // ie
	{
		id = event.srcElement.getAttribute('id');
	}
	else // moz
	{
		id = this.getAttribute('id');
	}
	validators[id].check();
}

// element validator object
function ElementValidator (node)
{
	this.id = node.getAttribute('id');
	this.element = document.getElementById(this.id);
	this.valid = true;
	this.min = node.getAttribute('min');
	this.max = node.getAttribute('max');
	this.req = node.getAttribute('req') == "true";
	this.regs = new Array();

	regexes = node.getElementsByTagName('regex');
	for (var i = 0; i < regexes.length; i++ )
	{
		// grab text inside regex tag(s)
		this.regs[i] = new RegExp(regexes[i].childNodes[0].nodeValue);
	}

	err = node.getElementsByTagName('error')[0];
	if (err != null)
	{
		this.error = err.childNodes[0].nodeValue;
	}
	else
	{
		this.error = null;
	}

	this.name = node.getAttribute('name');
	this.sameAs = node.getAttribute('sameas');

	// get reference to element node that value should equal
	if (this.sameAs != null)
	{
		this.sameAs = document.getElementById(this.sameAs);
	}

	// classname of enclosing <li>
	this.parentClass = this.element.parentNode.className;

	this.check = function()
	{
		// confirmation value. must be same as confirming value + valid for
		// confirming value's rules
		if (this.sameAs != null)
		{
			if (this.element.value == this.sameAs.value)
			{
				if (validators[this.sameAs.getAttribute('id')].valid == true)
				{
					this.makeValid();
				}
				else
				{
					var otherName = validators[this.sameAs.getAttribute('id')].name;
					this.makeInvalid('Your ' + otherName + ' is not correct.');
				}
			}
			else
			{
				var otherName = validators[this.sameAs.getAttribute('id')].name;
				var msg = 'This value must be identical to your ' + otherName + '.';
				this.makeInvalid(msg);
			}
		}
		else
		{
			var val = this.element.value;

			// first check for required
			if (this.req && val == "")
			{
				this.makeInvalid(this.reqErrMsg());
				return;
			}
			else if ((this.req == false) && (val == "")) // if not required and no value, is valid
			{
				this.makeValid();
				return;
			}

			// check for length
			if ((this.min != null && val.length < this.min) || (this.max != null && val.length > this.max))
			{
				this.makeInvalid(this.lenErrMsg());
				return;
			}

			// check that it matches at least one supplied regex, if any supplied
			if (this.regs.length > 0)
			{
				var pass = false;
				for (var i = 0; i < this.regs.length; i++)
				{
					if (this.regs[i].test(val))
					{
						pass = true;
						break;
					}
				}
				if (pass == false)
				{
					this.makeInvalid(this.error);
					return;
				}
			}

			// passed all tests
			this.makeValid();
		}
	}

	this.lenErrMsg = function()
	{
		var cap = this.name.substring(0,1).toUpperCase();
		var capName = cap + this.name.substring(1, this.name.length);

		if (this.min != null && this.max != null)
		{
			ret = capName + ' must be between ' + this.min + ' and ';
			ret += this.max +  ' characters.';
			return ret;
		}
		else if (this.min != null)
		{
			return capName + ' must be more than ' + this.min + ' characters.';
		}
		else // max, no min
		{
			return capName + ' must be less than ' + this.max + ' characters.';
		}
	}

	this.reqErrMsg = function()
	{
		letter = this.name.substring(0, 1);
		switch (letter)
		{
			case 'a':
			case 'e':
			case 'i':
			case 'o':
			case 'u':
				word = 'your';
				break;
			default:
				word = 'your';
				break;
		}
		return 'You must supply ' + word + ' ' + this.name + '.';
	}

	this.makeInvalid = function(errMsg)
	{
		this.element.parentNode.className = this.parentClass + " error";

		// insert error message
		// if already invalid will have an error message already
		if (this.valid == false)
		{
			errorNode = document.getElementById(this.id + 'errmsg');
			textNode = document.createTextNode(errMsg);
			// childnodes[0] is the old error text
			errorNode.replaceChild(textNode, errorNode.childNodes[0]);
		}
		else
		{
			// create and add to <li> a span with an error message
			span = document.createElement('span');
			span.className = "errormsg";
			span.setAttribute("id", this.id + "errmsg");
			textNode = document.createTextNode(errMsg);
			span.appendChild(textNode);
			this.element.parentNode.appendChild(span);
		}
		this.valid = false;
	}

	this.makeValid = function()
	{
		// remove error message if there
		if (this.valid == false)
		{
			errorNode = document.getElementById(this.id + 'errmsg');
			this.element.parentNode.removeChild(errorNode);
		}
		this.valid = true;
		this.element.parentNode.className = this.parentClass;
	}
}

importXML(getXmlUrl(), parseFormXml);
