﻿var errorsHeader = 'Please correct the following.\n\n';

function Validate(form, controlID, errorsHeader, regexElementIdFilter)
{
	// set up properties
	this.form = form;
	this.namespace = controlID;
	this.errors = '';
	this.setfocus = null;
	this.errorsHeader = errorsHeader;
	if (regexElementIdFilter)
	{
		this.regexElementIdFilter = regexElementIdFilter;
	}
	// set up attributes
	this.requiredAttribute = 'required';
	this.requiredEmptyAttribute = 'requiredEmpty';
	this.validationTypeAttribute = 'validationtype';
	this.regexAttribute = 'regex';
	this.minLengthAttribute = 'minlength';
	this.numericMinLengthAttribute = 'numericminlength';
	this.maxLengthAttribute = 'maxlength';
	this.numericMaxLengthAttribute = 'numericmaxlength';
	this.minValueAttribute = 'minvalue';
	this.maxValueAttribute = 'maxvalue';
	this.equalsAttribute = 'equals';
	
	// set up error handling attributes
	this.defaultErrorAttribute = 'error';
	this.requiredErrorAttribute = 'requirederror';
	this.validationTypeErrorAttribute = 'validationtypeerror';
	this.regexErrorAttribute = 'regexerror';
	this.minLengthErrorAttribute = 'minlengtherror';
	this.maxLengthErrorAttribute = 'maxlengtherror';
	this.minValueErrorAttribute = 'minvalueerror';
	this.maxValueErrorAttribute = 'maxvalueerror';
	this.equalsErrorAttribute = 'equalserror';
	
	// set up error handling default errors
	this.defaultError = '{name} is invalid.'
	this.defaultRequiredError = '{name} is required.';
	this.defaultValidationTypeError = '{name} is invalid.';
	this.defaultRegexError = '{name} is invalid.';
	this.defaultMinLengthError = '{name} is too short in length.';
	this.defaultMaxLengthError = '{name} is too long in length.';
	this.defaultMinValueError = '{name} must be greater than {minValue}.';
	this.defaultMaxValueError = '{name} must be less than {maxValue}.';
	this.defaultEqualsError = '{name} is not equal to {equals}';
	this.defaultNotEqualsError = '{name} cannot equal {equals}';
	
	// add methods to object
	this.run = run;
	this.validateSingleElement = validateSingleElement;
	this.outputErrors = outputErrors;
	this.checkFocus = checkFocus;
	this.setError = setError;
	this.cleanAttributeForErrorDisplay = cleanAttributeForErrorDisplay;
	this.validateRequired = validateRequired;
	this.validateType = validateType;
	this.validateRegex = validateRegex;
	this.validateMinLength = validateMinLength;
	this.validateMaxLength = validateMaxLength;
	this.validateMinValue = validateMinValue;
	this.validateMaxValue = validateMaxValue;
	this.validateEquals = validateEquals;
	this.isExemptFromValidation = isExemptFromValidation;
	
	// add validation type methods
	this.setValidateTypeError = setValidateTypeError;
	this.validateAmount = validateAmount;
	this.validateDate = validateDate;
	this.validateMod10 = validateMod10;
	this.validateNumeric = validateNumeric;
	
	//this.nonePattern = '^\.*$';
	this.stringPattern = '^.+$';	
	this.upperCaseStringPattern = '^[A-Z]([A-Z)|\s)*$';
	this.numericPattern = '^\\d+$';
	this.numericStripper = /\D/g;
	this.alphaNumericPattern = '^\\w+$';
	
	var amountSeparators = '(\\.|,)';
	this.amountPattern = '^(\\d+(' + amountSeparators + '\\d+)*)$';
	
	this.dateYearPattern = '^\\d{4}$';
	this.dateMonthPattern = '^\\d{2}$';
	this.dateDayPattern = '^\\d{2}$';
	
	var validEmailChars = '[^\:\,\;\#$\%\&\(\)\+\=\/ ]+';
	this.emailPattern = '^' + validEmailChars + '(\\.' + validEmailChars + ')?@' + validEmailChars + '(\\.' + validEmailChars + ')+$';

}

function run()
{
	// run validation on the form elements
	for (var i = 0; i < this.form.length; i++)
	{
		var e = this.form.elements[i];
		
		if (!this.isExemptFromValidation(e))
		{
			this.validateSingleElement(e);
		}
	}
	
	return this.outputErrors();
}

function isExemptFromValidation(e)
{
	if (e.id.indexOf(this.namespace) != 0)
	{
		return true;
	}
	
	if ((this.regexElementIdFilter) && (!e.id.match(this.regexElementIdFilter)))
	{
		return true;
	} 
	
	return false;
} 

function outputErrors()
{
	// if there is an error output it
	if(this.errors)
	{
		alert(this.errorsHeader + this.errors);
		
		if (this.setfocus)
		{
			this.setfocus.focus();
		}
		
		return false;
	}
	
	return true;
}

function validateSingleElement(e)
{
	this.validateRequired(e);
	// only validate the rest if they actually have something
	if (0 < e.value.length)
	{
		this.validateType(e);
		this.validateRegex(e);
		this.validateMinLength(e);
		this.validateMaxLength(e);
		this.validateMinValue(e);
		this.validateMaxValue(e);
		this.validateEquals(e);
	}
}

function checkFocus(e)
{
	if (!this.setfocus)
	{
		this.setfocus = e;
	}
}

function validateRequired(e)
{
	if((e.getAttribute(this.requiredAttribute) == 'true') && ((e.value.length < 1) || (e.value == e.getAttribute(this.requiredEmptyAttribute))))
	{
		this.setError(e, this.requiredErrorAttribute, this.defaultRequiredError);
	}
}

function validateType(e)
{
	var type = e.getAttribute(this.validationTypeAttribute);
	var value = e.value;
	
	if (type) 
	{
		if ((type == 'Address') && (!value.match(this.stringPattern)))
		{
			this.setValidateTypeError(e);
		}
		else if ((type == 'AlphaNumeric') && (!value.match(this.alphaNumericPattern)))
		{
			this.setValidateTypeError(e);
		}
		else if ((type == 'Amount') && (!this.validateAmount(value)))
		{
			this.setValidateTypeError(e);
		}
		else if ((type == 'Country') && (!value.match(this.stringPattern)))
		{
			this.setValidateTypeError(e);
		}
		else if ((type == 'Email') && (!value.match(this.emailPattern)))
		{
			this.setValidateTypeError(e);
		}
		else if ((type == 'Mod10') && (!this.validateMod10(value)))
		{
			this.setValidateTypeError(e);
		}
		else if ((type == 'Name') && (!value.match(this.stringPattern)))
		{
			this.setValidateTypeError(e);
		}
		else if ((type == 'Numeric') && (!this.validateNumeric(value)))
		{
			this.setValidateTypeError(e);
		}
		else if ((type.indexOf('Date') == 0) && (!this.validateDate(e, type, value)))
		{
			this.setValidateTypeError(e);
		}
		else if ((type == 'State') && (!value.match(this.stringPattern)))
		{
			this.setValidateTypeError(e);
		}
		else if ((type == 'String') && (!value.match(this.stringPattern)))
		{
			this.setValidateTypeError(e);
		}
		else if ((type == 'UpperCaseString') && (!value.match(this.upperCaseStringPattern)))
		{
			this.setValidateTypeError(e);
		}
		else if ((type == 'Zip') && (!value.match(this.stringPattern)))
		{
			this.setValidateTypeError(e);
		}
		
	}
}

function validateRegex(e)
{
	var regex = e.getAttribute(this.regexAttribute);
	if ((regex) && (!e.value.match(regex)))
	{
		this.setError(e, this.regexErrorAttribute, this.defaultRegexError);
	}
}

function validateMinLength(e)
{
	var length = e.getAttribute(this.minLengthAttribute);
	var numericLength = e.getAttribute(this.numericMinLengthAttribute);
	
	if ((0 < length) && (e.value.length < length))
	{
		this.setError(e, this.minLengthErrorAttribute, this.defaultMinLengthError);
	}
	else if ((0 < numericLength)  && (0 < e.value.length) && (e.value.replace(this.numericStripper, '').length < numericLength))
	{
		this.setError(e, this.minLengthErrorAttribute, this.defaultMinLengthError);
	}
}

function validateMaxLength(e)
{
	var length = e.getAttribute(this.maxLengthAttribute);
	var numericLength = e.getAttribute(this.numericMaxLengthAttribute);
				
	if ((0 < length) && (length < e.value.length))
	{
		this.setError(e, this.maxLengthErrorAttribute, this.defaultMaxLengthError);
	}
	else if ((0 < numericLength)  && (0 < e.value.length) && (numericLength < e.value.replace(this.numericStripper, '').length))
	{
		this.setError(e, this.maxLengthErrorAttribute, this.defaultMaxLengthError);
	} 
}

function validateMinValue(e)
{
	var min = e.getAttribute(this.minValueAttribute);
	
	if ((min != null) && (0 < min.length))
	{
		if ((5 < min.length) && (min.substring(0, 5) == '&gt;='))
		{
			if (e.value < parseFloat(min.substring(5, min.length)))
			{
				this.setError(e, this.minValueErrorAttribute, this.defaultMinValueError);
			}
		}
		else if ((4 < min.length) && (min.substring(0, 4) == '&gt;'))
		{
			if (e.value <= parseFloat(min.substring(4, min.length)))
			{
				this.setError(e, this.minValueErrorAttribute, this.defaultMinValueError);
			}
		}
		else if (e.value < parseFloat(min))
		{
			this.setError(e, this.minValueErrorAttribute, this.defaultMinValueError);
		}
	}
}

function validateMaxValue(e)
{
	var max = e.getAttribute(this.maxValueAttribute);
	
	if ((max != null) && (0 < max.length))
	{
		if ((5 < max.length) && (max.substring(0, 5) == '&lt;='))
		{
			if (e.value > parseFloat(max.substring(5, max.length)))
			{
				this.setError(e, this.maxValueErrorAttribute, this.defaultMaxValueError);
			}
		}
		else if ((4 < max.length) && (max.substring(0, 4) == '&lt;'))
		{
			if (e.value >= parseFloat(max.substring(4, max.length)))
			{
				this.setError(e, this.maxValueErrorAttribute, this.defaultMaxValueError);
			}
		}
		else if (parseFloat(e.value) > max)
		{
			this.setError(e, this.maxValueErrorAttribute, this.defaultMaxValueError);
		}
	}
}

function validateEquals(e)
{
	// eventually this should be equipped to do string
	// comparison as well as other element comparisons
	
	var equal = e.getAttribute(this.equalsAttribute);
	
	if ((equal != null) && (0 < equal.length))
	{
		if ((2 < equal.length) && (equal.substring(0, 2) == '!='))
		{
			if (e.value == equal.substring(2, equal.length))
			{
				this.setError(e, this.equalsErrorAttribute, this.defaultEqualsError);
			}
		}
		else if ((2 < equal.length) && (equal.substring(0, 2) == '=='))
		{
			if (e.value != equal.substring(2, equal.length))
			{
				this.setError(e, this.equalsErrorAttribute, this.defaultEqualsError);
			}
		}
		else if (equal.charAt(0) == '=')
		{
			if (e.value != equal.substring(1, equal.length))
			{
				this.setError(e, this.equalsErrorAttribute, this.defaultEqualsError);
			}
		}
		else if (e.value != equal)
		{
			this.setError(e, this.equalsErrorAttribute, this.defaultEqualsError);
		}
	}
}

function setValidateTypeError(e)
{
	this.setError(e, this.validationTypeErrorAttribute, this.defaultValidationTypeError);
}

function setError(e, errorAttribute, defaultTypeError)
{
	var error = e.getAttribute(errorAttribute);
	if (!error)
	{
		if (e.getAttribute(this.defaultErrorAttribute))
		{
			error = e.getAttribute(this.defaultErrorAttribute);
		}
		else if (defaultTypeError)
		{
			error = defaultTypeError;
		}
		else
		{
			error = this.defaultError;
		}
	}
	
	// this would make more sense but it doesn't work
	// so i'll do each explicitly while i make this work
	var results = error.match(/{\s*(\w+)\s*}/g);
	if (results)
	{
		for (var i = 0; i < results.length; i++)
		{
			var dollarOne = results[i].replace(/{\s*(\w+)\s*}/, '$1');
			error = error.replace(/{\s*\w+\s*}/, this.cleanAttributeForErrorDisplay(e, dollarOne));
		}
	}
	
	this.errors += error + '\n';
	this.checkFocus(e);	
}

function cleanAttributeForErrorDisplay(e, attributeName)
{
	var attribute = e.getAttribute(attributeName.toLowerCase());
	
	if (attribute == null)
	{
		return attributeName;
	}
	
	if (attributeName.match(/^(minvalue|maxvalue)$/i))
	{
		return attribute.replace(/[^\d.,]/g, '');
	}
	
	return attribute;
}

function validateAmount(amount)
{
	if ((!amount.match(this.amountPattern)) || (amount == 0))
	{
		return false;
	}
	
	return true;
}

function validateDate(e, type, value)
{
	var today = new Date();
	
	if ((type == 'DateYear') && ((value < today.getYear()) || (!value.match(this.dateYearPattern))))
	{
		return false;
	}
	//just make sure it is two digits for now
	else if ((type == 'DateMonth') && (!value.match(this.dateMonthPattern)))
	{
		return false;
	}
	//just make sure it is two digits for now
	else if ((type == 'DateDay') && (!value.match(this.DateDayPattern)))
	{
		return false;
	}
	
	return true;
}

function validateMod10(cardNumber)
{
	var ccCheckRegExp = /\D/;
	var cardNumbersOnly = cardNumber.replace(/ /g, "");
		
	if (!ccCheckRegExp.test(cardNumbersOnly))
	{
		var numberProduct;
		var checkSumTotal = 0;
		
		while (cardNumbersOnly.length < 16)
		{
			cardNumbersOnly = '0' + cardNumbersOnly;
		}

		for (digitCounter = cardNumbersOnly.length - 1; 0 <= digitCounter; digitCounter -= 2)
		{
			checkSumTotal += parseInt (cardNumbersOnly.charAt(digitCounter));
			numberProduct = String((cardNumbersOnly.charAt(digitCounter - 1) * 2));
			for (var productDigitCounter = 0; productDigitCounter < numberProduct.length; productDigitCounter++)
			{
				checkSumTotal += parseInt(numberProduct.charAt(productDigitCounter));
			}
		}

		return (checkSumTotal % 10 == 0);
	}

	return false;
}

function validateNumeric(number)
{
//	number = number.replace(/\s/g, '');
	
	if (!number.match(this.numericPattern))
	{
		return false;
	}
	return true;
}

function validate(controlID, elementName, filter)
{
	
	//make sure we can run this javascript
 	if (document.getElementById && document.createTextNode)
	{
		var validate = new Validate(document['SkySales'], controlID + '_', errorsHeader, filter);
		
		if (elementName)
		{
			validate.validateSingleElement(document.getElementById(controlID + "_" + elementName));
			return validate.outputErrors();
		}
		
		return validate.run();
	}
  	
  	// could not use javascript rely on server validation
  	return true;
}

function validateForm(form, filter)
{
	var validate = new Validate(form, '', errorsHeader, filter);
	return validate.run();
}
