function in_array ($needle, $haystack, $strict) {
	
	/* declare variables */
	var $haystackIndex, $boolStrict;
	
	/* set variable -- $haystackIndex */
	$haystackIndex = 0;
	
	/* set variable -- $boolStrict */
	$boolStrict = !!$strict;
	
	/* loop through $nodes */
	while (($haystackIndex < $haystack.length)) {
		
		/* check if $needle is in $haystack */
		if ((($boolStrict) || (typeof $haystack [$haystackIndex] == typeof $needle)) &&
				($haystack [$haystackIndex] == $needle)) {
			
			/* match */
			return true;
		}
		
		/* Increment $haystackIndex by 1 */
		$haystackIndex = $haystackIndex + 1;
	}
	
	/* no match */
	return false;
}

function validateDate ($date) {
	
	var $dateRegExp = new RegExp ('^\\d{2}\/\\d{2}\/\\d{4}$', 'g');
	
	return $dateRegExp.test ($date);
}

function validateZipCode ($zipCode) {
	
	var $zipCodeRegExp = new RegExp ('^\\d{5}(?:-\\d{4})?$', 'g');
	
	return $zipCodeRegExp.test ($zipCode);
}

function validPhone ($phone) {
	
	var $phoneRegExp = new RegExp ('^(1\\s*[-\/\.]?)?(\\((\\d{3})\\)|(\\d{3}))\\s*[-\/\.]?\\s*(\\d{3})\\s*[-\/\.]?\\s*(\\d{4})\\s*(([xX]|[eE][xX][tT])\\.?\\s*(\\d+))*$', 'g');
	
	return $phoneRegExp.test ($phone);
}

function validEmail ($email) {
	
	var $emailRegExp = new RegExp ('\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*([,;]\\s*\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*)*', 'g');
	
	return $emailRegExp.test ($email);
}

function validURL ($url) {
	
	var $urlRegExp = new RegExp ('^((http|ftp|https):\\/\\/)?[\\w\\-_]+(\.[\\w\\-_]+)+([\\w\\-\\.,@?^=%&amp;:/~\+#]*[\\w\\-\\@?^=%&amp;/~\\+#])?$', 'g');
	
	return $urlRegExp.test ($url);
}

function validate ($form) {
	
	/* declare variables */
	var $node, $nodeIndex, $nodeName, $nodes;
	var $nodeInputType, $nodeNameAttr, $nodeValue;
	var $nodeNameAttrs, $nodesByNodeNameAttr;
	var $nodesByNodeNameAttrIndex, $noInput, $ignoreOtherExtras;
	var $nameAttrParts, $nameAttrPart, $namePartIndex;
	var $namePartExtras, $alertFirstNode, $alertMessages;
	var $nodeNameAttrName, $namePartIndex, $isRequired;
	var $nodesByNodeNameAttr2;
	
	/* set variable -- $nodes */
	$nodes = $form.elements;
	
	/* set variable -- $nodeNameAttrs */
	$nodeNameAttrs = [];
	
	/* set variable -- $alertMessages */
	$alertMessages = [];
	
	/* loop through $nodes */
	for (($nodeIndex = 0); ($nodeIndex < $nodes.length); ($nodeIndex = $nodeIndex + 1)) {
		
		/* set variable -- $node */
		$node = $nodes [$nodeIndex];
		
		/* set variable -- $nodeName */
		$nodeName = $node.nodeName.toLowerCase ();
		
		/* set variable -- $nodeNameAttr */
		$nodeNameAttr = $node.getAttribute ('name');
		
		/* check if not null -- $nameAttr */
		if (($nodeNameAttr != null)) {
			
			/* switch -- $nodeName */
			switch (($nodeName)) {
				
				/* skip these nodes */
				case 'button'		: 
				case 'fieldset'	: continue;
				
				/* validate -- input */
				case 'input'		: 
					
					/* set variable -- $nodeInputType */
					$nodeInputType = $node.type.toLowerCase ();
					
					/* switch -- $nodeInputType */
					switch (($nodeInputType)) {
						
						/* multiple nodes with same name -- execute once */
						case 'checkbox'	: 
						case 'radio'		: 
							
							/* check if not in array already */
							if ((!in_array ($nodeNameAttr, $nodeNameAttrs))) {
								
								/* get all elements by that name */
								$nodesByNodeNameAttr = $nodes [$nodeNameAttr];
								
								/* check if array */
								if (($nodesByNodeNameAttr.length)) {
									
									/* set variable -- $noInput */
									$noInput = true;
									
									/* set variable -- $nodesByNodeNameAttrIndex */
									$nodesByNodeNameAttrIndex = 0;
									
									/* loop through $nodesByNodeNameAttr */
									while (($nodesByNodeNameAttrIndex < $nodesByNodeNameAttr.length)) {
										
										/* check if checked */
										if (($nodesByNodeNameAttr [$nodesByNodeNameAttrIndex].checked)) {
										
											/* set variable -- $noInput */
											$noInput = false;
											
											/* set variable -- $nodeValue */
											$nodeValue = $nodesByNodeNameAttr [$nodesByNodeNameAttrIndex].value;
											
											/* break out */
											break;
										}
										
										/* Increment $nodesByNodeNameAttrIndex by 1 */
										$nodesByNodeNameAttrIndex = $nodesByNodeNameAttrIndex + 1;
									}
								} else { /* single element */
									
									/* set variable -- $noInput */
									$noInput = true;
									
									/* check if checked */
									if (($nodesByNodeNameAttr.checked)) {
										
										/* set variable -- $noInput */
										$noInput = false;
										
										/* set variable -- $nodeValue */
										$nodeValue = $nodesByNodeNameAttr.value;
									}
								}
								
								/* add nodeNameAttr to nodeNameAttrs */
								$nodeNameAttrs [$nodeNameAttrs.length] = $nodeNameAttr;
							} else {
								
								/* set variable -- $noInput */
								$noInput = false;
							}
							
							/* break out of switch */
							break;
						
						/* text and password */
						case 'password'		: 
						case 'text'			: 
							$nodeValue = $node.value;
							break;
						
						/* skip these types of node */
						case 'button'		: 
						case 'file'			: 
						case 'hidden'		: 
						case 'image'		: 
						case 'reset'		: 
						case 'submit'		: continue;
					}
					
					/* break out of switch */
					break;
				
				/* validate -- select */
				case 'select'		: 
					
					/* set variable -- $nodeValue */
					$nodeValue = $node.options [$node.selectedIndex].value;
					
					/* break out of switch */
					break;
				
				/* validate -- textare */
				case 'textarea'	: 
					
					/* set variable -- $nodeValue */
					$nodeValue = $node.value;
					
					/* break out of switch */
					break;
			}
			
			/* set variable -- $nameAttrParts */
			$nameAttrParts = $nodeNameAttr.split ('+');
			
			/* set variable -- $nodeNameAttrName */
			$nodeNameAttrName = $nameAttrParts [0].split ('_').join (' ');
			
			$isRequired = false;
			
			if ((in_array ('r', $nameAttrParts))) {
				
				if (($nodeName == 'input') && (($nodeInputType == 'checkbox') || ($nodeInputType == 'radio'))) {
					
					if (($noInput)) {
						$alertMessages [$alertMessages.length] = 'The ' + $nodeNameAttrName + ' field is required.';
					}
				} else if (!$nodeValue) {
					
					$alertMessages [$alertMessages.length] = 'The ' + $nodeNameAttrName + ' field is required.';
				}
				
				$isRequired = true;
			}
			
			if (($isRequired) || ((!$nodeValue) || ($noInput))) {
				
				/* set variable -- $ignoreOtherExtras */
				$ignoreOtherExtras = false;
				
				/* conditional check check */
				if ((in_array ('cnd', $nameAttrParts))) {
					
					/* set variable -- $ignoreOtherExtras */
					$ignoreOtherExtras = true;
				}
				
				/* loop through $nameAttrParts -- start at 1 */
				for (($namePartIndex = 1); ($namePartIndex < $nameAttrParts.length); ($namePartIndex = $namePartIndex + 1)) {
					
					/* set variable -- $nameAttrPart */
					$nameAttrPart = $nameAttrParts [$namePartIndex];
					
					/* set variable -- $namePartExtras */
					$namePartExtras = $nameAttrPart.split ('-');
					
					/* set variable -- $nameAttrPart */
					$nameAttrPart = $namePartExtras [0].toLowerCase ();
					
					/* set variable -- $namePartExtras */
					$namePartExtras = $namePartExtras.slice (1);
					
					/* switch -- $nameAttrPart */
					switch (($nameAttrPart)) {
						
						case 'd': // date
							if ((!$ignoreOtherExtras) && (!validateDate ($nodeValue))) {
								$alertMessages [$alertMessages.length] = 'The ' + $nodeNameAttrName +
									' field does not satisfy a valid date structure.';
							}
							break;
						case 'z': // zipcode
							if ((!$ignoreOtherExtras) && (!validateZipCode ($nodeValue))) {
								$alertMessages [$alertMessages.length] = 'The ' + $nodeNameAttrName +
									' field does not satisfy a valid zipcode structure.';
							}
							break;
						case 'e': // email
							if ((!$ignoreOtherExtras) && (!validEmail ($nodeValue))) {
								$alertMessages [$alertMessages.length] = 'The ' + $nodeNameAttrName +
									' field does not satisfy a valid email structure.';
							}
							break;
						case 'p': // phone
							if ((!$ignoreOtherExtras) && (!validPhone ($nodeValue))) {
								$alertMessages [$alertMessages.length] = 'The ' + $nodeNameAttrName +
									' field does not satisfy a valid phone structure.';
							}
							break;
						case 'u': // url
							if ((!$ignoreOtherExtras) && (!validURL ($nodeValue))) {
								$alertMessages [$alertMessages.length] = 'The ' + $nodeNameAttrName +
									' field does not represent a valid URL string.';
							}
							break;
						case 'n': // number -- optionals: unsigned
							if ((!$ignoreOtherExtras) && (isNaN (parseInt ($nodeValue)))) {
								$alertMessages [$alertMessages.length] = 'The ' + $nodeNameAttrName +
									' must be a of a number format.';
							} else if ((!$ignoreOtherExtras) && ($namePartExtras) && ($namePartExtras [0] == 'u') &&
								($nodeValue.charAt (0) == '-')) {
								$alertMessages [$alertMessages.length] = 'The ' + $nodeNameAttrName +
									' must be a of a non-negative number format.';
							}
							break;
						case 'cndt': // conditional
							
							$nodesByNodeNameAttr2 = $nodes [$namePartExtras [0].split ('__').join ('+')];
							if ($nodesByNodeNameAttr2) {
								if ($nodesByNodeNameAttr2.length) {
									$nodesByNodeNameAttrIndex = 0;
									while (($nodesByNodeNameAttrIndex < $nodesByNodeNameAttr2.length)) {
										
										/* check if checked */
										if ((($nodesByNodeNameAttr2 [$nodesByNodeNameAttrIndex].checked) || ($nodesByNodeNameAttr2 [$nodesByNodeNameAttrIndex].selected)) &&
											($nodesByNodeNameAttr2 [$nodesByNodeNameAttrIndex].value == $namePartExtras [1].split ('__').join ('+').split ('_').join (' '))) {
											
											if (($nodeName == 'input') && (($nodeInputType == 'checkbox') || ($nodeInputType == 'radio'))) {
												
												if (($noInput)) {
													$alertMessages [$alertMessages.length] = 'The ' + $nodeNameAttrName +
														' cannot be left blank';
												}
											} else if (!$nodeValue) {
												
												$alertMessages [$alertMessages.length] = 'The ' + $nodeNameAttrName +
													' cannot be left blank';
											}
										}
										
										/* Increment $nodesByNodeNameAttrIndex by 1 */
										$nodesByNodeNameAttrIndex = $nodesByNodeNameAttrIndex + 1;
									}
								} else {
									
									if (($nodesByNodeNameAttr2.value == $namePartExtras [1].split ('__').join ('+').split ('_').join (' '))) {
										
										if (($nodeName == 'input') && (($nodeInputType == 'checkbox') || ($nodeInputType == 'radio'))) {
											
											if (($noInput)) {
												$alertMessages [$alertMessages.length] = 'The ' + $nodeNameAttrName +
													' cannot be left blank';
											}
										} else if (!$nodeValue) {
											
											$alertMessages [$alertMessages.length] = 'The ' + $nodeNameAttrName +
												' cannot be left blank';
										}
									}
								}
							}
							break;
					}
				}
			}
			
			/* Set the first node to focus upon error  */
			if (($alertMessages.length) && (!$alertFirstNode)) $alertFirstNode = $node;
		}
	}
	
	/* check if we have something to alert to user */
	if (($alertMessages.length)) {
		
		/* alert the user */
		alert ($alertMessages.join ('\n'));
		
		/* focus the node if set */
		if (($alertFirstNode)) $alertFirstNode.focus ();
		
		/* cancel form submission */
		return false;
	}
	
	return true;
	
}
