/**
 * @author Keith Foster
 * 
 */
var Field = (function(){	
	return function(id){
		var id = id;
		var field = null;
		this.set = function(value) {
			field = value;
		};
		this.get = function() {
			return field;
		};
	};
})();
var Model = (function(){
	return function(fields){
		var dataFields = new Array();
		var getFN = null, setFN = null;
		for(var i=0; n=fields.length, i<n; i++) {
			var fieldName = fields[i].toString();
			dataFields[fieldName] = new Field(fieldName);
			getFN = 'get'+fieldName.charAt(0).toUpperCase()+fieldName.slice(1, fieldName.length);
			setFN = 'set'+fieldName.charAt(0).toUpperCase()+fieldName.slice(1, fieldName.length);
			
			this[getFN] = (function(field){
				return function() {
					return dataFields[field].get();
				} 
			})(fieldName);
			this[setFN] = (function(field){
				return function(value) {
					dataFields[field].set(value);
				}
			})(fieldName);
		}
	}
})();

var Form = (function(){
	
	return function(){
		this.model = new Model(['element', 'requiredFields', 'type', 'invalidFields']);
	}
	
})();
var FormController = (function(){
	var FORMS = new Array();
	var memory = ['contact', 'send', 'comment'];
	var invalidFields = new Array();
	
	function initialise(callback){
		if(!callback) callback = null;
		getForms();
		
		for(var i=0, frm=null; n=FORMS.length, frm=FORMS[i], i<n; i++) {
			frm.model.setRequiredFields(getRequired(frm));			
			frm.model.getElement().obj = frm;
		}
		
		var that = this;
		for(var i=0, frm=null; n=FORMS.length, frm=FORMS[i], i<n; i++) {
			frm.model.getElement().onsubmit = function() {
				if(callback === null) {
					var valid = that.validate(this.obj);
					return valid;
					
				} else {
					if(that.validate(this.obj)){
						callback();
					}				
					return false;
				}
			}
		}
	}
	
	function getRequired(f){
		var required = new Array();
		var labels = f.model.getElement().getElementsByTagName('label');
		var strLabel = null;
		for(var i=0, label = null; n=labels.length, i<n, label=labels[i]; i++){			
			strLabel = label.innerHTML.toString();
			if(strLabel.indexOf('*')!=-1){
				var inputID = label.getAttribute('for')
				required[required.length] = {
					element: document.getElementById(inputID),
					dataType: getDataType(inputID)
				};
			}
		}
		return required;		
	}
	
	function getDataType(inputID){
		var input = document.getElementById(inputID);
		var dataType = null;
		
		if(input){
			if(input.tagName.toLowerCase() == 'input'){
				switch(input.getAttribute('type')){
					case 'text':
						switch(inputID){
							case 'email':
							case 'email_address':
							case 'emailaddress':
								dataType = 'email';
								break
							case 'name':
							case 'firstname':
							case 'first_name':
							case 'lastname':
							case 'last_name':
							case 'surname':
							case 'forename':
								dataType = 'alpha'
								break;
							case 'phone':
							case 'telephone':
							case 'mobile':
							case 'fax':
								dataType = 'numeric';
								break;
							default:
								dataType = 'alphanumeric';
								break;
						}
						break;
					case 'radio':
					case 'checkbox':
						dataType = 'checked';
						break;
					default:
						dataType = 'aomasdfasf';
						break;
					
				}
			} else if(input.tagName.toLowerCase() == 'select') {
				dataType = 'selected';
			} else if(input.tagName.toLowerCase() == 'textarea') {
				dataType = 'alphanumeric';
			}
		}
		return dataType;
	}
	
	/**
	 * Set the HTML element for the form
	 */
	function getForms(){
		var forms = document.getElementsByTagName('form');
		for(var i=0, frm=null; n=forms.length, frm=forms[i], i<n; i++) {
			FORMS[i] = new Form();
			FORMS[i].model.setElement(frm);	
		}
	}
	
	var validationFunctions = {
		alpha: function(element, title, default_label) {
			var msg = 'Only alphabetic characters allowed';
			var regex = /\d/g;
			if(validationFunctions.empty(element.value) || element.value == default_label) {
				msg = 'Please enter a value';
				return {element:element, message:title+' - '+msg };
			} else if(element.value.search(regex)!=-1) { 
				return {element:element, message:title+' - '+msg};	
			}
			return true;
		},
		numeric: function(element, title, default_label) {
			var msg = 'Only numeric characters allowed';
			var regex = /\D/g;
			if(validationFunctions.empty(element.value) || element.value == default_label) {
				msg = 'Please enter a value';
				return {element:element, message:title+' - '+msg };
			} else if(element.value.search(regex)!=-1) {
				return {element:element, message:title+' - '+msg };
			}
			return true;
		},
		alphanumeric: function(element, title, default_label) {
			var msg = 'Please enter a value';
			if(validationFunctions.empty(element.value)) {
				return {element:element, message:title+' - '+msg };
			}
			return true;
		},
		checked: function(element, title, number_checked, max_checked) {	
			number_checked = number_checked ? number_checked : 1;
			max_checked = max_checked ? max_checked : "0";  /* 0 = unlimited */
			
			var msg = 'You must check at least '+number_checked+' checkbox(es).';
			var max_msg = 'You cannot check more than '+max_checked+' checkboxes.';
			var checked = 0;
			var input = element.getElementsByTagName('input')[0];
			var inputs = element.getElementsByTagName('input');
			
			var radios = (input.type == 'radio');
			if(!radios) { // CHECKBOXES
				for(var i=0; i<inputs.length; i++) {
					if(inputs[i].checked) {
						number_checked--;
						
						if(max_checked !== 0)
						{
							checked++;
						}
					}
				}
				
				if(number_checked <= 0 && max_checked == 0) {
					return true;
				} else if(number_checked <= 0 && max_checked == checked) {
					return true;
				}
				
				return {element:element, message:title+' - '+msg };
			} else {
				for(var i=0; i<inputs.length; i++) {
					if(inputs[i].checked) {
						return true;
					}
				}
				return {element:element, message:title+' - '+msg };
			}
		},
		selected: function(element, title) {
			var msg = 'Please select an option';
			var selected = element.options[element.selectedIndex];
			if(selected.value == -1) {
				return {element:element, message:title+' - '+msg };
			}
			return true;
		},
		fileinput: function(element, title) {
			var msg = 'You need to choose a file to upload';
			if(validationFunctions.empty(element.value)) {
				return {element:element, message:title+' - '+msg };
			}
		},
		terms: function(element, title) {
			var msg = 'You must accept the terms & conditions to submit your application.';
			if(!element.checked) {
				return {element:element, message:msg };
			}
		},
		email: function(element, title, default_label) {
			var msg = 'Email not in the correct format';
			var regex = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*\.(\w{2,})$/;
			if(element.value == "" || element.value == default_label) {
				return {element:element, message:title+' - '+msg };
			} else if(element.value.search(regex) == -1) {
				return {element:element, message:title+' - '+msg };
			}
			return true;
		},
		empty: function(value){
			if(value == '') {
				return true;
			} else {
				return false;
			}
		},
		identical: function(element) {
			var fields = element.getElementsByTagName('input');
			
			// I know that this is a very inefficient, but time dictates the quick and obvious solution. <sigh>
			for(var i=0; n=fields.length, i<n; i++) {
				for(var j=0; j<n; j++) {
					if(fields[i].value!=fields[j].value) {
						return {element:element, message:'Please make sure that your email addresses match' };
						return false;
					}
				}
			}
			return true;
		},
		dob: function(element){
			var msg = 'Please make sure you date of birth is in the correct format';
			var strDate = element.value.toString();
			var regex = /\d\d\/\d\d\/\d\d\d\d/;
			
			if(validationFunctions.empty(element.value)) {
				return {element:element, message:'Date of Birth - You must provide a date of birth' };
			} else if(!strDate.match(regex)) {
				return {element:element, message:msg };
			}
			return true;
		},
		yesnoText: function(element, title, defaultLabel, form){
			// if the value of the radio button is yes, then we need to make sure that the text area is not empty.
			var radioButtons = jQuery('label.radio input', element);
			var radioButtonValue = null, inputField = jQuery('label.text input', element).get(0);
			
			for(var i=0; n=radioButtons.length, i<n; i++){
				if(radioButtons.get(i).checked) {
					radioButtonValue = radioButtons.get(i).value;
					break;
				}
			}
			
			if(radioButtonValue == 1){
				if (validationFunctions.empty(inputField.value)) {
					return {
						element: element,
						message: 'You must provide an answer'
					};
				}
			}
			return true;
		}
	}
	
	
	return function(callback){
		initialise.call(this, callback);
		this.hasRequiredFields = function(frm){
			return frm.model.getRequiredFields().length != 0 ? true : false;
		}		
		this.setErrorNotification = function(obj){
			obj.element.className = obj.element.className.toString()+' validation-error';
		};
		this.clearErrorNotifications = function(frm){
			var requiredFields = frm.model.getRequiredFields(), cssClass = null;						
			invalidFields = new Array();
			for(var i=0, input=null; n=requiredFields.length, i<n, input=requiredFields[i]; i++){
				cssClass = input.element.className.toString();
				if(cssClass == 'validation-error'){
					input.element.className = '';
				}
			}
		};
		this.validate = function(frm){
			this.clearErrorNotifications(frm);
			
			if(this.hasRequiredFields(frm)){
				frm.model.setInvalidFields(new Array());
				var validation_type = null, required = frm.model.getRequiredFields();
				var valid = false;
				
				for(var i=0, input=null; n=required.length, i<n, input=required[i]; i++){
					valid = validationFunctions[input.dataType](input.element, input.element.title, '', frm.model.getElement());
					if(valid !== true) {
						frm.model.getInvalidFields().push(valid);
					}
				}
				var invalidFields = frm.model.getInvalidFields();				
				var invalidFieldsCount = invalidFields.length;
				if(invalidFieldsCount > 0){
					for(var i=0, invalidElement=null; i<invalidFieldsCount, invalidElement=invalidFields[i]; i++){
						this.setErrorNotification(invalidElement);
					}
					return false;
				} else {
					return true;
				}
				
			} else {
				return true;
			}
		};
	};
})();
