if (typeof com == "undefined") { com = {}; }
if (typeof com.digitaria == "undefined") { com.digitaria = {}; }

/**
 * Sets up the validator for the page.
 * Allows you to override most of the settings for the system.
 * You can also override when performing individual validations.
 *
 * @returns {void}
 * @param {hash} settings Pass any settings overrides you wish through here.
 * @param {string} settings.classValidate This is the class to check for, on form elements, that indicates they should be validated. With this class alone, they will be validated as non "".
 * @param {string} settings.classEmail This is the class to check for, on form elements, when you want to validate them as email addresses.
 * @param {string} settings.className This is the class to check for, on form elements, when you want to validate them as names.
 * @param {string} settings.classZip This is the class to check for, on form elements, when you want to validate them as zip codes.
 *
 * @param {string} settings.classMatchPrefix This is the prefix of a class. For example, if you want to check a field matches the field with id MyField, you would add the class [settings.classMatchPrefix]MyField - i.e. validMatchMyField with the default value.
 *
 * @param {string} settings.classError This is the class that gets added to fields, their rows and the form, when there're errors.
 *
 * @param {string} settings.expressionParent This is a CSS expression that's used to match parent elements of the field that doesn't validate, to then apply the error class to them. With the default value of .formRow, it will look for all .formRow parents of the field and apply settings.classError to them.
 * @param {boolean} revCountsAsEmpty If this is true and the field has a rev value, if the field's value matches the rev value, it'll also count as empty. This way, we can pass in default values that we want to also count as empty.
 * @author Nick Davison
 */
com.digitaria.validator=function(settings) {
	this.settings=jQuery.extend({
		classValidate: "validate",
		
		classEmail: "validEmail",
		className: "validName",
		classZip: "validZip",
		
		classMatchPrefix: "validMatch",
		
		classError: "validatorError",
		
		expressionParent: '.formRow',
		
		revCountsAsEmpty: false
	}, settings);
	
	this.checkEmail = new RegExp(/^([\w-]+\.)*?[\w-]+@[\w-]+\.([\w-]+\.)*?[\w]+$/);
	this.checkName = new RegExp(/^[a-zA-Z\'\-\s\.]{1,35}$/);
	this.checkZip = new RegExp(/^(\d{5}-\d{4}|\d{5}|\d{9})$|^([a-zA-Z]\d[a-zA-Z] \d[a-zA-Z]\d)$/);
}

/**
 * Add the error class to a field (and its appropriate parents).
 * @returns {void}
 * @param {jQuery} field The field we're applying to.
 * @param {hash} settings Allows overriding of the default settings.
 * @author Nick Davison
 */
com.digitaria.validator.prototype.showError=function(field, settings) {
	// Allow settings to be overridden
	var settings=jQuery.extend(this.settings, settings);
		
	// Ensure the field is in jQuery form
	var field=$(field);
	
	// Add the error class to the element itself
	field.addClass(settings.classError);
	
	// Add the error class to any parent elements that matcht the expressionParent setting
	field.parents(settings.expressionParent).addClass(settings.classError);
}

/**
 * Remove the error class to a field (and its appropriate parents).
 * @returns {void}
 * @param {jQuery} field The field we're applying to.
 * @param {hash} settings Allows overriding of the default settings.
 * @author Nick Davison
 */
com.digitaria.validator.prototype.hideError=function(field, settings) {
	// Allow settings to be overridden
	var settings=jQuery.extend(this.settings, settings);
		
	// Ensure the field is in jQuery form
	var field=$(field);
	
	// Remove the error class to the element itself
	field.removeClass(settings.classError);
	
	// Remove the error class to any parent elements that matcht the expressionParent setting
	field.parents(settings.expressionParent).removeClass(settings.classError);
}

/**
 * Perform validation of a form.
 * 
 * <p>It will go through all elements with class [settings.classValidate] that are either an input, select or textarea.
 * Each one is then checked for classes to indicate what types of validation should be performed.
 * If successfully validated, any prior errors will be stripped via hideError().
 * If unsuccessfully validated, the [settings.classError] will be applied via showError().
 * If ANY elements were unsuccessfully validated, the form will gain the error class and we return false.
 * Otherwise, the form is stripped of the error class and we return true.</p>
 *
 * @returns {boolean}
 * @param {jQuery} form The form we're validating.
 * @param {hash} settings Allows overriding of the default settings.
 * @author Nick Davison
 */
com.digitaria.validator.prototype.validate=function(form, settings) {
	var _thisValidator=this;
	
	// Ensure the form is jQuery friendly
	var form=$(form);
	
	// Allow settings to be overridden
	var settings=jQuery.extend(this.settings, settings);
	
	// Store whether the form validates or not.
	var isValid=true;
	
	// Find all elements with the validate class within the form
	$('.'+settings.classValidate, form).each(function() {
		var $_this=$(this);
		
		// Only perform checks on inputs, selects, textareas
		if ($_this.is("input, select, textarea")) {
			
			var thisIsValid=true;
														  
			// Handle everything other than checkboxes
			if (!$_this.is(':checkbox')) {
				var val=$_this.val(); // Get the current value
				
				if (val=="") { // Check for empty strings
					thisIsValid=false;
				} else if ((settings.revCountsAsEmpty) && (val==$_this.attr('rev'))) { // If revCountsAsEmpty is true and the value is the same as the rev
					thisIsValid=false;									
				} else {
					// Check for emails
					if ($_this.is('.'+settings.classEmail)) {
						if (!_thisValidator.checkEmail.test(val)) thisIsValid=false;
					}
					// Check for names
					if ($_this.is('.'+settings.className)) {
						if (!_thisValidator.checkName.test(val)) thisIsValid=false;
					}
					// Check for zips
					if ($_this.is('.'+settings.classZip)) {
						if (!_thisValidator.checkZip.test(val)) thisIsValid=false;
					}
					
					// Check for matches - these are a bit more involved
					// First see if the prefix exists anywhere in the class string
					if (this.className.toString().indexOf(settings.classMatchPrefix)!=-1) {
						// If it does, break out all of the classes
						var classes=this.className.toString().split(" ");
						// Go through the classes
						for (var i=0; i<classes.length; i++) {
							// If the class starts with the prefix
							if (classes[i].indexOf(settings.classMatchPrefix)==0) {
								// Grab everything after the prefix
								var matchId=classes[i].substring(settings.classMatchPrefix.toString().length);
								// If the element with that id's val doesn't match the current val
								if ($('#'+matchId).val()!=val) {
									// The field fails
									thisIsValid=false;
								}
							}
						}
					}
				}
			} else { // Handle checkboxes - all they get is checking they're checked.
				if (!this.checked) {
					thisIsValid=false;
				}
			}
			
			if (thisIsValid) { // If the field's valid, show it as valid
				_thisValidator.hideError($_this, settings);
			} else { // If the field's invalid, show it as invalid and invalidate the form
				_thisValidator.showError($_this, settings);
				isValid=false;
			}
		}
	});
	
	// Depending on whether the whole form had any errors or no errors, add or remove classError from the form itself.
	if (isValid) {
		form.removeClass(settings.classError);
	} else {
		form.addClass(settings.classError);
	}
	
	// Return whether the form validated or not
	return isValid;
}

com.digitaria.initRevFieldDefaults=function() {
	$('input[rev], textarea[rev]').blur(function() {
		if ($(this).val()=="") { /* Set the rev on blur */
			$(this).val($(this).attr('rev'));
			$(this).addClass("inactive");
			$(this).removeClass("active");
		}
	 }).focus(function() { /* Clear the rev on focus */
		 if ($(this).val()==$(this).attr('rev')) {
			$(this).val('');
			$(this).addClass("active");
			$(this).removeClass("inactive");
		 }
	 }).each(function() { /* Initialize, setting any blanks to the revs */
		 if ( ($(this).val()=="") || ($(this).val()==$(this).attr('rev')) ) {
			$(this).val($(this).attr('rev'));
			$(this).addClass("inactive");
			$(this).removeClass("active");
		}
	 });
}
