/**
 * @namespace validation.formValidation
 * @author patrickc
 * @sdoc form_validation.sdoc
 */


/** @id FormValidation */
	function FormValidation(){
		this.alertMessages			= AlertMessages;		// if no flavours installed, javascript alert errors
		this.attachHashmap			= AttachHashmap;		// attach the hashmap to each element
		this.checkElement	 		= CheckElement;			// check form element, access by page
		this.checkElementBespoke	= CheckElementBespoke; 	// check bespoke elements
		this.checkElementCheckbox	= CheckElementCheckbox;	// check checkbox elements
		this.checkElementRadio		= CheckElementRadio;	// check radio elements
		this.checkElementSelect		= CheckElementSelect;	// check select form element
		this.checkElementText 		= CheckElementText;		// check text form element
		this.checkForm 				= CheckForm;			// check entire form
		this.checkFunction			= CheckFunction;		// check a function
		this.checkRegExp			= CheckRegExp;			// check a reg exp
		this.get					= Get;					// get unknown element type
		this.logger					= new Logger;			// log actions 

	
	
		/** @id FormValidation.AlertMessages */
		function AlertMessages(form){
			var message = "Sorry, the form cannot be submitted"
			message+="\n__________________\n";
			form = this.get(form);
			form.validationArray = validation.validation[form.name];
			for (name in form.validationArray){
				if (document.getElementById(name) && document.getElementById(name).message){
					message+="\n  "+ document.getElementById(name).message;
				}
			}
			message+="\n__________________";
			message+="\n\nPlease try again.";
			alert(message);
			if (form.focusEl){
				form.focusEl.focus()
			};
		}

		/** @id FormValidation.Get */
		function Get(el){
			el = ( typeof(el) == "object" ) ? el : ( document.getElementById(el) ) ? document.getElementById(el) : (document.forms[el]) ? document.forms[el] : null ;
			if (el && !el.form){
				el.form = new function(el){while(el){if(el.tagName=='FORM'){return el}el=el.parentNode;}return null;}(el);
			}
			
			return el;
		}

		/** @id FormValidation.CheckForm */
		function CheckForm(form){
			form = this.get(form);
			if (!form){
				if (window.logger){logger.error(new Error,'CheckForm: no such form')}
				return true;
			}
			form.isValid 	= true;
			form.focusEl 	= null;
			if (!form.onsubmit || form.onsubmit == ''){
				form.onsubmit = function(){
					var valid = validation.checkForm(this);
					if (!valid&&validation.flavour&&validation.flavour.linkOnError){
						validation.flavour.linkOnError();
					}
					return valid;
				};
			}
			var isValid 	= form.isValid;
			var el			= null;
			if (!form.validationArray && validation.validation[form.name]){
				form.validationArray = validation.validation[form.name];
				if (window.logger){logger.log('CheckForm: ['+ form.name +']');}
			} else {
				if (window.logger && !form.validationArray){logger.log('CheckForm: no validation array ['+ form.name +']');}
			}			
			for (name in form.validationArray){
				if (document.getElementById(name)){
					el = document.getElementById(name);
					isValid = this.checkElement(el);
					if (!isValid && form.isValid){
						form.isValid = isValid
						form.focusEl = el;
					}
				}
			}
			return form.isValid;
		} 


 

 		/** @id FormValidation.CheckElement */
		function CheckElement(el){
			var ok = true;
			el = this.get(el);
			try{
				if (el.form.validationArray[el.id]){ // does element have a hashmap?
					try {
						if (!el.validationArray){this.attachHashmap(el);}
					} catch(e){if (window.logger){logger.error(e,'CheckElement: attaching hashmap ['+ el.id +']');}};
					el.message = null;
					try {
						if ( el.type == "text" || el.type == "textarea" || el.type == "password" ){
							ok = this.checkElementText(el);
						} else if (/^select/.test(el.type)){
							ok = this.checkElementSelect(el);
						} else if (/^checkbox/.test(el.type)){
							ok = this.checkElementCheckbox(el);
						} else if (/^radio/.test(el.type)){
							ok = this.checkElementRadio(el);
						} else {
							ok = this.checkElementBespoke(el);
						}	
					} catch (e){if (window.logger){logger.error(e,'CheckElement: if statment ['+ el.id +']');}}		
				}
			} catch(e){if (window.logger){logger.error(e,'CheckElement: checking ['+ el.type +']');}}			
			return ok;
		} 		
			
		/** @id FormValidation.AttachHashmap */
		function AttachHashmap(el){
			if (!el.validationArray){
				if (el.form.validationArray[el.id]){
					el.validationArray = el.form.validationArray[el.id];
				}
			}				
		}		


		/** @id FormValidation.CheckElementText */
		function CheckElementText(el){
			var ok = true;
			var validation = [];
			for (var i=0;i<el.validationArray.length;i++){
				validation = el.validationArray[i];
				if ( validation[0] ){
					ok = this.checkRegExp(validation[1][1],validation[1][0],el.value);
				} else {
					ok = this.checkFunction(el,validation[1][1],validation[1][0]);
				}
				if (!ok){
					el.message = validation[2];
					break;
				}
			}	
			this.logger.log('\ttext:validation '+ el.id  + ' is '+ ok);
			return ok;
		} 		
		
		
		/** @id FormValidation.CheckElementSelect */
		function CheckElementSelect(el){
			var ok = true;
			var validation = [];
			for (var i=0;i<el.validationArray.length;i++){
				validation = el.validationArray[i];
				if ( validation[0] ){
					ok = (el.selectedIndex > 0) ? true : false;
				} else {
					ok = this.checkFunction(el,validation[1][1],validation[1][0]);
				}
				if (!ok){
					el.message = validation[2];
					break;
				}
			}	
			this.logger.log('\tselect:validation '+ el.id  + ' is '+ ok);
			return ok;
		}

		
		/** @id FormValidation.CheckElementCheckbox */
		function CheckElementCheckbox(el){
			var ok = true;
			var validation = [];
			for (var i=0;i<el.validationArray.length;i++){
				validation = el.validationArray[i];
				if ( validation[0] ){
					ok = (el.checked);
				} else {
					// function, return value , element id
					ok = this.checkFunction(el,validation[1][1],validation[1][0]);
				}
				if (!ok){
					el.message = validation[2];
					break;
				}
			}	
			this.logger.log('\tcheckbox:validation '+ el.id + ' is '+ ok);
			return ok;
		}	

		/** @id FormValidation.CheckElementRadio */
		function CheckElementRadio(el){
			var ok = true;
			var validation = [];
			for (var i=0;i<el.validationArray.length;i++){
				validation = el.validationArray[i];
				if ( validation[0] ){
					if (el.form[el.name] && el.form[el.name].length != 0){ok = false;}
					for (var ii=0;ii<el.form[el.name].length;ii++){
						if (el.form[el.name][ii].checked){
							ok = true;
							break;
						}
					}
					// ok = (el.checked);
				} else {
					// function, return value , element id
					ok = this.checkFunction(el,validation[1][1],validation[1][0]);
				}
				if (!ok){
					el.message = validation[2];
					break;
				}
			}	
			this.logger.log('\tradio:validation '+ el.id + ' is '+ ok);
			return ok;
		}	
				
		/** @id FormValidation.CheckElementBespoke */
		function CheckElementBespoke(el){
			var ok = true;
			var validation = [];
			for (var i=0;i<el.validationArray.length;i++){
				validation = el.validationArray[i];
				try {
					ok = this.checkFunction(el,validation[1][1],validation[1][0]);
					if (!ok){
						el.message = validation[2];
						break;
					}
				} catch(e) {
					ok = true;
					if (window.logger){logger.error(e,'FormValidation.CheckElementBespoke '+ el.id);}
				}
			}	
			this.logger.log('\tbespoke:validation '+ name + ' is '+ ok);
			return ok;
		}	
			
		/** @id FormValidation.CheckFunction */
		function CheckFunction(el,mthd,returnVal){
			var ok = true;
			if (mthd=='isValid'){return el.form.isValid;}
			try {
				if (typeof(mthd)== "string"){
					ok = eval('window.'+mthd)(el,returnVal);
				} else if (typeof(mthd)== "function"){
					ok = mthd(el,returnVal);
				}
			}catch(e){
				if (window.logger){logger.error(e,'FormValidation.CheckFunction '+ el.id);}
			}
			return ok;		
		}		
		
		/** @id FormValidation.CheckRegExp */
		function CheckRegExp(re,match,value){
			var ore = re;
			re = new RegExp(re);
			if ( re.test(value) != match ){
				return false ;
			}	
			return true;		
		}	
					
		/** @id FormValidation.Logger */		
		function Logger(){
			// methods
			this.log 			= Log;
			this.review 		= Review;
			this.reset 			= Reset;
			this.error			= _Error;
			// params
			this.history 		= new Array;
			this.debug			= window.location.href.match('localhost') ? true : false;
			
			function Log(m){
				if (window.logger) logger.log(m);
				if (this.debug) this.history.push(m);
			}
			function Review(){
				alert(this.history.join("\n"))
			}
			function Reset(){
				this.history = null;
				this.history = new Array;
			}
			function _Error(err,msg){
				if (window.logger) logger.error(err,msg);
			}
		}				
		
	}		
	
	if (!window.validation){
		validation = new Object;
	}	
	
	validation.formValidation 	= new FormValidation;	
	
	
	// shortcut overwrite this in flavour file
	validation.checkForm 		= function(form){
		if (user.jsSupportLevel<2){return true}
		if (!validation.formValidation.checkForm(form)){
			validation.formValidation.alertMessages(form);
			return false;
		} else {
			return true;
		}
	};
	if (!String.prototype.trim){
		String.prototype.trim 		= function(){return this.replace(/^\s+|\s+$/g, '')};
	}
	if (!String.prototype.normalize){
		String.prototype.normalize 	= function(){return this.replace(/\t/g,' ').replace(/\s+/g,' ').trim()};
	}

	//validation.checkElement 	= function(el){validation.formValidation.checkElement(el)}; 	// shortcut, expects element object ref	
	//validation.helpElement 		= function(el){validation.formValidation.helpElement(el)}; 	// shortcut, expects element object ref	
		
			
