/* 
 * system.forms.validation.js
 * version 1.0.3
 * Copyright (C) Jason Mingl (Ratheous)
 *
 * Requires: system.forms.js  2.0.0+
 *
 *	06/16/2007 : 1.0.3 - All validators now perform their own tests. This can be used to collect more data through dynamic patterns
 *	05/10/2007 : 1.0.2 - Added names and default expressions to all validators 
 *	04/30/2007 : 1.0.1 - Validators are no longer defined as functions. No more 'new validators.email' etc.
 *	04/29/2007 : 1.0.0 - Moved out of system.forms.js v2.1.1
 *
 */

// ----------------------------------------------

if(!system.forms.validation)
	system.forms.validation = {};
var validators = system.forms.validation;

// Validate integer ----------------------------------------------------------------------

system.forms.validation.integer =
{
	name: 'integer',
	expr: /integer/,
	test: function(f) { return this.expr.test(f.element.className); },
	format: function(v) { return parseInt(v); }, //return parseInt(field.element.value);
	validate: function(f)
	{
		f.error = false;
		if(empty_string.test(f.element.value)) { system.forms.validation.check_required_field(f); return; }
		f.warning = false; f.error = false; f.message = "";
		if(isNaN(parseInt(f.element.value, 10))) { f.error = true; f.message = "Error: Not a valid number"; return; }
	}
};

// Validate ccnumber ----------------------------------------------------------------------

system.forms.validation.ccnumber =
{
	name: 'ccnumber',
	expr: /ccnumber/,
	test: function(f) { return this.expr.test(f.element.className); },
	error_message: 'Error: Not a valid credit card number',
	warning_message: 'Warning: This card number format is not recognized',
	format: function(v) { return v.replace(/[^\d]+/ig, ""); },
	validate: function(f, fmt)
	{
		f.error = false;
		if(empty_string.test(f.element.value)) { system.forms.validation.check_required_field(f); return; }
		f.warning = false; f.error = false; f.message = "";
		if(fmt) f.element.value = this.format(f.element.value);
		
		if(isNaN(parseInt(f.element.value, 10))) { f.error = true; f.message = this.error_message; return; }
		
		var len = f.element.value.length;
		var first = f.element.value.substring(0,1);
		if(!(len == 15 && first == '3')/*amex*/ && !(len == 16 && first >= '4' && first <= '6')/*visa/mast/disc*/)
		{ f.warning = true; f.message = this.warning_message; return; }
	}
};

// Validate date fields -------------------------------------------------------------------

system.forms.validation.date =
{
	name: 'date',
	expr: /date/,
	test: function(f) { return this.expr.test(f.element.className); },
	format: function(v)
	{
		var mysql_date_fmt = /(\d{4})[./-](\d{2})[./-](\d{2})/;
		var std_date_fmt = /\d{2}[./-]\d{2}[./-]\d{4}/;
		var tryformat = true;
		var tv = v;
		
		if(mysql_date_fmt.test(tv))
		{ 
			tv = tv.replace(/[^\d]+/ig, "");
			if(tv.length == 8)  { tv = tv.slice(4,6) + "/" + tv.slice(6,8) + "/" + tv.slice(0,4); tryformat = false; }
		}
		else
		{
			tv = tv.replace(/[^\d]+/ig, "");
			if(tv.length == 8) { tv = tv.slice(0,2) + "/" + tv.slice(2,4) + "/" + tv.slice(4,8); tryformat = false; }
			else if(tv.length == 6) { tv = tv.slice(0,2) + "/" + tv.slice(2,4) + "/20" + tv.slice(4,6); tryformat = false; }
		}
		if(tryformat)
		{
			var date = new Date(Date.parse(tv));
			var month = date.getMonth() + 1; month = month < 10 ? '0'+month : month;
			var day = date.getDate(); if(day < 10) day = "0" + day;
			var year = date.getFullYear();
			tv = month + "/" + day + "/" + year;
		}

		if(tv == "00/00/0000" || tv == "NaN/NaN/NaN")
			return v;
		return tv;
	},
	validate: function(f, fmt)
	{
		if(empty_string.test(f.element.value)) { system.forms.validation.check_required_field(f); return; }
		if(fmt) f.element.value = this.format(f.element.value); // Format data (if possible)
		f.warning = false; f.error = false; f.message = "";
		var std_date_fmt = /\d{2}[/]\d{2}[/]\d{4}/;
		
		if(!std_date_fmt.test(f.element.value))
		{ f.error = true; f.message = "Error: Invalid Date"; return; }
		
		var today = new Date;
		var date = new Date(Date.parse(f.element.value));

		if(date.toString() == "Invalid Date") { f.error = true; f.message = "Error: Invalid Date"; }
		else if(date.getYear() > (today.getYear() + 100)) { f.warning = true; f.message = "Warning: Date more than 100 years in the future! Possibly an error..."; }
		else if(date.getYear() < (today.getYear() - 10)) { f.warning = true; f.message = "Warning: Date is more than 10 years in the past"; }
	}
};

// Validate phone numbers --------------------------------------------------------------------

system.forms.validation.phone_number =
{
	name: 'phone_number',
	expr: /phone/,
	test: function(f) { return this.expr.test(f.element.className); },
	telephone_number: /[0-9 ()-]+$/,
	format: function(value)
	{
		value = value.replace(/[^\d]+/ig, "");
		if(value.length == 7) value = value.slice(0,3) + "-" + value.slice(3,7); /*555-5555*/	
		else if(value.length == 10) value = "(" + value.slice(0,3) + ") " + value.slice(3,6) + "-" + value.slice(6,10);	/*(555) 555-5555*/
		else if(value.length == 11)	value = value.slice(0,1) + " (" + value.slice(1,4) + ") " + value.slice(4,7) + "-" + value.slice(7,11);	/*1 (555) 555-5555*/
		return value;
	},
	validate: function(f, fmt)
	{
		if(empty_string.test(f.element.value)) { system.forms.validation.check_required_field(f); return; }
		if(fmt) f.element.value = this.format(f.element.value); // Format data (if possible)
		f.warning = false; f.error = false; f.message = "";
		for (var j = 0, numdigits = 0; j < f.element.value.length; j++)
			if (f.element.value.charAt(j) >= '0' && f.element.value.charAt(j) <= '9') 
				numdigits++;
		if(!this.telephone_number.test(f.element.value)) { f.error = true; f.message = "Error: not a valid telephone number. Characters permitted are digits, space and ()-"; }
		else if(numdigits < 10) { f.error = true; f.message = "Error: " + numdigits + " digits - valid length is 10-11 digits"; }
		else if(numdigits > 11) { f.error = true; f.message = "Error: " + numdigits + " digits - valid length is 10-11 digits"; }
	}
};

// Validate currency -------------------------------------------------------------

system.forms.validation.currency =
{
	name: 'currency',
	expr: /currency/,
	test: function(f) { return this.expr.test(f.element.className); },
	error_message: "Error: Invalid currency value",
	currency_fmt: /^\-?\(?\$\d+\.\d+\)?$/,
	format: function(v)
	{
		if(v == "") return v;
		v = new String(v);
		// If value contains any character other than -, (), $, . or a digit, skip formatting
		if(v.search(/[^\-^\(^\)^\$^.^\d]/i) != -1) return v;
		var neg = v.search(/\(/) != -1 || v.search(/-/) != -1;
		v = v.replace(/[\(\)\-\$]/ig, "");
		v = String(Math.abs(v));
		var decimals; if((pos = v.search(/\./i)) != -1) decimals = (v.length - pos) - 1;
		
		if(decimals)
		{
			if(decimals == 1) v = "$" + v + "0";
			else if(decimals == 2) v = "$" + v;
			else
			{
				v = v.replace(/[.]+/ig, "");
				var decimal_val = v.substr(pos, decimals);
				var whole_number = v.substr(0, v.length - decimals);
				dec_temp = decimal_val.substr(0, 2) + "." + decimal_val.substr(2, decimals - 2);
				dec_temp = Math.round(dec_temp);
				v = "$" + whole_number + "." + (dec_temp < 10 ? "0" + dec_temp : dec_temp);
			}
		}
		else { v = v.replace(/[^\d]+/ig, ""); v = "$" + v + ".00"; }
		
		if(neg) return "(" + String(v) + ")";
		else return v;
	},
	validate: function(f, fmt)
	{
		if(empty_string.test(f.element.value)) { system.forms.validation.check_required_field(f); return; }
		if(fmt) f.element.value = this.format(f.element.value); // Format data (if possible)
		f.warning = false; f.error = false; f.message = "";
		if(!this.currency_fmt.test(f.element.value)) { f.error = true; f.message = this.error_message; }
	}
};

// Validate email address -------------------------------------------------------------

system.forms.validation.email =
{
	name: 'email',
	expr: /email/,
	test: function(f) { return this.expr.test(f.element.className); },
	error_message: "Error: Invalid email address",
	warning_message: "Warning: Unusual email address",
	email_standard: /^[-a-z0-9!#$%&\'*+\/=?^_`{|}~]+(\.[-a-z0-9!#$%&\'*+\/=?^_`{|}~]+)*@(([a-z]([-a-z0-9]*[a-z0-9]+)?){1,63}\.)+([a-z]([-a-z0-9]*[a-z0-9]+)?){2,63}$/,
	/*'*/
	email_common: /^[A-Za-z][\w.-]+@\w[\w.-]+\.[\w.-]*[A-Za-z][A-Za-z]$/,
	format: function(v) { return v; },
	validate: function(f)
	{
		if(empty_string.test(f.element.value)) { system.forms.validation.check_required_field(f); return; }
		f.element.value = f.element.value.trim(); // Remove outer whitespace from value
		f.warning = false; f.error = false; f.message = "";	
		if(!this.email_standard.test(f.element.value)) { f.error = true; f.message = this.error_message; }
		else if(!this.email_common.test(f.element.value)) { f.warning = true; f.message = this.warning_message; }
	}
};

// Validate zipcodes -------------------------------------------------------------

system.forms.validation.zipcode =
{
	name: 'zipcode',
	expr: /zipcode/,
	test: function(f) { return this.expr.test(f.element.className); },
	format: function(value)
	{
		value = value.replace(/[^\d]+/ig, "");
		if(value.length == 9) value = value.slice(0,5) + "-" + value.slice(5,9); /*55555-5555*/	
		return value;
	},
	validate: function(f, fmt)
	{
		if(empty_string.test(f.element.value)) { system.forms.validation.check_required_field(f); return; }
		if(fmt) f.element.value = this.format(f.element.value); // Format data (if possible)
		f.warning = false; f.error = false; f.message = '';
		for (var j = 0, numdigits = 0; j < f.element.value.length; j++)
			if (f.element.value.charAt(j) >= '0' && f.element.value.charAt(j) <= '9') 
				numdigits++;
		if(numdigits != 5 && numdigits != 9) { f.error = true; f.message = "Error: " + numdigits + " digits. Valid length is 5 or 9 digits"; }
	}
};

Class.override(system.forms.form,
{
	validators: new Array,
	register_validator: function(validator) { this.validators.push(validator); },
	initialize: function(opts) 
	{ 
		this.register_validator(validators.phone_number);
		this.register_validator(validators.email);
		this.register_validator(validators.zipcode);
		this.register_validator(validators.ccnumber);
		
		this.parent.initialize.apply(this, [opts]);
	},
	register_field: function(field)
	{
		try
		{
			for(var i = 0; i < this.validators.length; i++)
			{ 
				if(this.validators[i].test(field)) 
					field.validator = this.validators[i]; 
			};
			if(/required/.test(field.element.className)) field.required = true;
			if(/checkbox/.test(field.element.className)) field.style_target = $('_'+field.element.id) || field.element.id;
			this.parent.register_field.apply(this, [field]);
		} catch(e) { alert('form::register_field : '+e.message); }
	}
});