/**
 * @author Walter Wimberly
 * @version .9.1
 * @fileoverview
 * <p>Each of the test methods returns Boolean true if the test passes and the 
 * error message if it fails. </p>
 * <p>Updated some minor bugs, which was causing minval to not work.</p>
 */

/**
 * @type Array
 * @private
 * <p>A String array of the methods which can be checked against.</p>
 */
var validatorAttributes = ["autotrim", "required", "email", "maxlen", "maxval", 
		"minlen", "minval", "notfirst", "maxwords", "usphone", "zipcode", 
		"uscurrency", "ssn", "time", "usdate", "internationaldate",
		"alphanumeric", "numeric", "alpha", "regex", "matches",
		"numgt", "numgte"];
/**
 * @type Array
 * @private
 * <p>An array of functions which can be checked against.</p>
 */
var validatorFunctions = [autotrim, required, email, maxlen, maxval, 
		minlen, minval, notfirst, maxwords, usphone, zipcode,
		uscurrency, ssn, time, usdate, internationaldate, 
		alphanumeric, numeric, alpha, regex, matches,
		numgt, numgte];

/**
 * @type	Boolean
 * <p>Used to determine if we are currently checking the form to submit, 
 * or not.</p>
 */
var formCheck = false;


/**
 * <p>Call this function after a the form(s) have been loaded and the 
 * appropriate tests will be attached to the onblur method of the form 
 * element.</p>
 * @method
 */
function initializeValidator() {
	var lstForm = document.getElementsByTagName('form');
	var msg;
	
	for(i = 0; i < lstForm.length; i++) {
		cn = lstForm[i].elements;	// get all of the elements in the form
		for(j=0; j < cn.length; j++) {
			for(k=0; k < validatorAttributes.length; k++) {
				if(cn[j].getAttribute(validatorAttributes[k])) {
					if (validatorAttributes[k] == 'required') {
						defineRequired(cn[j].getAttribute('id'));
					}
					myAttachEvent(cn[j], 'blur', validatorFunctions[k]);
				}
			}
		}
	}
}

/**
 * <p>If the input is required, then apply the CSS style of the same
 * 	name to the associated label tag.  Additionally, a star (*) will
 * 	be inserted before the text of the label to visually identify 
 * 	that the tag will be required.</p>
 * <p>This function is called during the initialization function 
 * 	call, if that method is called.  If the checked element is not 
 * 	implicitly stated as required, this function will not be 
 * 	called. So tags that use attributes like minlen, and minwords 
 * 	would need to have required added as well as an attribute to
 * 	take advantage of this feature.</p>
 * @see #initializeValidation
 * @param {String} id	The id of the DOM Object which needs to 
 * 				checked to see if a label applies, in which to make
 * 				it required.
 * 				
 */
function defineRequired(id) {
	var lstLabels = document.getElementsByTagName('label');
	for(n=0; n < lstLabels.length; n++) {
		if(lstLabels[n].htmlFor == id) {
			// add a CSS class to the label
			addClassToElement(lstLabels[n], 'required');
			// add a star to the front of the label text
			lstLabels[n].innerHTML = "<span class=\"requiredText\">* required</span> " + lstLabels[n].innerHTML;
			break;
		}
	}
}

/**
 * <p>This function adds a CSS class to a given DOM object. By 
 * 	generating this method, a more centralized way of managing this
 * 	process can occur.</p>
 * <p>If a given element already has a CSS style attached to it,
 * 	this function will ensure that the original style is kept,
 * 	and the new style is appended.  If the element already has
 * 	the same style attached, nothing will happen. If no class has
 * 	been assigned to this element, then the class name applied will
 * 	be the only class assigned to the tag.</p>
 * @param {DOMObject} element	DOM Object that is supposed to
 * 		have a CSS element attached to it.
 * @param {String} classname	String representing the name of 
 * 		the CSS class to be applied to the element 
 */
function addClassToElement(element, classname) {
	if(!element) {
		return;
	}
	if( element.className === '' || element.className === null) {
		element.className = classname;
	} else if (element.className.indexOf(classname) == -1 ) {
		element.className += ' ' + classname;
	}
}

/**
 * @method
 * @param {Object} frm	The form to be called.
 * <p>This method will validate the form when it is submitted, if it is 
 * manually placed in the onsubmit method.</p>
 * <p><strong>Example:</strong> <br />
 * <form .... onsubmit="return checkForm(this);"></p>
 * <p>This will check the form before it is submitted.  Because <em>return</em>
 * is used, if checkForm returns false, then it will not submit the form
 * requiring the user to fix the errors before proceding.</p>
 * <p>This can also be attached to an onclick method of a button with 
 * some minor code tweaks to allow the user to confirm the correct data/
 * type of data had been entered.  Should be unnecessary since the form 
 * is giving instaneous feedback as the form is being filled out.</p>
 * @type	Boolean
 * @throws  NullPointerException
 * @return	Returns true if the form passed all of the error checks, false 
 * 		if it failed any of the checks.
 */
function validatorCheckForm(frm) {
	if (frm === null ) {
		throw("NullPointerException: A valid form must be passed to " +
			"the Check Form function.");
	}
	formCheck = true;	// set the formCheck value to true so error checking
						// knows how to handle the pop-up display information
	var cn = frm.elements;	// get all of the elements in the form
	// Used to keep a running tally of the error message which form checking.
	var alertMsg = '';
	
	for(j=0; j < cn.length; j++) {
		for(k=0; k < validatorAttributes.length; k++) {
			if(cn[j].getAttribute(validatorAttributes[k])) {

				// check the form element
//				if(cn[j].getAttribute('required') !== null ) {
					// build the alert message.
					temp = validatorFunctions[k](cn[j]);
					
					if(temp !== '') {
						alertMsg += temp + "\n";
					}
//				}
				
			}
		}
	}
	
	formCheck = false;	// release the form checking flag
	if(alertMsg !== '') {
		// if there was a message - an error occured, and it will be 
		// displayed 
		alertMsg = 'There were errors processing the form:\n\n' + alertMsg;
		//alert(alertMsg);
		alertMsg = '';
		// don't let the person progress past this point because of the error
		return false;
	} else {
		// no errors, so return true and let the person submit the form.
		return true;
	}
}

/**
 * <p><strong>Error Information</strong><br />
 * This method only needs to be called from the other included 
 * functions, however it is important enough to note here as it yeilds
 * information on how the error messages and classes are handled.</p>
 * <p>Displays the error based upon the status of the error checking. 
 * If frmCheck is set to true, no pop-ups are displayed.</p>
 * <p>Error messages can come from several sources:</p>
 * <ul>
 * 	<li><strong>Error Specific Message:</strong> If you want define an 
 * 		error message for a given element, and you want it to be for a 
 * 		spefic type of error create an attribute on the element to be 
 * 		used such as <em>requirederrmsg</em>. This can be broken down to 
 * 		"required error message".  If the required attribute is present 
 * 		and requirederrmsg is also present, then the contents of the 
 * 		requirederrmsg attribute will be displayed for this	error 
 * 		message, but only for that error.  So if additional errors are 
 * 		present on the form element, then they can get different error
 * 		messages.</li>
 * 	<li><strong>Tag Specific Message:</strong> The same error message
 * 		can be used regardless of the error generating it.  This message
 * 		can be displayed using the <em>errmsg</em> attribute.  What ever 
 * 		the value within the errmsg attribute, will be displayed for that
 * 		form element, if there are any errors.  If their are multiple 
 * 		errors the error message will be displayed multiple times, unless
 * 		an Error Specific Message attribute was used for the other
 * 		potential errors.</li>
 * 	<li><strong>Generic Error Message:</strong> When no Error Specific 
 * 		Tag Message, or Tag Specific Error Message can be determined, a
 * 		generic error message can be used to generate an error.</li>
 * </ul>
 * <p><strong>Pop-Up Information</strong><br />
 * 	Additionally, you can set the <strong>popup</strong> attribute
 * 	(ex.: popop="only").  By doing so, when an error on that form field
 * 	occurs, it will cause the error message to display in a pop-up window.
 * 	<br />Legal values for the popup attribute are: only and both.  If 
 * 	<em>both</em> is set, the error message will be displayed in both
 * 	the pop-up window, and an error box below the form element.  If 
 * 	the value <em>only</em> is set, only the pop-up window gets the error 
 * 	message.  This is a <em>per field</em> attribute setting.</p>
 * <p><strong>CSS Style Information</strong><br />
 * 	Two CSS classes are used for defining error messages.  You can 
 * 	include	the external CSS file provided, make changes, etc. The 
 * 	classes are <strong>.errMsg</strong> and .<strong>errElem</strong>.  
 * 	errMsg is used to display the error message box.  errElem is for the 
 * 	form element with the error.  If these are not available, or made to 
 * 	be blank, then the element recieving these classes will have no 
 *  additional style attached.  The errElem is smartly applied and 
 *  removed so it will not effect any additional styles that have been 
 *  applied, unless it directly effects an associated attribute.</p>
 * @private
 * @method
 * @param {Event} elem - which element is getting the error message
 * @param {String} errType - what type of error - important for 
 * 		generating unique sections to hold the ID
 * @param {String} msg - the default error message.
 * @type	String
 * @return	Returns the error message os it can be captured by the 
 * calling method. 
 */
function displayError(elem, errType, msg) {
	var idErrName = elem.getAttribute('id') + "_" + errType + "_err";
	var container = null;
	var txt = '';
	
	if(elem.getAttribute(errType + 'errmsg') !== null ) {
		msg = elem.getAttribute(errType + 'errmsg');
	} else if(elem.getAttribute('errmsg') !== null ) {
		msg = elem.getAttribute('errmsg');
	}
	
	if(document.getElementById(idErrName) && elem.getAttribute('popup') != 'only') {
		container = document.getElementById(idErrName);
		if(msg != container.firstChild.innerText) {
			container.innerHTML = msg;
		}
	} else if(elem.getAttribute('popup') != 'only') {
		container = document.createElement('div');
		txt = document.createTextNode(msg);
		container.appendChild(txt);
		container.setAttribute('id', idErrName);
		if(!document.getElementById(idErrName)) {
			elem.parentNode.insertBefore(container,elem.nextSibling);
		}
		
		document.getElementById(idErrName).className = 'errMsg';
	}
	
	if((elem.getAttribute('popup') == 'only' || elem.getAttribute('popup') == 'both') && !formCheck) {
		alert(msg);
	}
	
	addClassToElement(elem, 'errElem');
	
	return msg;
}

/**
 * <p>If the error has been resolved, it will remove the error node and 
 * reset any styles.</p>
 * @private
 * @param {DOMObject} elem
 * @param {String} errType
 */
function removeErrorNode(elem, errType) {
	id = elem.getAttribute('id');
	idErrName = id + "_" + errType + "_err";
	var parent = null;
	
	// remove the error message node
	if(document.getElementById(idErrName)) {
		parent = document.getElementById(idErrName).parentNode;
		parent.removeChild(document.getElementById(idErrName));
	}
	
	// remove the error class from the element
	elem.className = trim(elem.className.replace(/errElem/, ' '));
}


/**
 * <p>Attached a function to an event for a given object.  Checks to make 
 * sure it can be done for different browsers.</p>
 * <p>This presents a unified method of adding the function as the event 
 * handler, and abstracts this level so the same code is not repeated over and over.</p>
 * @private
 * @param {DOMObject} obj
 * @param {Event} evt	The event (usually onblur) which caused this function to be called.
 * @param {Function} func
 * @type Boolean	
 * @return returns if the event was successfully added to the handler 
 * or not
 */
function myAttachEvent(obj,evt,func){
	var ret = false;
	if (obj.addEventListener){
		obj.addEventListener(evt,func,false);
		ret = true;
	} else if (obj.attachEvent) { 
		ret = obj.attachEvent("on"+evt,func);
	}
	return ret;
}

/**
 * <p>Trims unnecessary white space around the text within the element.
 * This is a private method that should not be needed except by other
 * functions within this library.</p>
 * @param {String} inString
 * @type	String
 * @return	Returns a trimed version of the string (without whitespace to as a
 * prefix or suffix to the string contents).
 */
function trim(inString) {
	if(inString !== '' && inString.replace) {
		// check to make sure there is a string, and that the string object
		// has the replace command.
		inString = inString.replace( /^\s+/g, "" );// strip leading white space
		inString = inString.replace( /\s+$/g, "" );// strip trailing white space 
	}
	return inString;
}


/**
 * <p>Convert the humpBack notation into English readable for determining
 * form element names.</p>
 * @private
 * @param {String} inString	The string which should be "fixed" to convert from hump
 * 		notation, or under_scored notation, into regular words for displaying error messages.
 * @type String
 * @return	Readable format of the string that was passed to the method
 */
function fixNaming(inString) {
	if(inString !== '') {
		rExp = /[A-Z]/g;
		inString = inString.replace(rExp,  ' $&' );

		rExp = /[-_]/g;
		inString = inString.replace(rExp,  ' ' );
		inString = inString.substr(0,1).toUpperCase() + inString.substr(1, inString.length - 1);		
	}
	return trim(inString);
}

/**
 * <p>Determine the target.  If a Form element is passed, it is returned, if an 
 * Event is passed, the element that sent the event is returned, if nothing
 * is passed (IE) then we get the last event, and determine which element 
 * generated that event.</p>
 * @param {Event} evt	The event (usually onblur) which caused this function to be called.
 * 		In some cases, this may also be the object itself.  The method will handle this
 * 		discrepancy.
 * @type	DOMObject	
 * @return	The form element that is to be checked.
 */
function getTarget(evt) {
	var element;
	if(evt.getAttribute && document.getElementById(evt.getAttribute('id')) == evt) {
		element = evt;
	} else {
		if (!evt) {
			evt = window.event;
		}
		
		if (evt.target) {
			element = evt.target;
		} else if (evt.srcElement) {
			element = evt.srcElement;
		}
		
		if (element.nodeType == 3) {
			// defeat Safari bug
			element = elem.parentNode;
		}
	}
	return element;
}

/**
 * <p>Determine if there was a match with the regular expression and the 
 * string.</p> 
 * @param {String} string	The value that is to be checked against a 
 * regualr expression.
 * @param {String} regEx	The regular expression that we will used
 * @type	Boolean		
 * @return	Returns true if there was a match with the regular 
 * 		expression, false if there was no match.
 */
function meetsRegEx(string, regEx) {
	var re = new RegExp(regEx);
	var m = re.exec(string);
	    
	return (m !== null);
}

/**
 * <p>If we want the form element to auto trim the white space, we can 
 * set this attribute.  Does not generate any error message - so safe for 
 * error checking if it is not a required field. 
 * <em>ex.: autotrim="autotrim"</em></p>
 * <p>This method is good for eliminating unwanted spaced before usernames, 
 * passwords, and other fields which could eventually cause a problem if 
 * looking for a match.</p>
 * @param {Event} evt	The event (usually onblur) which caused this 
 * 		function to be called.
 */
function autotrim(evt) {
	var elem = getTarget(evt);
	elem.value = trim(elem.value);
}

/**
 * <p>This element cannot be left blank. <em>example: required="true"</em></p>
 * @param {Event} evt	The event (usually onblur) which caused this 
 * 		function to be called.
 * @type	String
 * @return	an error message is necessary, otherwise a null string
 */
function required(evt) {
	var elem = getTarget(evt);
	
	if(trim(elem.value) === '') {
		return displayError(elem, 'required', 'Campo Obrigatório!');
	} else {
		removeErrorNode(elem, 'required');
		return '';
	}
}

/**
 * <p>This element must be a standard valid e-mail address. 
 * <em>ex.: email="email"</em></p>
 * @param {Event} evt	The event (usually onblur) which caused this function to be called.
 * @type	String
 * @return	an error message is necessary, otherwise a null string
 */
function email(evt) {
	var elem = getTarget(evt);
	var reg = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
	
	if(!meetsRegEx(elem.value, reg)) {
		return displayError(elem, 'email', 'The field ' + fixNaming(elem.name) + ' is not a valid e-mail address.');
	} else {
		removeErrorNode(elem, 'email');
		return '';
	}
}

/**
 * <p>This element cannot have more than the number of charcters that the 
 * attribute value specifies. <em>ex.: maxlen="300"</em></p>
 * @param {Event} evt	The event (usually onblur) which caused this function to be called.
 * @type	String
 * @return	an error message is necessary, otherwise a null string
 */
function maxlen(evt) {
	var elem = getTarget(evt);

	if(elem.value.length > elem.getAttribute('maxlen')) {
		return displayError(elem, 'maxlen', 'The field ' + fixNaming(elem.name) + ' is too long. It can only be ' + 
			elem.getAttribute('maxlen') + ' characters long. You currently have ' + 
			elem.value.length + ' characters.');
	} else {
		removeErrorNode(elem, 'maxlen');
		return '';
	}
}

/**
 * <p>Called if this form element cannot be above the value specified 
 * within the value of the attribute. <em>ex.: maxval="300"</em> - then 
 * the contents of the text box cannot have a numeric value of over 
 * 300.</p>
 * <p>Additionally, the value in the textbox must consist of only 
 * numbers. The numeric function is automatically called with this 
 * function. This should make writting the attributes a little simpler.
 * However, a value does not have to entered.  So if the field is 
 * manditory, then it should have an attribute of <em>required</em> 
 * as well.</p>
 * @see #numeric
 * @see #required
 * @param {Event} evt	The event (usually onblur) which caused this function to be called.
 * @type	String
 * @return	an error message is necessary, otherwise a null string
 */
function maxval(evt) {
	// ensure that the form element is also numeric
	numeric(evt);
	var elem = getTarget(evt);

	if(parseFloat(elem.value) > parseFloat(elem.getAttribute('maxval'))) {
		return displayError(elem, 'maxval', 'The field ' + fixNaming(elem.name) + ' is too large a number. ' +
			'It can only have a maximum value of ' + elem.getAttribute('maxval') + 
			'. It is currently ' + elem.value + '.');
	} else {
		removeErrorNode(elem, 'maxval');
		return '';
	}
}

/**
 * <p>This element must be at least n characters long as specified by the 
 * attribute value.  <em>ex.: minlen="6"</em></p>
 * <p>This attribute is good to use when you want to ensure a certain 
 * field, like a password is over a given length to make it more difficult
 * to guess.</p>
 * <p>This has a similar effect to required, with the added bonus of 
 * ensuring that the field has a length over the specified number. If 
 * you wanted to use it as/instead of the required attribute, you could 
 * specify: <em>minlen="1"</em>.</p>
 * @param {Event} evt	The event (usually onblur) which caused this 
 * 		function to be called.
 * @type	String
 * @return	an error message is necessary, otherwise a null string
 * @see #required
 */
function minlen(e) {
	// call required as it is assumed at this point.
	var elem = getTarget(e);
	
	if(elem.value.length < elem.getAttribute('minlen')) {
		displayError(elem, 'minlen', 'The field ' + fixNaming(elem.name) + ' is not long enough. It must be at least ' + 
			elem.getAttribute('minlen') + ' characters long. You currently have ' + 
			elem.value.length + ' characters');
		return false;
	} else {
		removeErrorNode(elem, 'minlen');
		return '';
	}

}

/**
 * <p>The value of this form element cannot be below the value specified 
 * within the value of the attribute. <em>ex.: minval="300"</em> - then 
 * the contents of the text box cannot have a numeric value less than 
 * 300.</p>
 * <p>Additionally, the value in the textbox must consist of only 
 * numbers. The numeric function is automatically called with this 
 * function. This should make writting the attributes a little simpler.
 * However, a value does not have to entered.  So if the field is 
 * manditory, then it should have an attribute of <em>required</em> 
 * as well.</p>
 * @see #numeric
 * @see #required
 * @param {Event} evt	The event (usually onblur) which caused this function to be called.
 * @type	String
 * @return	an error message is necessary, otherwise a null string
 */
function minval(evt) {
	var elem = getTarget(evt);
	var str;
	
	if(isNaN(parseFloat(elem.value)) ) {
		str = 'The field ' + fixNaming(elem.name) + ' does not appear to even be a number!';	
		return displayError(elem, 'minval', str);
	} else if( parseFloat(elem.value) < parseFloat(elem.getAttribute('minval'))) {
		str = 'The field ' + fixNaming(elem.name) + ' does not have a large enough value. ' +
			'It must have a minumum value of at least ' + elem.getAttribute('minval') + 
			'. It is currently ' + elem.value + '.'
			
		return displayError(elem, 'minval', str);
	} else {
		removeErrorNode(elem, 'minval');
		return '';
	}
}

/**
 * <p>Called if this form element, a drop down element or a list box, 
 * is not the first element as the selected element. 
 * <em>ex.: notfirst="notfirst"</em></p>
 * <p>This attribute is only effective for llist boxes and drop-down 
 * menus.  (i.e. the select tag)</p>
 * @param {Event} evt	The event (usually onblur) which caused this function to be called.
 * @type	String
 * @return	an error message is necessary, otherwise a null string
 */
function notfirst(evt) {
	var elem = getTarget(evt);
	if (elem.selectedIndex === 0) {
		return displayError(elem, 'notfirst', 'Please pick something other than the first choice.');
	} else {
		removeErrorNode(elem, 'notfirst');
		return '';
	}
}

/**
 * <p>Called if this form element cannot have more than a certain number 
 * of words.  Sites requiring short answers, interview questions, etc would
 * benifit from it availablity.  <em>ex.: maxwords="250"</em> would keep
 * any response more than 250 from progressing through.</p>
 * <p>Words are specified by being seperated with a space.  Words 
 * seperated with new line characters, commas, and other values not 
 * associated with a space, will not be counted with this version.  
 * Future updates might allow for those functions to take place.</p>
 * @param {Event} evt	The event (usually onblur) which caused this 
 * 		function to be called.
 * @type	String
 * @return	an error message is necessary, otherwise a null string
 */
function maxwords(evt) {
	var elem = getTarget(evt);
	
	var arr = elem.value.split(' ');
	var wordCnt = arr.length;
	if(wordCnt > elem.getAttribute('maxwords')) {
		return displayError(elem, 'maxwords', 'The field ' + fixNaming(elem.name) + ' has too many words. ' +
			'You shouldn\'t have more than ' + elem.getAttribute('maxwords') + 
			' words. You have ' + wordCnt + ' words.');
	} else {
		removeErrorNode(elem, 'maxwords');
		return '';
	}
}

/**
 * <p>Called if this form element is supposed to be a standard 10 digit 
 * US phone number (area code plus phone number).  It will accept numbers
 * and seperators only, so vanity phone numbers ex.: (800) my-teeth, will  
 * not validate.
 * <em>ex.: usphone="usphone"</em>.</p>
 * <p>This attribute will allow standard phone numbers to be used such 
 * as:<br />
 * 407-555-1234<br />
 * 407.555.1234<br />
 * 407 555 1234<br />
 * (407)555-1234<br />
 * (407) 555-1234
 * </p>
 * <p>Note: This attribute does not check to see if the phone number is a 
 * legitimate value, only that it is a legitimate format. i.e. someone could 
 * enter 407-555-1234, which is not legal, but in the correct format.</p> 
 * @param {Event} evt	The event (usually onblur) which caused this function to be called.
 * @type	String
 * @return	an error message is necessary, otherwise a null string
 */
function usphone(evt) {
	var elem = getTarget(evt);
	var reg = /^[2-9][0-9]{2}([-. ])[2-9][0-9]{2}\1[0-9]{4}$/;
	var reg2 = /^\([2-9][0-9]{2}\)[ ]*[2-9][0-9]{2}[- \.][0-9]{4}$/;
	elem.value = trim(elem.value);
	
	var tested = meetsRegEx(elem.value, reg) || meetsRegEx(elem.value, reg2);
	if(!tested) {
		return displayError(elem, 'usphone', 'The field ' + fixNaming(elem.name) + ' is not a valid phone number.');
	} else {
		removeErrorNode(elem, 'usphone');
		return '';
	}
}

/**
 * <p>Called if this form element is supposed to be 5 digit or 9 digit 
 * zip code.</p>
 * <p>This attribute will allow standard zip codes to be used such 
 * as:<br />
 * 32712<br />
 * 32712-1234
 * </p>
 * <p>Note: This attribute does not check to see if the zip code is a 
 * legitimate value, only that it is a legitimate format.</p> 
 * @param {Event} evt	The event (usually onblur) which caused this 
 * 		function to be called.
 * @type	String
 * @return	an error message is necessary, otherwise a null string
 */
function zipcode(evt) {
	var elem = getTarget(evt);
	var reg = /^\d{5}\-\d{4}|\d{5}$/;
	
	if(!meetsRegEx(elem.value, reg)) {
		return displayError(elem, 'zipcode', 'The field ' + fixNaming(elem.name) + ' is not a valid US zip code.');
	} else {
		removeErrorNode(elem, 'zipcode');
		return '';
	}
}

/**
 * <p>Called if this form element is supposed to be in the form of US 
 * currency (US dollars).  This does not allow for commas for thousand
 * places, but does require the decimal and two digits for the cents.  
 * The dollar sign is also required for the start of the value. 
 * <em>ex.: uscurrency="uscurrency"</em></p>
 * <p>This attribute will allows for:<br />
 * $123.45<br />
 * $0.99
 * </p>
 * @param {Event} evt	The event (usually onblur) which caused this function to be called.
 * @type	String
 * @return	an error message is necessary, otherwise a null string
 */
function uscurrency(evt) {
	var elem = getTarget(evt);
	var reg = /^\$\d+(\.\d\d){0,1}$/;
	
	if(!meetsRegEx(elem.value, reg)) {
		return displayError(elem, 'uscurrency', 'The field ' + fixNaming(elem.name) + ' is not a valid US Currency.');
	} else {
		removeErrorNode(elem, 'uscurrency');
		return '';
	}
}

/**
 * <p>This attribute is used to check to see that the form element is using
 * a SSN format.  It will support dashes or spaces between the number 
 * groupings, as well as leaving them out.  <em>ex.: ssn="ssn"</em></p>
 * <p>This attribute will allows for:<br />
 * 123-45-6789<br />
 * 123 45 6789<br />
 * 123456789
 * </p>
 * <p>Note: This attribute does not check to see if theSSN is valid for
 * a living individual, only that it is a legitimate format.</p> 
 * @param {Event} evt	The event (usually onblur) which caused this function to be called.
 * @type	String
 * @return	an error message is necessary, otherwise a null string
 */
function ssn(evt) {
	var elem = getTarget(evt);
	var reg = /^\d{3}([- ])?\d{2}\1?\d{4}$/;

	if(!meetsRegEx(elem.value, reg)) {
		return displayError(elem, 'ssn', 'The field ' + fixNaming(elem.name) + ' is not a valid US Social Security Number.');
	} else {
		removeErrorNode(elem, 'ssn');
		return '';
	}	
}

/**
 * <p>Called if this form element is a time value of hours and minutes.</p>
 * <p>This attribute will allows for:<br />
 * 9:45<br />
 * 9:45 am<br />
 * 9:45 AM
 * </p>
 * <p>This formating does not allow for 24 hour time telling, sometimes 
 * called "Military Format".  It also does not allow for time zones to be
 * included with the time.  Given the number of time zones (there are 
 * more than 24 depending upon country location) it would be impractical
 * to include that information.  Likewise, most people do not know their
 * +/- GMT value, so it is not valid for this time pattern.</p>
 * @param {Event} evt	The event (usually onblur) which caused this function to be called.
 * @type	String
 * @return	an error message is necessary, otherwise a null string
 */
function time(evt) {
	var elem = getTarget(evt);
	var reg = /^([1-9]|1[0-2]):[0-5]\d( (am|pm|AM|PM))?$/;

	if(!meetsRegEx(elem.value, reg)) {
		return displayError(elem, 'time', 'The field ' + fixNaming(elem.name) + ' is not a valid standard time.');
	} else {
		removeErrorNode(elem, 'time');
		return '';
	}	
}

/**
 * <p>Called if this form element is a US formated date value 
 * (month-day-year). Two seperators are supported including the slash and 
 * the dash. Use of the seperators must be consistant.</p>
 * <p>This attribute will allows for:<br />
 * 6/7/2007<br />
 * 06/7/2007<br />
 * 6/07/2007<br />
 * 06/07/2007<br />
 * 6/7/07<br />
 * 06/07/07<br />
 * et cetra.  Dashes may also replace the slashes.
 * </p>
 * @param {Event} evt	The event (usually onblur) which caused this function to be called.
 * @type	String
 * @return	an error message is necessary, otherwise a null string
 */
function usdate(evt) {
	var elem = getTarget(evt);
	var reg =  /^(1[0-2]|0?[1-9])(\-|\/)([0-2]?0?[\d]|3[01])(\2)\d{2,4}$/;

	if(!meetsRegEx(elem.value, reg)) {
		return displayError(elem, 'usdate', 'The field ' + fixNaming(elem.name) + ' is not a valid standard time.');
	} else {
		removeErrorNode(elem, 'usdate');
		return '';
	}	
}

/**
 * <p>Called if this form element is an international formated date 
 * value (year-month-day). Three seperators are supported including the 
 * slash, the dash, and the period.  Use of the seperators must be 
 * consistant.  The year may be in 2 digit or 4 digit format.</p>
 * <p><strong>Note:</strong> This will not make the entry {@link requried}. 
 * You must add that attribute to the form element as well if you 
 * require this form element to have a value.</p>
 * @param {Event} evt	The event (usually onblur) which caused this function to be called.
 * @type	String
 * @return	an error message is necessary, otherwise a null string
 */
function internationaldate(evt) {
	var elem = getTarget(evt);
	var reg = /^\d{2,4}(\-|\/\.)(1[0-2]|[1-9])(\1)([0-2]?[\d]|3[01])$/;

	if(!meetsRegEx(elem.value, reg)) {
		return displayError(elem, 'intdate', 'The field ' + fixNaming(elem.name) + ' is not a valid standard time.');
	} else {
		removeErrorNode(elem, 'intdate');
		return '';
	}	
}

/**
 * <p>Called if this form element can contain only letters and numbers.
 * No special characters or formatters are allowed.</p>
 * <p><strong>Note:</strong> This will not make the entry {@link requried}. 
 * You must add that attribute to the form element as well if you 
 * require this form element to have a value.</p>
 * @param {Event} evt	The event (usually onblur) which caused this function to be called.
 * @type	String
 * @return	an error message is necessary, otherwise a null string
 */
function alphanumeric(evt) {
	var elem = getTarget(evt);
	var reg = /^([a-zA-Z\d])*$/;

	if(!meetsRegEx(elem.value, reg)) {
		return displayError(elem, 'alphanumeric', 'The field ' + fixNaming(elem.name) + ' must be only letters and/or numbers.');
	} else {
		removeErrorNode(elem, 'alphanumeric');
		return '';
	}
}

/**
 * <p>Called if this form element can contain only numbers. No letters, 
 * or special symbols will be included.  A single decimal place is 
 * allowed to seperate the space between the whole number and the decimal,
 * value, however, the comma, used to group numbers, is not allowed, nor
 * is the period allowed to group numbers.</p>
 * <p><strong>Note:</strong> This will not make the entry {@link requried}. 
 * You must add that attribute to the form element as well if you 
 * require this form element to have a value.</p>
 * @param {Event} evt	The event (usually onblur) which caused this function to be called.
 * @type	String
 * @return	an error message is necessary, otherwise a null string
 */
function numeric(evt) {
	var elem = getTarget(evt);
	var reg = /^(\d*|\d*\.\d+)$/;

	if(!meetsRegEx(elem.value, reg)) {
		return displayError(elem, 'numeric', 'The field ' + fixNaming(elem.name) + ' must be only numbers.');
	} else {
		removeErrorNode(elem, 'numeric');
		return '';
	}
}

/**
 * <p>Called if this form element can contain only letters. No numbers, 
 * or special symbols will be included.</p>
 * <p><strong>Note:</strong> This will not make the entry {@link requried}. 
 * You must add that attribute to the form element as well if you 
 * require this form element to have a value.</p>
 * @param	{Event} evt	The event (usually onblur) which caused this function to be called.
 * @type	String
 * @return	an error message is necessary, otherwise a null string
 * @see #required
 */
function alpha(evt) {
	var elem = getTarget(evt);
	var reg = /^([a-zA-Z])*$/;

	if(!meetsRegEx(elem.value, reg)) {
		return displayError(elem, 'alpha', 'The field ' + fixNaming(elem.name) + ' must be only letters.');
	} else {
		removeErrorNode(elem, 'alpha');
		return '';
	}
}

/**
 * <p>Called if this form element must match a regular expression. The 
 * regular expression to be matched is the value within the attribute 
 * regex.</p>
 * <p>This feature was added incase any potential areas that were not 
 * covered by the built in expresssions were needed.  With this attribute
 * those circumstances could be covered.  This might include things like 
 * product serial numbers, library card values, et cetera.</p>
 * @param {Event} evt	The event (usually onblur) which caused this 
 * function to be called.
 * @type	String
 * @return	an error message is necessary, otherwise a null string
 */
function regex(evt) {
	var elem = getTarget(evt);
	var reg = elem.getAttribute('regex');

	if(!meetsRegEx(elem.value, reg)) {
		return displayError(elem, 'regex', 'The field ' + fixNaming(elem.name) + ' does not match the appropriate pattern.');
	} else {
		removeErrorNode(elem, 'regex');
		return '';
	}
}

/**
 * <p>The value of this form element must match another form element's, 
 * value. The form element to match against is the value of the matches
 * attribute. <em>ex.: matches="password"</em> could be used on a confirm
 * password field, that requires the passwords to match. The value in the 
 * attribute should be the form elements id.  If the HTML document is well 
 * formed, this will keep the elements from potentially having the same 
 * name in two different forms.</p>
 * <p><strong>Note:</strong> This will not make the entry {@link requried}. 
 * You must add that attribute to the form element as well if you 
 * require this form element to have a value.  However, if the form 
 * element which this element is supposed to match, has the required 
 * attribute, then essentially this form element also gets that benifit
 * because they two values must match.</p>
 * @param {Event} evt	The event (usually onblur) which caused this function to be called.
 * @type	String
 * @return	an error message is necessary, otherwise a null string
 */
function matches(evt) {
	var elem = getTarget(evt);
	var dup = document.getElementById(elem.getAttribute('matches'));
	
	if(elem.value != dup.value) {
		return displayError(elem, 'matches', 'The field ' + fixNaming(elem.name) + ' does not match ' + fixNaming(elem.getAttribute('matches')) );
	} else {
		removeErrorNode(elem, 'matches');
		return '';
	}
}

/**
 * <p>The number in the given field must be larger than the field 
 * associated as the value in the attribute numgt.</p>
 * <p><strong>Note:</strong> This will not make the entry {@link requried}. 
 * You must add that attribute to the form element as well if you 
 * require this form element to have a value.  However, if the form 
 * element which this element is supposed to match, has the required 
 * attribute, then essentially this form element also gets that benifit
 * because they two values must match.</p>
 * @param {Event} evt	The event (usually onblur) which caused this function to be called.
 * @type	String
 * @return	an error message is necessary, otherwise a null string
 */
function numgt(evt) {
	var elem = getTarget(evt);
	var tgt = document.getElementById(elem.getAttribute('numgt'));
	
	if(elem.value <= document.getElementById(tgt).value ) {
		return displayError(elem, 'numgt', 'The field ' + fixNaming(elem.name) + ' is not greater than ' + fixNaming(elem.getAttribute('numgt')) );
	} else {
		removeErrorNode(elem, 'numgt');
		return '';
	}
}

/**
 * <p>The number in the given field must be larger than or equal to the 
 * field associated as the value in the attribute numgt.</p>
 * <p><strong>Note:</strong> This will not make the entry {@link requried}. 
 * You must add that attribute to the form element as well if you 
 * require this form element to have a value.  However, if the form 
 * element which this element is supposed to match, has the required 
 * attribute, then essentially this form element also gets that benifit
 * because they two values must match.</p>
 * @param {Event} evt	The event (usually onblur) which caused this function to be called.
 * @type	String
 * @return	an error message is necessary, otherwise a null string
 */
function numgte(evt) {
	var elem = getTarget(evt);
	var tgt = document.getElementById(elem.getAttribute('numgt'));
	
	if(elem.value < document.getElementById(tgt).value ) {
		return displayError(elem, 'numgte', 'The field ' + fixNaming(elem.name) + ' is not greater than ' + fixNaming(elem.getAttribute('numgte')) );
	} else {
		removeErrorNode(elem, 'numgte');
		return '';
	}
}