/***************************************************************************************************************************************************************
 REQUIRES:
 - Prototype 1.6.0
 ***************************************************************************************************************************************************************/

if (CUPH === undefined) {
	var CUPH = function() {
	};
}


CUPH.Validation = {
	date: function(input, options) {
		// Configure options
		options = Object.extend({
			allowUnknowns: false
		}, options);

		// Declare regular expressions
		var regex = /\b(?:(?:(\d{2})(\d{2})(\d{2}|\d{4}))|(?:(\d{1,2})[\/-](\d{1,2})[\/-](\d{2}|\d{4})))\b/

		// Declare an array to hold the original values of the raw date
		var rawAry = regex.exec(input);

		// Parse the date appropriately
		if (rawAry != null) {
			rawAry = [
				rawAry[1] || rawAry[4],
				rawAry[2] || rawAry[5],
				rawAry[3] || rawAry[6]
			];
		} else {
			throw "Incorrect date format.  Enter as MM/DD/YYYY, MM/DD/YY, MMDDYY, or MMDD9999 (e.g., if year is unknown).";
		}

		// Declare parts of date
		var month = parseInt(rawAry[0].substring(0, 1) != "0" ? rawAry[0] : rawAry[0].substring(1));
		var day = parseInt(rawAry[1].substring(0, 1) != "0" ? rawAry[1] : rawAry[1].substring(1));
		var year = parseInt(rawAry[2].substring(0, 1) != "0" ? rawAry[2] : rawAry[2].substring(1));

		// Check for numbers
		if (isNaN(month)) {
			throw "Invalid month (" + rawAry[0] + ") in the date entry.";
		} else if (isNaN(day)) {
			throw "Invalid day (" + rawAry[1] + ") in the date entry.";
		} else if (isNaN(year)) {
			throw "Invalid year (" + rawAry[2] + ") in the date entry.";
		}

		// Check for unknowns
		if (!options.allowUnknowns && (month == 99 || day == 99 || year == 9999)) {
			throw "Unknown values are not allowed in the date.";
		}

		// Create a events
		var date = new Date();

		// Handle year
		if (year < 100) {
			// Get the current century
			var currentCentury = parseInt(date.getFullYear() / 100) * 100;

			// Get the threshold
			var threshold = date.getFullYear() + 15 - currentCentury;

			// Adjust year
			year = year + currentCentury - (year > threshold ? 100 : 0);
		} else if (year > 2998 && year < 9999) {
			throw "The year entry (" + year + ") must be less than the year 2999.";
		}

		// Create temporary parts of the date
		var tempMonth = month != 99 ? month - 1 : 0; // Unknown accounts for a month with 31 days
		var tempDay = day != 99 ? day : date.getDate(); // Unknown is simply today's date
		var tempYear = year != 9999 ? year : (month - 1 == 1 ? 2008 : date.getFullYear()); // Unknown accounts for leap year

		// Update the date
		date.setMonth(1);
		date.setDate(1);
		date.setFullYear(tempYear);
		date.setMonth(tempMonth);
		date.setDate(tempDay);

		if (date.getDate() != tempDay) {
			throw "Invalid day (" + day + ") in the date entry.";
		} else if (date.getMonth() != tempMonth) {
			throw "Invalid month (" + month + ") in the date entry.";
		} else if (date.getFullYear() != tempYear) {
			throw "Invalid year (" + year + ") in the date entry.";
		}

		// Return the formatted date
		return (month < 10 ? "0" : "") + month + "/" + (day < 10 ? "0" : "") + day + "/" + year;
	},
	email: function(input) {
		// Determine if the e-mail address matches
		if (input.search(/\b^([0-9a-zA-Z]+[-._+&])*[0-9a-zA-Z]+@([-0-9a-zA-Z]+[.])+[a-zA-Z]{2,6}$\b/) != 0) {
			throw "Invalid e-mail address.";
		}

		// Return the valid e-mail address
		return input;
	},
	name: function(input, options) {
		// Configure options
		options = Object.extend({
			allowSpaces: false
		}, options);

		// Iterate over the characters and check for illegal characters
		for (var i = 0; i < input.length; i++) {
			var c = input.substring(i, i + 1);

			// Check if the current character is not in the valid characters string or if the string
			// begins or ends with a dash or if it is a space if spaces are not allowed
			if ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz -'".indexOf(c) < 0 || ((i == 0 || i == input.length - 1) && c == "-") || (c == " " && !options.allowSpaces)) {
				if (options.allowSpaces) {
					throw "An invalid character (" + c + ") was found.  This Validation may only contain the letters A-Z and a-z, a dash, an apostrophe, and a space.";
				} else {
					throw "An invalid character (" + c + ") was found.  This Validation may only contain the letters A-Z and a-z, a dash, and an apostrophe.";
				}
			}
		}

		return input;
	},
	phone: function(input, options) {
		// Configure options
		options = Object.extend({
			allowExtension: false
		}, options);

		// Match the regex
		var match;

		if (options.allowExtension) {
			match = /^(\d{3})[ .-]?(\d{3})[ .-]?(\d{4})(?:(?:[ -]|\s*?(?:x|ext)\.?\s*?)?(\d{1,6}))?$/.exec(input);
		} else {
			match = /(\d{3})[ .-]?(\d{3})[ .-]?(\d{4})/.exec(input);
		}

		// Determine if the phone number matches
		if (match == null || match[0] != input) {
			if (options.allowExtension) {
				throw "Incorrect phone number format.  Enter as ##########, ###-###-####, or ###-###-#### ext. ######.";
			} else {
				throw "Incorrect phone number format.  Enter as ########## or ###-###-####.";
			}
		}

		// Return the formatted phone number
		if (options.allowExtension && !Object.isUndefined(match[4]) && match[4] != null && !match[4].blank()) {
			return match[1] + "-" + match[2] + "-" + match[3] + " ext. " + match[4];
		} else {
			return match[1] + "-" + match[2] + "-" + match[3];
		}
	},
	range: function(value, options) {
		// Configure options
		options = Object.extend({
			max: 0,
			min: 0,
			outliers: [],
			precision: 0
		}, options);

		// Check if the value is a number
		if (isNaN(value)) {
			throw "The field's value must be a number.";
		}

		// Check if the value is an outlier
		if (options.outliers != null) {
			for (var i = 0; i < options.outliers.length; i++) {
				if (value == options.outliers[i]) {
					return value;
				}
			}
		}

		// Check if the value is out of range
		if (value < options.min || value > options.max) {
			throw "The Validation must have a value between " + options.min + " and " + options.max + ". (" + value + ")";
		}

		// Format the number
		return new Number(value).toFixed(options.precision);
	},
	ssn: function(input) {
		// Determine if the phone number matches
		if (input.match(/\d{3}[- ]?\d{2}[- ]?\d{4}/) != input) {
			throw "A social security number must be in the form 123-45-6789 or 123456789";
		}

		// Remove any dashes, dots, or spaces
		input = input.replace(/[ -]/g, "");

		// Return the formatted social security number
		return input.substring(0, 3) + "-" + input.substring(3, 5) + "-" + input.substring(5);
	},
	time: function(input, options) {
		// Configure options
		options = Object.extend({
			allowUnknowns: false
		}, options);

		// Declare regular expressions
		var regex = /24:?00|2[0-3]:?[0-5]\d|[0-1]?\d:?[0-5]\d/ // X:XX, XXX, XX:XX, or XXXX

		// Handle unknown date
		if (input == "9999" || input == "99:99") {
			if (options.allowUnknowns) {
				return "9999";
			} else {
				throw "Unknown values are not allowed in the time.";
			}
		}

		// Determine if the time matches
		if (input.match(regex) != input) {
			throw "Incorrect time format.  Enter as H:MM, HMM, HH:MM, or HHMM.";
		}

		// Remove the colon
		input = input.replace(":", "").replace(/^0(\d{3})$/, "$1");

		// Work the parts
		var rawHours = input.substring(0, input.length - 2);
		var rawMinutes = input.substring(input.length - 2);

		// Declare parts of time
		var hours = parseInt(rawHours);
		var minutes = parseInt(rawMinutes.substring(0, 1) != "0" ? rawMinutes : rawMinutes.substring(1));

		// Handle oddity
		if (hours == 24 && minutes == 0) {
			hours = 0;
		}

		// Check hour/minute ranges
		if (minutes < 0 || minutes > 59) {
			throw "Invalid minute (" + minutes + ") in the time entry.";
		}
		if (hours < 0 || hours > 23) {
			throw "Invalid hour (" + hours + ") in the time entry.";
		}

		// Return the formatted time
		return (hours < 10 ? "0" : "") + hours + (minutes < 10 ? "0" : "") + minutes;
	},
	zip: function(input, options) {
		// Configure options
		options = Object.extend({
			isPlusFour: false
		}, options);

		// Declare regular expressions
		var regex = /\b(\d{5})[ -]?(\d{4})?\b/ // DDDDD, DDDDDDDDD, DDDDD-DDDD, or DDDDD DDDD

		// Match the expression
		var match = regex.exec(input);

		// Handle errors
		if (match == null || match.length < 2) {
			throw "Incorrect ZIP code format.  Enter as DDDDD, DDDDD DDDD, DDDDD-DDDD, or DDDDDDDDD.";
		}

		// Return the ZIP code in the correct format
		return match[1] + ((options.isPlusFour && !Object.isUndefined(match[2]) && match[2] != null && !match[2].blank()) ? ("-" + match[2]) : "")
	}
};

if (!Number.prototype.toFixed || /Opera|Safari|Konqueror|KHTML/.test(navigator.userAgent)) {
	Number.prototype.toFixed = function(f) {
		f = parseInt(f / 1 || 0);

		if (f < 0 || f > 20) {
			throw "The number of fractional digits is out of range";
		}

		if (isNaN(this)) {
			return "NaN";
		}

		var s = this < 0 ? "-" : "";
		var x = Math.abs(this);

		if (x > Math.pow(10, 21)) {
			return s + x.toString();
		}

		var m = Math.round(x * Math.pow(10, f)).toString();

		if (!f) {
			return s + m;
		}

		while (m.length <= f) {
			m = "0" + m;
		}

		return s + m.substring(0, m.length - f) + "." + m.substring(m.length - f);
	};
}

