/*
*/

var validation = { fulltext : /^.+$/,
                   alpha    : /^[a-zA-Z]+$/,
									 alphanum : /^[0-9a-zA-Z]+$/,
									 num      : /^[0-9]+$/,
									 email    : /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/,
									 free     : /^.+$/m };
									  
function form_validator(form_name) {
	this.name=form_name;
	this.form=null;
	this.fields=new Array();
	this.messages="";
}

/**
 * parameters: name     - name of the field this will reference to
 *             type     - an enumerated value to identify the type of validation required
 */
form_validator.prototype.add_field=function (name) {
	var field=new Array();
	switch(arguments.length) {
		case 4:
			if(arguments[2]=="custom") {
				field.custom=arguments[3];
			}
			else {
				field.custom=null;
			}
		case 3:
			field.type=arguments[2];
		case 2:
			if(arguments[1]!="")
				field.label= arguments[1];
			else
				field.label=arguments[0];
		case 1:
			if(!field.type)
				field.type="free";
			this.fields[arguments[0]]=field;
	}
}


/**
 * Form Validator Initialisation
 */
form_validator.prototype.init=function () {
	for(var i=0; i < document.forms.length; i++) {
		if(document.forms[i].name==this.name) {
			this.form=document.forms[i];
			break;
		}
	}
	
	if(this.form==null)
		this.form=document.getElementById(this.name);
	
	if(this.form==null) {
		alert("Could not complete initialisation of the form validator.\nCould not find a form named '" + this.name + "'");
		return false;
	}	
	
	if(this.debug) {
		this.debug_panel=new script_debugger("bsc_debug_panel");
		
		this.debug_panel.add_message("Debug panel initialised...");
		this.debug_panel.add_message("Form validator initialised...");
		this.debug_panel.add_line_break();
		
		var count=0;
		
		for(field in this.fields) {
			count++;
		}
		
		this.debug_panel.add_message(count + " fields require validation");
	}
}

form_validator.prototype.validate=function () {
	var inputs=this.form.getElementsByTagName("input");
	var selects=this.form.getElementsByTagName("select");
	var textareas=this.form.getElementsByTagName("textarea");
	var current_input_name='';
	var itemChecked=false;
	var returnValue=true;
	var errors=Array();
	
	this._strip_form_errors(inputs);
	this._strip_form_errors(selects);
	this._strip_form_errors(textareas);
	
	this.clear_errors();
	
	if(this.debug) {			
		for(var i=0; i < inputs.length; i++) {
			var input=inputs[i];
			this.debug_panel.add_message(input.name + " is awaiting validation..");
		}
		
		this.debug_panel.add_line_break();
		
		this.debug_panel.add_message('Found ' + inputs.length + ' input elements');
		this.debug_panel.add_message('Found ' + textareas.length + ' textarea elements');
		this.debug_panel.add_message('Found ' + selects.length + ' select elements');
		this.debug_panel.add_line_break();		
		this.debug_panel.add_message('Validating input elements...');
		this.debug_panel.add_line_break();		
	}
	
	for(var i=0; i < inputs.length; i++) {
		var input=inputs[i];
		
		if(this.debug) {
			this.debug_panel.add_message("Currently validating " + input.name + " which is item " + i + ' in the inputs list');
		}
		
		if(input.name=="") {
			if(this.debug) {
				this.debug_panel.add_message("Current input has no name... Skipping validation...");
				this.debug_panel.add_line_break();		
			}
			continue;
		}
		
		if(input.type=="submit" || input.type=="button" || input.type=="image" || !this.fields[input.name]) {			
			if(this.debug) {
				if(!this.field[input.name])
					this.debug_panel.add_message(input.name + ' is not a required field...');
				else 
					this.debug_panel.add_message(input.name + ' is a ' + input.type + " which can't be validated...");
				
				this.debug_panel.add_message("Skipping validation for " + input.name);
				this.debug_panel.add_line_break();
			}
			
			continue;
		}
		
		if(input.type=='radio') {
			if(this.debug) {
				this.debug_panel.add_message(input.name + ' is a radio button');
			}
			
			var j=0;
			var boxes=new Array();
			
			do {
				input=inputs[i+j];
				boxes.push(input);
				
				if(input.checked) itemChecked=itemChecked || true;
				j++;
			} while(inputs[j+i].name == input.name);
			
			i+=j-1; // realign the counter to be the current input index			
				
				
			if(this.debug) {
				this.debug_panel.add_message(input.name + ' validation ' + (itemChecked ? ' succeeded' : ' failed'));
				this.debug_panel.add_line_break();
			}
			
			if(!itemChecked) {
				this.messages+="You must select at least one of the options for " + this.fields[input.name].label + "\n";
				
				while(boxes.length>0)
					errors.push(boxes.pop());
			}
		}
		else if(input.type=='checkbox') {			
			if(this.debug) {
				this.debug_panel.add_message(input.name + ' is a check box');
			}
			
			var j=0;
			
			var boxes=new Array();
			
			do {
				input=inputs[i+j];
				boxes.push(input);
				
				if(input.checked) itemChecked=itemChecked || true;
				j++;
			} while(inputs[j+i].name == input.name);
			
			i+=j-1; // realign the counter to be the current input index
			
				
			if(this.debug) {
				this.debug_panel.add_message("Validated " + j + " check boxes...");
				this.debug_panel.add_message(input.name + ' validation ' + (itemChecked ? ' succeeded' : ' failed'));
				this.debug_panel.add_line_break();
			}
			
			if(!itemChecked) {
				this.messages+="You must select at least one of the options for " + this.fields[input.name].label + "\n";
				
				while(boxes.length>0)
					errors.push(boxes.pop());
			}
		}
		else { // all that leaves is text fields
			
			if(this.debug) {
				this.debug_panel.add_message(input.name + ' is a text field');
			}
			
			if(this.fields[input.name].custom!=null) {
				itemChecked=this.fields[input.name].custom(input.value);
				
				if(!itemChecked) {
					this.messages+="You must provide an answer for " + this.fields[input.name].label + "\n";
					errors.push(input);
				}
			}
			else {
				regex=validation[this.fields[input.name].type];
				
				if(this.debug) {
					this.debug_panel.add_message(input.name + ' requires ' + this.fields[input.name].type + ' validation...');
				}
				
				itemChecked=(regex.test(input.value) && input.value!='');
				
				if(this.debug) {
					this.debug_panel.add_message(input.name + ' validation ' + (itemChecked ? ' succeeded' : ' failed'));
					this.debug_panel.add_line_break();
				}
					
				if(!itemChecked) {
					if(this.fields[input.name].type=="email")
						this.messages+=this.fields[input.name].label + " must be an email address\n";
					else if(this.fields[input.name].type=="alpha") 
						this.messages+=this.fields[input.name].label + " can only contain characters from the alphabet\n";
					else if(this.fields[input.name].type=="alphanum")
						this.messages+=this.fields[input.name].label + " can only contain characters from the alphabet and/or numbers\n";
					else if(this.fields[input.name].type=="num")
						this.messages+=this.fields[input.name].label + " can only contain numbers\n";
					else  {
						this.messages+=this.fields[input.name].label + " cannot be left empty\n";
					}
					errors.push(input);
				}
			}
		}
		returnValue=returnValue && itemChecked;
		itemChecked = false;
	}
	
			
	if(this.debug) {
		this.debug_panel.add_message('Validating select inputs...');
		this.debug_panel.add_line_break();
	}
	
	for(var i=0; i < selects.length; i++) {
		var select=selects[i];
		var itemChecked=true;
		
		if(this.debug) {
			this.debug_panel.add_message(select.name + ' requires ' + this.fields[select.name].type + ' validation...');
		}
		
		if(this.fields[select.name] && (select.value==null || select.value=="")) {
			itemChecked = false;
			this.messages += "You must select a option for " + this.fields[select.name].label + "\n";
			errors.push(select);
		}
		
		returnValue = returnValue && itemChecked;
		itemChecked = true;
	}
	
	for(var i=0; i < textareas.length; i++) {
		var textarea=textareas[i];
		var itemChecked=true;
		
		if(this.fields[textarea.name]) {
			if(this.fields[textarea.name].custom!=null) {
				itemChecked=this.fields[textarea.name].custom(textarea.value);
			}
			else {
				var regex=validation[this.fields[textarea.name].type];			
				itemChecked=regex.test(textarea.value);
			}
					
			if(!itemChecked) {
				this.messages+=this.fields[textarea.name].label + " cannot be left empty\n";
				errors.push(textarea);
			}
		}
		
		returnValue=returnValue && itemChecked;
		itemChecked = true;
	}
	
	this._show_form_errors(errors);
	
	// we are debugging so NEVER return true, we don't want the form to be processed if we are debugging
	if(this.debug) return false;
	
				
	if(this.debug) {
		this.debug_panel.add_message('Overall validation ' + (returnValue ? ' succeeded' : ' failed'));
	}
	
	return returnValue;
}


form_validator.prototype.get_errors=function (clear) {
	var messages="";
	
	if(clear) {
		messages=this.messages; 
		this.messages="";
	}
	
	return messages;
}

form_validator.prototype._show_form_errors=function (arrayObj) {
	var obj=null;
	
	for(var i=0; i < arrayObj.length; i++) {
		obj=arrayObj[i];
		
		if(obj.className!="") {
			obj.className="form_validator_errors " + obj.className;
		}
		else {
			obj.className="form_validator_errors";
		}
	}
	
	if(this.messages!='') {
		this._display_errors();
	}
}

form_validator.prototype._strip_form_errors=function (arrayObj) {
	var obj=null;
	
	var div=document.getElementById("form_validator_error_message");
	if(div!=null) {
		this.form.removeChild(div);
	}
	
	for(var i=0; i < arrayObj.length; i++) {
		obj=arrayObj[i];
		
		if(obj.className=="") continue;
		
		var className="form_validator_errors";
		var position=obj.className.indexOf(className);
		
		if(position>=0) {
			if(obj.className.length==className.length) {
				obj.className="";
			}
			else {
				if(position>0 && obj.className.charAt(position-1)==' ') {
					position--;
					className=' ' + className;
				}
				
				if(position+className.length < obj.className.length && obj.className.charAt(position + className.length-1)==' ' && className.charAt(0)!=' ') {
					className+=' ';
				}
				
				obj.className=obj.className.substr(position,className.length-1);
			}
		}
	}
}

form_validator.prototype._display_errors=function () {
		if(this.display_type=="alert") {
			alert(this.messages);
		}
		else if(this.display_type=="inline") {
			var message=this.messages.split('\n');
			
			var div=document.createElement("div");
			div.id="form_validator_error_message";
			
			for(var i=0; i < message.length; i++) {
				div.appendChild(document.createTextNode(message[i]));
				if(i<message.length-1)
					div.appendChild(document.createElement("br"));
			}
			
			this.form.insertBefore(div,this.form.childNodes[0]);
		}
}

form_validator.prototype.has_errors   = function () { return this.messages!=""; }
form_validator.prototype.clear_errors = function () { this.messages="";         }

form_validator.prototype.display_type = "alert";
form_validator.prototype.debug        = false;


if(!self.addLoadEvent) {
	// appending the addLoadEvent method, if it hasn't been defined already
	// function written by Simon Willison (simon.incutio.com)
	function addLoadEvent(func) {
		var oldonload = window.onload;
		if (typeof(window.onload) != 'function') {
			window.onload = func;
		} else {
			window.onload = function() {
				oldonload();
				func();
			}
		}
	}
}
