// $Id: Forms.js,v 1.16 2009/05/27 01:16:01 cmanley Exp $
// Copyright (c) 2007, Craig Manley (craigmanley.com)

// Make sure the required scripts are loaded.
// /js/i18n/??.js (Strings object)


/***
 * Validator class for creating objects for input validations.
 * Used by ValidatorFactory namespace.
 *
 * @param chars - null or string of allowed input characters.
 * @param regex_or_func - null or validation regex or boolean function.
 * @param minlen - null or minimum valid string length.
 * @param maxlen - null or maximum valid string length.
 */
function Validator(chars, regex_or_func, minlen, maxlen) {
	this._chars = chars;
	this._regex = null;
	this._func = null;
	this._minlen = minlen;
	this._maxlen = maxlen;

	// Determine if function or regex was passed.
	// regex_or_func.constructor.toString() should look like this (tested with Firefox 2, Opera 9, MSIE 7):	"function Foo(param1, param2) { ..."
	if (regex_or_func) {
		var s = regex_or_func.constructor.toString();
		var x = null;
		if (/^\s*function ([^\s\(]+)/.test(s)) {
			x = RegExp.$1;
		}
		else if (/^\[class (\S+)\]$/.test(s)) { // dunno what this is anymore - probably something returned by older browsers.
			x = RegExp.$1;
		}
		if (x) {
			if (x == 'Function') {
				this._func = regex_or_func;
			}
			else if (x == 'RegExp') {
				this._regex = regex_or_func;
			}
		}
	}

	this.charOK = function(char) {
		if (this._chars && (this._chars.indexOf(char) == -1)) {
			return false;
		}
		return true;
	}

	this.test = function(s) {
		if (this._minlen && (s.length < this._minlen)) {
			return false;
		}
		if (this._maxlen && (s.length > this._maxlen)) {
			return false;
		}
		if (this._regex) {
			return this._regex.test(s);
		}
		else if (this._func) {
			return this._func(s);
		}
		return true;
	}

	this.minLen = function() {
		return this._minlen;
	}

	this.minLenOK = function(s) {
		if (!this._minlen) {
			return true;
		}
		return s.length >= this._minlen;
	}

	this.maxLen = function() {
		return this._maxlen;
	}

	this.maxLenOK = function(s) {
		if (!this._maxlen) {
			return true;
		}
		return s.length <= this._maxlen;
	}
}



/***
 * ValidatorFactory
 * Creates Validator objects.
 */
var ValidatorFactory = new (function() {

	/* Private properties */
	var _validators = {
		'email'			: new Validator(null, function(s) { return (s.length <= 100) && /^([^\(\)\<\>\@\,\;\:\"\[\]])+\@(([a-zA-Z0-9\-])+\.)+[a-zA-Z0-9]{2,6}$/.test(s); }, 7, 100 ),	// /^.+@.+\..{2,3}$/
		'password'		: new Validator(null, null, 4, 32),
		'company'		: new Validator(null, null, 1, 50),
		'gender'		: new Validator(null, /^(M|F)$/, 1, 1),
		'name'			: new Validator(null, null, 1, 75),
		'firstname'		: new Validator(null, null, 1, 50),
		'lastname'		: new Validator(null, null, 2, 50),
		'telephone'		: new Validator(null, /^[\d\(\) \-\.]{10,20}$/, 10, 20),
		'boolean'		: new Validator(null, /^(1|0)$/, 1, 1),
		'address'		: new Validator(null, null, 4, 100),
		'postalcode'	: new Validator(null, null, 4, 10),
		'city'			: new Validator(null, null, 3, 50),
		'country_code'	: new Validator(null, /^[A-Z]{2}$/)
	};

	/* Public methods */
	this.get = function(key) {
		if (!_validators[key]) {
			throw 'No Validator object found with key "' + key + '".';
		}
		return _validators[key];
	}

})();



/***
 * Abstract form controller class.
 * Controls a form and related actions.
 * Requires ValidatorFactory.
 */
function AFormController() {
	this._getForm = function() {
		throw "This must be implemented in child class!";
	}
	this._getFieldDefs = function() {
		throw "This must be implemented in child class!";
	}
};

// Validates the form.
AFormController.addMethod('validate', function () {
		var f = this._getForm();

		// Transformations
		for (var i=0; i < f.elements.length; i++) {
			if (f.elements[i].type == 'text') {
				f.elements[i].value = f.elements[i].value.trim();
			}
		}

		// Check fields
		var missing = new Array();
		var badsyntax = new Array();
		var focus_me = null;
		var fielddefs = this._getFieldDefs();
		for (var name in fielddefs) {
			var e = f.elements[name];
			if (!e) {
				throw "No element found in form '" + f.id + "' having name '" + name + "'.";
			}
			var val = '';
			if (e.type) {
				if ((e.type == 'text') || (e.type == 'password')) {
					val = e.value.trim();
				}
				else if (e.type == 'select-one') {
					if (e.selectedIndex >= 0) {
						val = e.options[e.selectedIndex].value;
					}
				}
				else {
					//alert(name + "\n" + e + "\n" + e.id + "\n" + e.name + "\n" + e.type);
					val = e.value;
				}
			}
			else {
				// assume radio group
				for (var i=0; i<e.length; i++) {
					if (e[i].checked) {
						val = e[i].value;
						break;
					}
				}
			}
			if (val.length) {
				var validator = fielddefs[name][2];
				if (validator) {
					if (!validator.test(val)) {
						badsyntax.push(fielddefs[name][1]);
						if (e.style) {
							e.style.backgroundColor = '#fdd'; // red
						}
					}
				}
			}
			else {
				if (fielddefs[name][0]) {
					missing.push(fielddefs[name][1]);
					if (e.style) {
						e.style.backgroundColor = '#fdd'; // red
					}
				}
			}
			if (!focus_me && (badsyntax.length || missing.length)) {
				if (e.focus) {
					focus_me = e;
				}
			}
		}

		// Handle errors
		var error = '';
		if (missing.length > 0) {
			error += Strings['err_fields_empty'] + "\n\t" + missing.join("\n\t") + "\n";
		}
		if (badsyntax.length > 0) {
			error += Strings['err_fields_syntax'] + "\n\t" + badsyntax.join("\n\t") + "\n";
		}
		if (error.length) {
			alert(error);
			if (focus_me) {
				focus_me.focus();
			}
			return false;
		}

		// Allow submission.
		return true;
	}
);

// Input onkeypress handler (filters unsupported characters)
AFormController.addMethod('inputKeyPress', function (event, input) {
		var key;
		var keychar;
		if (window.event) {
			key = window.event.keyCode;
		}
		else if (event) {
			key = event.which;
		}
		else {
			return true;
		}
		// Ignore control keys
		if ((key==null) || (key==0) || (key==8) || (key==9) || (key==13) || (key==16) || (key==27)) {
			return true;
		}
		keychar = String.fromCharCode(key);
		//document.title = "key: " + key + "\tchar: " + keychar;
		// Get field def for this input element's name.
		var def = this._getFieldDefs()[input.name];
		// Perform filtering and/or checks if definition found.
		if (def) {
			var validator = def[2];
			if (validator) {
				// Don't allow unsupported chars.
				if (!validator.charOK(keychar)) {
					return false;
				}
			}
		}
		return true;
	}
);

// Input onkeyup handler (colorizes the input field based on validation while typing)
AFormController.addMethod('inputKeyUp', function (event, input) {
		var key;
		var keychar;
		if (window.event) {
			key = window.event.keyCode;
		}
		else if (event) {
			key = event.which;
		}
		else {
			return true;
		}
		//keychar = String.fromCharCode(key);
		//document.title = "key: " + key + "\tchar: " + keychar;
		// Get field def for this input element's name.
		var def = this._getFieldDefs()[input.name];
		// Perform filtering and/or checks if definition found.
		if (def) {
			if (input.value.length) {
				var validator = def[2];
				if (validator && !validator.test(input.value)) {
					input.style.backgroundColor = '#ffe'; // yellow
				}
				else {
					// default
					input.style.backgroundColor = '';
				}
			}
			else {
				// yellow or default
				input.style.backgroundColor = def[0] ? '#ffe' : '';
			}
		}
		return true;
	}
);

// Input onkeyup handler  (colorizes the input field based on validation)
AFormController.addMethod('inputBlur', function (event, input) {
		// Get field def for this input element's name.
		var def = this._getFieldDefs()[input.name];
		// Perform filtering and/or checks if definition found.
		if (def) {
			if (input.value.length) {
				var validator = def[2];
				if (validator && !validator.test(input.value)) {
					input.style.backgroundColor = '#fdd'; // red
				}
				else {
					// default
					input.style.backgroundColor = '';
				}
			}
			else {
				// red or default
				input.style.backgroundColor = def[0] ? '#fdd' : '';
			}
		}
		return true;
	}
);




/***
 * Login namespace.
 * Controls the form and related actions.
 * Extends AFormController.
 */
var Login = (function() {
	var c = function() {};
	c.extend(AFormController);
	c.addMethod('_getForm', function () {
		if (!this._form) {
			var id = 'formLogin';
			this._form = document.getElementById(id);
			if (!this._form) {
				throw "Unable to find DOM element with id '" + id + "'.";
			}
		}
		return this._form;
	});
	c.addMethod('_getFieldDefs', function () {
		if (!this._fielddefs) {
			this._fielddefs = {
				// name => [required, desc, validator]
				'email'		: [true, Strings['email']		, ValidatorFactory.get('email')],
				'password'	: [true, Strings['password']	, ValidatorFactory.get('password')]
			};
		}
		return this._fielddefs;
	});
	return new c();
})();




/***
 * Register namespace.
 * Controls the form and related actions.
 * Extends AFormController.
 */
var Register = (function() {
	var c = function() {};
	c.extend(AFormController);
	c.addMethod('_getForm', function () {
		if (!this._form) {
			var id = 'formRegister';
			this._form = document.getElementById(id);
			if (!this._form) {
				throw "Unable to find DOM element with id '" + id + "'.";
			}
		}
		return this._form;
	});
	c.addMethod('_getFieldDefs', function () {
		if (!this._fielddefs) {
			this._fielddefs = {
				// name => [required, desc, validator]
				'email'			: [true	, Strings['email']		, ValidatorFactory.get('email')],
				'password'		: [true	, Strings['password']	, ValidatorFactory.get('password')],
				'password2'		: [true	, Strings['password2']	, ValidatorFactory.get('password')],
				'company'		: [false, Strings['company']	, ValidatorFactory.get('company')],
				'gender'		: [true	, Strings['gender']		, ValidatorFactory.get('gender')],
				'firstname'		: [true	, Strings['firstname']	, ValidatorFactory.get('firstname')],
				'lastname'		: [true	, Strings['surname']	, ValidatorFactory.get('lastname')],
				'telephone'		: [false, Strings['telephone']	, ValidatorFactory.get('telephone')],
				'newsletter'	: [false, Strings['newsletter']	, ValidatorFactory.get('boolean')],
				'address'		: [true	, Strings['address']	, ValidatorFactory.get('address')],
				'postalcode'	: [true	, Strings['postalcode']	, ValidatorFactory.get('postalcode')],
				'city'			: [true	, Strings['city']		, ValidatorFactory.get('city')],
				'country_code'	: [true	, Strings['country']	, ValidatorFactory.get('country_code')]
			};
		}
		return this._fielddefs;
	});
	c.addMethod('validate', function () {
		var result = this.callSuper('validate');
		if (result) {
			var f = this._getForm();
			// Check that passwords are equal.
			if (f.elements['password'].value != f.elements['password2'].value) {
				alert(Strings['err_password_mismatch']);
				f.elements['password'].focus();
				result = false;
			}
			// Check for house number in address for countries that require it.
			var addr = f.elements['address'].value;
			if (!addr.match(/\d+/)) {
				var ecc = f.elements['country_code'];
				var i = ecc.selectedIndex;
				if (i >= 0) {
					var cc = ecc.options[i].value;
					if (cc == 'NL') {
						var error = Strings['err_fields_syntax'] + "\n\t" + Strings['address'];
						alert(error);
						ecc.focus();
						result = false;
					}
				}
			}
		}
		return result;
	});

	return new c();
})();



/***
 * ForgotPassword namespace.
 * Controls the form and related actions.
 * Extends AFormController.
 */
var ForgotPassword = (function() {
	var c = function() {};
	c.extend(AFormController);
	c.addMethod('_getForm', function () {
		if (!this._form) {
			var id = 'formForgotPassword';
			this._form = document.getElementById(id);
			if (!this._form) {
				throw "Unable to find DOM element with id '" + id + "'.";
			}
		}
		return this._form;
	});
	c.addMethod('_getFieldDefs', function () {
		if (!this._fielddefs) {
			this._fielddefs = {
				// name => [required, desc, validator]
				'email'		: [true, Strings['email'], null] // ValidatorFactory.get('email')
			};
		}
		return this._fielddefs;
	});
	return new c();
})();




/***
 * Account namespace.
 * Controls the form and related actions.
 * Extends AFormController.
 */
var Account = (function() {
	var c = function() {};
	c.extend(AFormController);
	c.addMethod('_getForm', function () {
		if (!this._form) {
			var id = 'formAccount';
			this._form = document.getElementById(id);
			if (!this._form) {
				throw "Unable to find DOM element with id '" + id + "'.";
			}
		}
		return this._form;
	});
	c.addMethod('_getFieldDefs', function () {
		if (!this._fielddefs) {
			this._fielddefs = {
				// name => [required, desc, validator]
				'company'		: [false, Strings['company']	, ValidatorFactory.get('company')],
				'gender'		: [true	, Strings['gender']		, ValidatorFactory.get('gender')],
				'firstname'		: [true	, Strings['firstname']	, ValidatorFactory.get('firstname')],
				'lastname'		: [true	, Strings['surname']	, ValidatorFactory.get('lastname')],
				'telephone'		: [false, Strings['telephone']	, ValidatorFactory.get('telephone')],
				'newsletter'	: [false, Strings['newsletter']	, ValidatorFactory.get('boolean')],
				'address'		: [true	, Strings['address']	, ValidatorFactory.get('address')],
				'postalcode'	: [true	, Strings['postalcode']	, ValidatorFactory.get('postalcode')],
				'city'			: [true	, Strings['city']		, ValidatorFactory.get('city')],
				'country_code'	: [true	, Strings['country']	, ValidatorFactory.get('country_code')]
			};
		}
		return this._fielddefs;
	});
	c.addMethod('validate', function () {
		var result = this.callSuper('validate');
		if (result) {
			var f = this._getForm();
			// Check for house number in address for countries that require it.
			var addr = f.elements['address'].value;
			if (!addr.match(/\d+/)) {
				var ecc = f.elements['country_code'];
				var i = ecc.selectedIndex;
				if (i >= 0) {
					var cc = ecc.options[i].value;
					if (cc == 'NL') {
						var error = Strings['err_fields_syntax'] + "\n\t" + Strings['address'];
						alert(error);
						ecc.focus();
						result = false;
					}
				}
			}
		}
		return result;
	});
	return new c();
})();




/***
 * ChangeEmail namespace.
 * Controls the form and related actions.
 * Extends AFormController.
 */
var ChangeEmail = (function() {
	var c = function() {};
	c.extend(AFormController);
	c.addMethod('_getForm', function () {
		if (!this._form) {
			var id = 'formChangeEmail';
			this._form = document.getElementById(id);
			if (!this._form) {
				throw "Unable to find DOM element with id '" + id + "'.";
			}
		}
		return this._form;
	});
	c.addMethod('_getFieldDefs', function () {
		if (!this._fielddefs) {
			this._fielddefs = {
				// name => [required, desc, validator]
				'password'		: [true	, Strings['password']	, ValidatorFactory.get('password')],
				'new_email'		: [true	, Strings['new_email']	, ValidatorFactory.get('email')],
				'new_email2'	: [true	, Strings['new_email2']	, ValidatorFactory.get('email')]
			};
		}
		return this._fielddefs;
	});
	c.addMethod('validate', function () {
		var result = this.callSuper('validate');
		if (result) {
			var f = this._getForm();
			if (f.elements['new_email'].value != f.elements['new_email2'].value) {
				alert(Strings['err_new_email_mismatch']);
				f.elements['new_email'].focus();
				result = false;
			}
		}
		return result;
	});
	return new c();
})();



/***
 * ChangePassword namespace.
 * Controls the form and related actions.
 * Extends AFormController.
 */
var ChangePassword = (function() {
	var c = function() {};
	c.extend(AFormController);
	c.addMethod('_getForm', function () {
		if (!this._form) {
			var id = 'formChangePassword';
			this._form = document.getElementById(id);
			if (!this._form) {
				throw "Unable to find DOM element with id '" + id + "'.";
			}
		}
		return this._form;
	});
	c.addMethod('_getFieldDefs', function () {
		if (!this._fielddefs) {
			this._fielddefs = {
				// name => [required, desc, validator]
				'password'		: [true	, Strings['current_password']	, ValidatorFactory.get('password')],
				'new_password'	: [true	, Strings['new_password']		, ValidatorFactory.get('password')],
				'new_password2'	: [true	, Strings['new_password2']		, ValidatorFactory.get('password')]
			};
		}
		return this._fielddefs;
	});
	c.addMethod('validate', function () {
		var result = this.callSuper('validate');
		if (result) {
			var f = this._getForm();
			if (f.elements['new_password'].value != f.elements['new_password2'].value) {
				alert(Strings['err_new_password_mismatch']);
				f.elements['new_password'].focus();
				result = false;
			}
		}
		return result;
	});
	return new c();
})();



/***
 * DeleteAccount namespace.
 * Controls the form and related actions.
 * Extends AFormController.
 */
var DeleteAccount = (function() {
	var c = function() {};
	c.extend(AFormController);
	c.addMethod('_getForm', function () {
		if (!this._form) {
			var id = 'formDeleteAccount';
			this._form = document.getElementById(id);
			if (!this._form) {
				throw "Unable to find DOM element with id '" + id + "'.";
			}
		}
		return this._form;
	});
	c.addMethod('_getFieldDefs', function () {
		if (!this._fielddefs) {
			this._fielddefs = {};
		}
		return this._fielddefs;
	});
	c.addMethod('validate', function () {
		var f = this._getForm();
		if (!f.elements['confirmed'].checked) {
			alert(Strings['err_confirm_del_profile']);
			return false;
		}
		return true;
	});
	return new c();
})();




/***
 * AltAddress namespace.
 * Controls the form and related actions.
 * Extends AFormController.
 */
var AltAddress = (function() {
	var c = function() {};
	c.extend(AFormController);
	c.addMethod('_getForm', function () {
		if (!this._form) {
			var id = 'formAltAddress';
			this._form = document.getElementById(id);
			if (!this._form) {
				throw "Unable to find DOM element with id '" + id + "'.";
			}
		}
		return this._form;
	});
	c.addMethod('_getFieldDefs', function () {
		if (!this._fielddefs) {
			this._fielddefs = {
				// name => [required, desc, validator]
				'alt_company'		: [false, Strings['company']	, ValidatorFactory.get('company')],
				'alt_name'			: [false, Strings['name']		, ValidatorFactory.get('name')],
				'alt_address'		: [true	, Strings['address']	, ValidatorFactory.get('address')],
				'alt_postalcode'	: [true	, Strings['postalcode']	, ValidatorFactory.get('postalcode')],
				'alt_city'			: [true	, Strings['city']		, ValidatorFactory.get('city')],
				'alt_country_code'	: [true	, Strings['country']	, ValidatorFactory.get('country_code')]
			};
		}
		return this._fielddefs;
	});
	c.addMethod('validate', function () {
		var f = this._getForm();
		var result = true;
		if (f.elements['delivery'][2].checked) {
			result = this.callSuper('validate');
			if (result) {
				// Check for house number in address for countries that require it.
				var addr = f.elements['alt_address'].value;
				if (!addr.match(/\d+/)) {
					var ecc = f.elements['alt_country_code'];
					var i = ecc.selectedIndex;
					if (i >= 0) {
						var cc = ecc.options[i].value;
						if (cc == 'NL') {
							var error = Strings['err_fields_syntax'] + "\n\t" + Strings['alt_address'];
							alert(error);
							ecc.focus();
							result = false;
						}
					}
				}
			}
		}
		if (result) {
			if (!f.elements['conditions_accepted'].checked) {
				alert(Strings['err_accept_conditions']);
				result = false;
			}
		}
		return result;
	});

	return new c();
})();





/***
 * NoRegister namespace.
 * Controls the form and related actions.
 * Extends AFormController.
 */
var NoRegister = (function() {
	var c = function() {};
	c.extend(AFormController);
	c.addMethod('_getForm', function () {
		if (!this._form) {
			var id = 'formNoRegister';
			this._form = document.getElementById(id);
			if (!this._form) {
				throw "Unable to find DOM element with id '" + id + "'.";
			}
		}
		return this._form;
	});
	c.addMethod('_getFieldDefs', function () {
		if (!this._fielddefs) {
			this._fielddefs = {
				// name => [required, desc, validator]
				'email'				: [true	, Strings['email']			, ValidatorFactory.get('email')],
				'company'			: [false, Strings['company']		, ValidatorFactory.get('company')],
				'gender'			: [true	, Strings['gender']			, ValidatorFactory.get('gender')],
				'firstname'			: [true	, Strings['firstname']		, ValidatorFactory.get('firstname')],
				'lastname'			: [true	, Strings['surname']		, ValidatorFactory.get('lastname')],
				'telephone'			: [false, Strings['telephone']		, ValidatorFactory.get('telephone')],
				'address'			: [true	, Strings['address']		, ValidatorFactory.get('address')],
				'postalcode'		: [true	, Strings['postalcode']		, ValidatorFactory.get('postalcode')],
				'city'				: [true	, Strings['city']			, ValidatorFactory.get('city')],
				'country_code'		: [true	, Strings['country']		, ValidatorFactory.get('country_code')],
				'alt_company'		: [false, Strings['alt_company']	, ValidatorFactory.get('company')],
				'alt_name'			: [false, Strings['alt_name']		, ValidatorFactory.get('name')],
				'alt_address'		: [false, Strings['alt_address']	, ValidatorFactory.get('address')],
				'alt_postalcode'	: [false, Strings['alt_postalcode']	, ValidatorFactory.get('postalcode')],
				'alt_city'			: [false, Strings['alt_city']		, ValidatorFactory.get('city')],
				'alt_country_code'	: [false, Strings['alt_country']	, ValidatorFactory.get('country_code')]
			};
		}
		return this._fielddefs;
	});
	c.addMethod('validate', function () {
		var f = this._getForm();
		var result;
		if (f.elements['delivery'][2].checked) {
			this._getFieldDefs(); // makes sure they are initialized
			var alts = ['alt_address', 'alt_postalcode', 'alt_city', 'alt_country_code'];
			for (var i=0; i < alts.length; i++) {
				this._fielddefs[alts[i]][0] = true;
			}
			result = this.callSuper('validate');
			for (var i=0; i < alts.length; i++) {
				this._fielddefs[alts[i]][0] = false;
			}
		}
		else {
			result = this.callSuper('validate');
		}
		if (result) {
			// Check for house number in address for countries that require it.
			var addr = f.elements['address'].value;
			if (!addr.match(/\d+/)) {
				var ecc = f.elements['country_code'];
				var i = ecc.selectedIndex;
				if (i >= 0) {
					var cc = ecc.options[i].value;
					if (cc == 'NL') {
						var error = Strings['err_fields_syntax'] + "\n\t" + Strings['address'];
						alert(error);
						ecc.focus();
						result = false;
					}
				}
			}
		}
		if (result && f.elements['delivery'][2].checked) {
			// Check for house number in address for countries that require it.
			var addr = f.elements['alt_address'].value;
			if (!addr.match(/\d+/)) {
				var ecc = f.elements['alt_country_code'];
				var i = ecc.selectedIndex;
				if (i >= 0) {
					var cc = ecc.options[i].value;
					if (cc == 'NL') {
						var error = Strings['err_fields_syntax'] + "\n\t" + Strings['alt_address'];
						alert(error);
						ecc.focus();
						result = false;
					}
				}
			}
		}
		if (result) {
			if (!f.elements['conditions_accepted'].checked) {
				alert(Strings['err_accept_conditions']);
				result = false;
			}
		}
		return result;
	});

	return new c();
})();






/***
 * PaymentMethod namespace.
 * Controls the form and related actions.
 * Extends AFormController.
 */
var PaymentMethod = (function() {
	var c = function() {};
	c.extend(AFormController);
	c.addMethod('_getForm', function () {
		if (!this._form) {
			var id = 'formPaymentMethod';
			this._form = document.getElementById(id);
			if (!this._form) {
				throw "Unable to find DOM element with id '" + id + "'.";
			}
		}
		return this._form;
	});
	c.addMethod('_getFieldDefs', function () {
		if (!this._fielddefs) {
			this._fielddefs = {
				// name => [required, desc, validator]
				'payment_method': [true	, Strings['payment_method'], null]
			};
		}
		return this._fielddefs;
	});
	c.addMethod('validate', function () {
		var f = this._getForm();
		var result = false;
		var radios = f.elements['payment_method'];
		if (radios.type) {
			result = radios.checked;
		}
		else {
			for (var i=0; i<radios.length; i++) {
				if (radios[i].checked) {
					result = true;
					break;
				}
			}
		}
		if (!result) {
			alert(Strings['err_no_payment_method']);
		}
		return result;
	});

	return new c();
})();




/***
 * Contact namespace.
 * Controls the form and related actions.
 * Extends AFormController.
 */
var Contact = (function() {
	var c = function() {};
	c.extend(AFormController);
	c.addMethod('_getForm', function () {
		if (!this._form) {
			var id = 'formContact';
			this._form = document.getElementById(id);
			if (!this._form) {
				throw "Unable to find DOM element with id '" + id + "'.";
			}
		}
		return this._form;
	});
	c.addMethod('_getFieldDefs', function () {
		if (!this._fielddefs) {
			this._fielddefs = {
				// name => [required, desc, validator]
				'email'		: [true	, Strings['email']	, ValidatorFactory.get('email')],
				'name'		: [true	, Strings['name']	, null],
				'message'	: [true	, Strings['message'], null]
			};
		}
		return this._fielddefs;
	});
	return new c();
})();

