validators = {
	'word': { regex: /^\w+$/, error_text: 'Must contain only letters and numbers' },
	'word_space': { regex: /^[\w\s]+$/, error_text: 'This field only allows letters, numbers, and spaces' },
	'allowed_chars': { regex: /^[\w\s\d\-\$\&\(\)_!+=;.,\/@"']+$/, error_text: 'This field only allows letters, numbers, spaces, and punctuation' },
	'date': { regex: /^\d{2}(\-|\/)\d{2}(\-|\/)\d{4}$/i, error_text: 'Date must be in form: DD/MM/YYYY (e.g. 25/01/1999)' },
	'date2': { regex: /^\d{2}(\-|\/)[a-z]{3}(\-|\/)\d{4}$/i, error_text: 'Date must be in form: DD/NNN/YYYY (e.g. 25/Jan/1999)' },
	'ansi_date': { regex: /^\d{4}(\-|\/)\d{2}(\-|\/)\d{2}$/, error_text: 'Date must be in form: YYYY/MM/DD (e.g. 1999/01/25)' },
	'ansi_time': { regex: /^(?:[01]?[0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?$/, error_text: 'Time must be in form: hh:mm::ss' },
	'email': { regex: /(^[\-\!\#\$\%\&\'\*\+\/\=\?\^\_\`\{\}\|\~a-z0-9]+(\.[\-\!\#\$\%\&\'\*\+\/\=\?\^\_\`\{\}\|\~a-z0-9]+)*)@(?:[a-z0-9\-]+\.)+[a-z]{2,6}$/i, error_text:'Invalid email address' },
	'integer': { regex: /^-?\d+$/, error_text: 'Must be a positive or negative integer' },
	'positive_int': { regex: /^\d+$/, error_text: 'Must be a positive integer' },
	'decimal': { regex: /^-?\d+\.?\d+$/, error_text: 'Must be a positive or negative decimal value' },
	'money': { regex: /^((\d+(\.\d{1,2})?)|\.\d{1,2})$/, error_text: 'Must be a positive amount in the form of X.XX' },
	'phone': { regex: /^[A-PR-Y0-9]{3}-[A-PR-Y0-9]{3}-[A-PR-Y0-9]{4}$/i, error_text: 'Invalid phone number' },
	'url': { regex: /^https?:\/\/\S+$/, error_text: 'Invalid url'},
	'password': { regex: /^.{6,12}$/, error_text: "Password must consist of letters and numbers and be between 6 and 12 characters in length" },
	'password_hard': { regex: /(?=^.{8,30}$)(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*()_+}{\'\":;?/>.<,]).*$/, error_text: "Password must be at least 8 characters in length and contain at least one lowercase character, one capital letter, one digit, and one special character" }
}

function validate(arrFields, kwargs)
{
	kwargs = kwargs || {};
	var skipValidation = kwargs.skipValidation === true; // Default to false. Normally we don't skip js validation, but if we want to rely just on the server's validation, we can set skipValidation = true

	var objReturn = {};
	objReturn.fields = arrFields;
	objReturn.values = {};
	objReturn.isValid = true;

	// When filling in a form in a modal, ensure that there aren't any conflicts with the page underneath (in case there are any identical ids)
	var prefix = isModalOpen() ? "#nimble_modal " : "";
	objReturn.prefix = prefix;

	for (var i = 0; i < arrFields.length; i ++)
	{
		var field = arrFields[i] || {'id' : '_nonexistent'};
		var required = field.required !== false; // default to required = true;
		var domField = $(prefix + poundFirst(field.id));
		if (domField.length == 0)
			continue;

		var value = "";
		var htmlField = null;
		if (domField.length == 1)
			htmlField = domField[0];

		if (htmlField.type == "radio" || htmlField.type == "checkbox")
		{
			if (htmlField.checked)
				value = htmlField.value;
			else
				continue;
		}
		else
			value = htmlField.value;

		if (!skipValidation) // Not skipping validation
		{
			if (required)
			{
				if (!testNullString(value))
				{
					objReturn.isValid = false;

					if (field.errors)
						field.errors.push("Field is required");
					else
						field.errors = ["Field is required"];
					continue;
				}
			}

			if (testNullString(value))
			{
				var arrValidators = [];
				var tmp = field.validators;
				if (typeof(tmp) != "undefined")
				{
					if (typeof(tmp) == "string")
						arrValidators = [validators[tmp]];
					else
						arrValidators = tmp;
				}

				for (var j = 0; j < arrValidators.length; j ++)
				{
					var curValidator = arrValidators[j];

					if (typeof(curValidator) == "string")
						curValidator = validators[curValidator];

					if (!curValidator.regex.test(value))
					{
						objReturn.isValid = false;
						var error_text = curValidator.error_text || "";

						if (field.errors)
							field.errors.push(error_text);
						else
							field.errors = [error_text];
					}
				}
			}
			else // not required, nothing provided...
				value = field.default_value || "";
		}
		else // Skipping validation
			value = value || field.default_value || "";

		if (field.skip !== true)
			objReturn.values[field.alias || field.id] = value;
	}
	
	return objReturn;
}


// Any refs to 'form' are meant to be the type of object returned by 'validate' above
function clearErrors(form, resetForm)
{
	var prefix = form.prefix || "";
	for (var i = 0; i < form.fields.length; i ++)
	{
		try {
			var tmp = $(prefix + "#"+ form.fields[i].id)
			tmp.removeClass("error");
			if (resetForm)
			{
				tmp.val('');
				tmp.blur();
			}
		}
		catch(e){}
	}
}

function alertInvalidForm(form, boolResetForm)
{
	var prefix = form.prefix || "";
	for (var i = 0; i < form.fields.length; i ++)
	{
		var curField = form.fields[i];
		try {
			if (curField.errors)
				$(prefix + poundFirst(curField.id)).addClass("error");
			else
				$(prefix + poundFirst(curField.id)).removeClass("error");
		}
		catch(e){}
	}
}


