var forms = {
	
	self  : false,
	fdata  : false,
	rules : false,
	//	this is when the required field "submit" is setup
	//	to call a javascript call instead of default vaidation action
	setup : function(frmid, fieldRules)
	{
		var  frm = dom.byId(frmid);
		if( !frm ) {
			alert(frmid + " could not be found");
			return;
		}
		//	store form in memory along with validation rules
		//forms.data[{"obj":frm, "rules":fieldRules}];
		//	load rules into memory for future requests 
		dom.addEvent(frm, "submit",  
			function(e){
					//...
					forms.self  = frm;
					forms.rules = fieldRules;
					forms.fdata  = false;
				}
		, false);
		//dom.addEvent(frm, "submit",  (fieldRules.callback) ? fieldRules.callback : function(e){forms.validate(e, fieldRules);}, false);
		dom.addEvent(frm, "submit",  (fieldRules.callback) ? fieldRules.callback : function(e){forms.validate(e, fieldRules);}, false);
	},

	
	validate : function(e, rules)
	{
		var custom  = "";
		var missing = [];
		var frm = dom.getEventElement(e);
		//	get rid of stupid dotted lines on submit button
		forms.get(frm, "submit").blur(); 
		//	find missing form values
		if( !rules &&  forms.self.name == frm.name){
			rules = forms.rules;
		}
		//	check for missing required fields
		for(var key in rules){
			if( rules[key].required ){
				var field = frm[key];
				if( field instanceof Object ){
					if( dom.isArray(field) ){
						//	may not need to be done
						//for(var i = 0; i < frm[key].length; i++){
						//	 alert(frm[key][i].value);
						//}
							
						//alert(frm[key]);	
					}else{
						if( field.type == "checkbox" || field.type == "radio"){
							if( !field.checked ) missing.push(field);	
						}else{
							var val = field.value.trim();
							//	check values are not empty
							if( val.length === 0 || val === "" ){
								missing.push(field);
							}
							//	just check for array field.
							if( dom.isArray(field) ){
								missing.push(field[0]);
							}
						}
					}
				}
			}
			//if( missing.length ) custom = "there are required fields missing in the forms.";
		}
		//	check field lengths
		if( !missing.length ){
			for(var key in rules){
				if( rules[key].min && frm[key].value.length < rules[key].min ){
					missing.push(frm[key]);
					custom = "'"+ forms.getLabel(frm, frm[key]).firstChild.nodeValue +"' must have a minimum of '"+ rules[key].min +"' characters.";
					continue;
				}
				if( rules[key].max && frm[key].value.length > rules[key].max ){
					missing.push(frm[key]);
					custom = "'"+ forms.getLabel(frm, frm[key]).firstChild.nodeValue +"' has too many characters, a maximum of '"+ rules[key].max  +"' is only allowed.";
					continue;
				}
			}
		}
		
		//	check datatypes
		if( !missing.length ){
			for(var key in rules){
				if( rules[key].type ){
					var field = frm[key];
					if( field.value != ""){
						switch(rules[key].type){
							case "email" :
								if( !field.value.email() ){
									missing.push(field);
									custom += "'"+ forms.getLabel(frm, frm[key]).firstChild.nodeValue +"' is not a valid email address.<br />";
								}
							break;
							case "alphanumeric" :
								if( !field.value.match(/^[a-zA-Z0-9]+$/) ){
									missing.push(field);
									custom += "'"+ forms.getLabel(frm, frm[key]).firstChild.nodeValue  +"' can only contain letters or numbers.<br />";
								}
							break;
							case "number" :
								if( field.value != parseInt(frm[key].value) ){
									missing.push(field);
									custom += "'"+ forms.getLabel(frm, frm[key]).firstChild.nodeValue +"' can only contain numbers.<br />";
								}
							break;
							case "phone" :
								if( !field.value.match(/^[ 0-9-()\+]+$/) ){
									missing.push(field);
									custom += "'"+ forms.getLabel(frm, frm[key]).firstChild.nodeValue +"' is not a valid phone number.<br />"; 
								}
							break;		
						}
					}
				}
			}
		}	
			
		forms.handleErrors(frm, missing);
		//	required fields are missing...setup output functionaliy
		if( missing.length ){
			forms.message(frm, custom);
			//forms.handleErrors(frm, missing);
			dom.cancel(e);	
			return false;
		}
		return true;
	},
	
	get : function(frm, inputType)
	{
		if( frm.elements ){
			
			for(var i = 0; i < frm.elements.length; i++){
				if( frm.elements[i].type && frm.elements[i].type == inputType ){	
					return frm.elements[i];
				}
			}
		}
		return false;
	},
	
	//	quick reference to pass back the label of an input element
	getLabel : function(frm, forInput)
	{
		var labels = dom.byTag("label", frm);
		for(var i = 0; i < labels.length; i++){
			var f = dom.hasAttr(labels[i], "for", true);
			if( f == frm.name+"-"+forInput.name ){
				return 	labels[i];
			}
		}
		return false;
	},
	
	
	/*  CUSTOM RESPONSE */
	handleErrors : function(frm, fields, simpleFieldArray)
	{
		if( !dom.isObject(frm) ) frm = dom.byId(frm);
		if( simpleFieldArray ){
			fields = [];
			for(var f = 0; f < simpleFieldArray.length; f++){
				fields.push(frm[simpleFieldArray[f]]);
			}	
		}
		var classname = "rferror";
		//	set error display for input fields that have errors
		dom.swapClass(frm, classname, "");
		dom.addClass(fields, classname);
		
		//	do custom label display
		var labels = dom.byTag("label", frm);
		dom.swapClass(labels, classname, "");
		var n = frm.name;
		for(var l = 0; l < labels.length; l++){
			var obj = dom.byId(dom.hasAttr(labels[l], "for", true));
			if( obj && dom.inArray(obj, fields) ){
				dom.addClass([labels[l]], classname);
			}
		}
	},
	
	
	/*  CUSTOM RESPONSE */
	message : function(frm, msg, classname)
	{
		var defaultMsg = "there are required fields in the form that are missing.";
		//	default classes and message
		var classes = new Array("alerterror", "alertpassed", "alertwarning");
		if( !msg || msg === "" ) msg = defaultMsg;
		//	clear text node, if any and setup...	
		forms.removeMessage(frm, true);
		
		var chld = frm.firstChild;
		var clss = ( !classname ? classes[0] : classes[1] );

		if( dom.hasClass(chld, "alert") ){
			var div = chld;
			chld.className = "alert "+ clss;
			chld.innerHTML = msg;
			sfx.flash(chld, 1000);
		}
		else{
			var div = dom.create("div");
			div.className = "alert "+ clss;
			div.innerHTML = msg;
			sfx.setOpacity(div, 0);
			frm.insertBefore(div, chld);
			sfx.fadeIn(div);
		}
		//	check to make sure overflow doesn't hide the base of form with alert error is displayed
		var p = frm.parentNode;
		if( p.style.overflow == "hidden" ){
			p.style.height = frm.offsetHeight +"px";	
		}
		ajax.hideLoader();
	},
	
	removeMessage : function(frm, textOnly)
	{
		//	clear text node, if any and setup...	
		if( frm.firstChild.nodeType == "3"){
			frm.removeChild(frm.childNodes[0]);
		}
		if( !textOnly ){
			//	remove alert user error
			if( dom.hasClass(frm.firstChild, "alert" ) ){
				frm.removeChild(frm.firstChild);
			}
		}	
	},
	
	/***********************************************************
		get all values/input fields in form  
		buildURL is used for sending back to ajax post request
	********************************************************** */
	data : function(obj, buildURL, exceptions)
	{
		var els = obj.elements;
		if( !exceptions ) exceptions = [];
		
		if( els ){
			if( buildURL ){
				var url = "";
				for(var i = 0; i < els.length; i++) {
					if( !dom.inArray(els[i].name, exceptions) ){
						if( els[i].type == "checkbox" || els[i].type == "radio" ){
							if( els[i].checked ){
								url += "&"+ els[i].name +"="+ els[i].value.encode();
							}	
						}
						else if( els[i].name && els[i].value !== "" ){
							url += "&"+ els[i].name +"="+ els[i].value.encode(); 		
						}
					}
				}
				return url;
			}
			return els;
		}
		else{
			alert("form cannot be defined :: forms.js->data()");	
		}
		return false;
	}
	
}
