/**
 Copyright (c) 2010, iModel Ltd. All rights reserved.
 Code licensed under the BSD License:
 http://www.i-model.co.uk/codebase/license.html
 version: 1.3.1
 
 Author: 		Phil Ewington (phil.ewington@i-model.co.uk)
 History:		1.0 - 22/04/08
				1.1 - 12/01/10 Added YUI3 dialog for alerts
 				1.2 - 08/08/10 Added global error handler
 */
 
 
/**
 * validForm object
 * @method validForm
 * @param errHandler {object} global error handler
 * @public
 */
var validForm = function(form, errHandler) {
	/**
	 * public properties
	 */
	this.submitted = false,		// controls submitting form more than once
	
	/**
	 * private properties
	 */
	this.form = form,								// form id to validate
	this.currentField = {},							// holds current field during validation
	this.taskList = [],								// object to hold validation tasks
	this.currentTask = 0,							// index of current task during validation
	this.errHandler = errHandler || null,			// override global error handler								
													
		
	// -----------------------
	// public methods
	// -----------------------
	
	/**
	 * function to create a task object
	 * @method createTask
	 * @access public
	 * @param fieldname {string} 
	 * @param required {boolean}
	 * @param msg {string}
	 * @param callback {function}
	 */
	this.createTask = function(fieldname, type, msg, callback) {
		
		// create task object
		task = {
			fieldname: fieldname,
			type: type,
			msg: msg,
			callback: callback || null
		}
		
		// dont add if it already exists
		for (var i=0; i < this.taskList.length; i++) {
			if (this.taskList[i].fieldname == fieldname) return false;
		}
		
		// add task to task list
		this._addTask(task);
	},
	
	/**
	 * function to remove field from task list
	 * @method removeTask
	 * @access public
	 * @param fieldname {string} 
	 */
	this.removeTask = function(fieldname) {
		for (var i=0; i < this.taskList.length; i++) {
			if (this.taskList[i].fieldname == fieldname) {
				this.taskList.splice(i, 1);
				return;
			}
		}
		return false;
	},
	
	/**
	 * function to reset submitted value
	 * @method reset
	 * @access public
	 */
	this.reset = function() {
		this.submitted = false;
	},
	

	this.validate = function() {
		
		// nothing to do if taskList is empty
		if (!this.taskList.length) return true;
		
		// do not allow submit button to be pressed more than once
		if (this.submitted) {
			var params = {
				height:40,
				dialogIcon:'alert',
				dialogText:'The form has already been submitted, please wait for a response from the remote server.'
			}
			dialog.show(params);
			return false;
		}
	
		for (i=0; i<this.taskList.length; i++) {
			
			// set current field from taskList
			var form = document.getElementById(this.form);
			this.currentField = form.elements[this.taskList[i].fieldname];
			this.currentTask = i;
			
			// determine validationType
			switch (this.taskList[i].type) {
	
				case 'required':
				
					// Validation of text,password,file,textarea,hidden fields
					if (this.currentField.type == 'text' || this.currentField.type == 'password' ||
						this.currentField.type == 'textarea' || this.currentField.type == 'file' ||
						this.currentField.type == 'hidden') {
						
						// Missing field
						if (!this.currentField.value || this.currentField.value == null) {
							if(this.taskList[this.currentTask].msg) {
								var params = {
									height:40,
									dialogIcon:'alert',
									dialogText: this.taskList[this.currentTask].msg
								}
								dialog.show(params);
								return false;
							}
						}

						// Callback
						if (this.taskList[this.currentTask].callback != null)
						{
							var callback = this.taskList[this.currentTask].callback;
							if (!callback(this.currentField.value, true)) {
								this.submitted = false;
								return false;
							}
						}
					}
	
					// validation of select lists
					if (this.currentField.type == 'select-one' || this.currentField.type == 'select-multiple') {

						if (this.currentField[this.currentField.selectedIndex].value == 'null') {

							if(this.taskList[this.currentTask].msg) {
								
								var params = {
									height:40,
									dialogIcon:'alert',
									dialogText: this.taskList[this.currentTask].msg,
									validForm: this
								}
								dialog.show(params);
								return false;							
							} 
							
						}
						
						// Callback
						if (this.taskList[this.currentTask].callback != null)
						{
							var callback = this.taskList[this.currentTask].callback;
							if (!callback(this.currentField.value, true)) {
								return false;
							}
						}
					}
	
					// validation of checkboxes
					if (this.currentField.type == 'checkbox') {
						if (!this.currentField.checked) {
							if (this.taskList[this.currentTask].msg) {
								var params = {
									height:40,
									dialogIcon:'alert',
									dialogText: this.taskList[this.currentTask].msg,
									validForm: this
								}
								dialog.show(params);
								return false;							
							}
						}
						
						// Callback
						if (this.taskList[this.currentTask].callback != null)
						{
							var callback = this.taskList[this.currentTask].callback;
							if (!callback(this.currentField.value, true)) {
								return false;
							}
						}
					}
	
					// validation of radio buttons
					if (this.currentField.length && this.currentField[0].type == 'radio') {
						var optionSelected = false;
						for (var j = 0; j < this.currentField.length; j++) {
							if (this.currentField[j].checked) {
								optionSelected = true;
								break;
							}
						}
						if (!optionSelected) {
							if (this.taskList[this.currentTask].msg) {
								var params = {
									height:40,
									dialogIcon:'alert',
									dialogText: this.taskList[this.currentTask].msg,
									validForm: this
								}
								dialog.show(params);
								return false;
							}
						}
						
						if (optionSelected)
						{					
							// Callback
							if (this.taskList[this.currentTask].callback != null)
							{
								var callback = this.taskList[this.currentTask].callback;
								if (!callback(this.currentField.value, true)) {
									return false;
								}
							}
						}
					}
					break;
					
					case 'custom':
						
						// custom function should be run, function is found in callback param
						var callback = this.taskList[this.currentTask].callback;
						if (!callback(this.currentField.value, true)) {
							return false;
						}
						break;			
			}
		}
		// ensure form is only submitted once
		this.submitted = true;
		return true;
	},
	
	// -----------------------
	// custom methods
	// -----------------------
	
	// UK Telephone number
	this.isUKTelephone = function(num) {
		
		if (arguments.lenth == 0) {
			// remove spaces
			var num = this.currentField.value.replace(/\s/g, '');
		}
		else {
			// remove spaces
			num = num.replace(/\s/g, '');
		}
		
		// a UK landline number is 11 digits long and starts with a 0
		// 01 & 02 numbers are the norm
		// 030, 033, 034, 037, 055 & 056 are also all valid
		var exp = new RegExp(/^0((1|2)[0-9]{9}|(30|33|34|37|55|56)[0-9]{8})$/);
		if (!exp.test(num)) {
			return false;
		}
		
		// tests passed
		return true;
	},
	
	// UK Mobile number
	this.isUKMobile = function(num) {
		
		if (arguments.lenth == 0) {
			// remove spaces
			var num = this.currentField.value.replace(/\s/g, '');
		}
		else {
			// remove spaces
			num = num.replace(/\s/g, '');
		}
		
		// basic format test
		// a UK landline number is 10 digits long and starts with a 0
		// 01 & 02 numbers are the norm
		var exp = new RegExp(/^07([1-5]|[7-9])[0-9]{8}$/);
		if (!exp.test(num)) {
			return false;
		}
		
		// tests passed
		return true;
	},
	
	// UK Postcode
	this.isUKPostcode = function(pcode) {
		
		// remove spaces
		var pcode  = this.currentField.value.replace(/\s/g, '');
		
		// format regex
		var exp = new RegExp(/^((GIR\s?0AA)|[^QVX]{1}[0-9]{1}|[^QVX]{1}[0-9]{2}|[^QVX]{1}[^IJZ]{1}[0-9]{1}|[^QVX]{1}[^IJZ]{1}[0-9]{2}|[^QVX]{1}[0-9]{1}[ABCDEFGHJKSTUW]{1}|[^QVX]{1}[^IJZ]{1}[0-9]{1}[ABEHMNPRVWXY]{1})(\s?)([0-9]{1}[^CIKMOV]{2})$/g);
	
		// test passed pcode against regex
		if (complex.test(pcode.toUpperCase())) return true;
		
		return false;
	},
	
	// -----------------------
	// private methods
	// -----------------------
	
	/**
	 * function to add a new task for processing
	 * @method addTask
	 * @access private
	 * @param {object} task to add to list
	 */
	this._addTask = function(task) {
		this.taskList.push(task);
	},
	
	/**
	 * global error handler
	 * @method errHandler
	 * @access private
	 */
	 this._errHandler = function() {

		// set focus on required field
		if (!this.currentField.disabled && this.currentField.type != 'hidden') {
			this.currentField.focus();
		}
	 };
};
