function qFormValidator(id,messageErrorId){
	var _host=this;
	var _form=new qForm();
	void _form.setId(id);
	void _form.setMessageErrorId(messageErrorId);
	void _form.parse();
	this.validate=function(delay){return _form.validate();};
	this.reset=function(){void _form.reset();};
	this.initialize=function(){
		var form=_form.getFormElement();
		form.onsubmit=_host.validate;
		form.onreset=_host.reset;
	} ;
	this.addValidation=function(name,type,param,message,id,initialValue,complementary){
		void _form.getInput(name).addValidation(type,param,message,id,initialValue||null,complementary||{});
	};
}
function qForm(){
	var _host=this;
	var _id;
	var _form;
	var _inputs={};
	var _messageErrorId;
	this.setId=function(id){if( typeof id=='string')_id=id;};
	this.getId=function(id){return _id;};	
	this.setMessageErrorId=function(id){if(typeof id=='string')_messageErrorId=id;};
	this.getMessageErrorId=function(id){ return _messageErrorId;};
	this.getFormElement=function(){
		if(_form)return _form;
		return _form=pjd.getById(_id);
	} ;	
	this.setInput=function(input){
		var name=input.name;
		if(!_inputs[name])_inputs[name]=new qFormInput();
		_inputs[name].addElement(input);
	} ;
	this.getInput=function(name){return _inputs[name];};
	this.parse=function(){
		var form=_host.getFormElement();
		for(var i=0;i<form.elements.length;i++)_host.setInput(form.elements[i]);
	};
	this.reset=function(){
		for(var i in _inputs)_inputs[i].reset();
		if(_messageErrorId){
			void pjd.hide(pjd.getById(_messageErrorId));
		}
	};
	this.validate=function(){
		var canSubmit=true;
		for(var i in _inputs)if(!_inputs[i].validate(true))canSubmit=false;
		if(_messageErrorId){
			void pjd[canSubmit?'hide':'show'](pjd.getById(_messageErrorId));
		}
		for(var i in _inputs)if(!_inputs[i].validate())canSubmit=false;
		return canSubmit;
	};
}
function qFormInput(){
	var _host=this;
	var _type=null;
	var _name;
	var _elements=[];
	var _validations={};
	var _initialValue=null;
	var _active=null;
	var _errorButton;
	var _errorLayer;
	this.getValue=function(){
		if(_type=='radio'&&_elements.length>1){
			for(var i=0;i<_elements.length;i++){
				var input=_elements[i];
				if(input.checked){
					return input.value;
					break;
				}
			}
			return '';
		}
		if(_type=='checkbox'){
			if(_elements.length>1){
				var values=[];
				for(var i=0;i<_elements.length;i++){
					var input=_elements[i];
					if(input.checked)void values.push(input.value);
				}
				return values.join(',');
			}else{
				var input=_elements[0];
				if(input.checked)return input.value;
				return '';
			}
		}
		return _elements[0].value;
	};
	this.setValue=function(reset,value){
		var reset=pjd.isBoolean(reset)?reset:false;
		for( var i=0;i<_elements.length;i++){
			var input=_elements[i];
			if( _type=='radio')input.checked=false;
			if( _type=='text')input.value=reset?"":value;
			if( _type=='password')input.value=reset?"":value;
		}
	};
	this.reset=function(resetValue){
		var resetValue=pjd.isBoolean(resetValue)?resetValue:true;
		if(_active!=null){
			void _host.manageDisplay(false,_active);
			_active=null;
		}
		if(_type=='password')void _host.displayPasswordStrength(null,true);
		if(resetValue)void _host.setValue(true);
	};
	this.validate=function(validateOnly){
		var validateOnly=pjd.isBoolean(validateOnly)?validateOnly:false;
		void _host.reset(false);
		var value=_host.getValue();
		if(_initialValue!=null&&value==_initialValue){
			_host.setValue(true);
			value="";
		}
		for(var i in _validations){
			var v=_validations[i];
			if(i=='empty'&& pjd.isEmpty(value)){_active=i;break;}
			if(i=='email'&&value.match(/^([\w-]+)(\.[\w-]+)*@([a-z\d-]+)(\.[a-z\d-]+)*(\.[a-z]{2,4})$/gi)==null){_active=i;break;}
			if(i=='whiteSpace'&&value.match(/\s+/gi)!=null){_active=i;break;}
			if(i=='length'&&value.length<v.param){_active=i;break;}
		}
		if(_active!=null){
			if(!validateOnly)void _host.manageDisplay(true,_active);
			return false;
		}
		return true;
	};
	this.manageDisplay=function(display,type){
		if(!_errorButton){
			_errorButton=pjd.node.inject('div');
			_errorLayer=pjd.node.inject('div');
			void pjd.addClassName(_errorButton,'form-error-button');
			void pjd.addClassName(_errorLayer,'form-error-layer');
		}
		var anchor=pjd.getById(_validations[type].anchorId);
		if(display){
			void pjd.show(_errorButton);
			void pjd.show(_errorLayer);
			void pjd.setHtml(_errorLayer,_validations[type].message);
			if(_errorLayer.offsetWidth>220)_errorLayer.style.width='220px';
			void pjd.addClassName(anchor,'form-error');
			var pos=pjd.getOffset(anchor);
			var x=pos.x+anchor.offsetWidth+2;
			var y=pos.y;
			if(_validations[type].complementary.x)x+=_validations[type].complementary.x;
			if(_validations[type].complementary.y)y+=_validations[type].complementary.y;
			void pjd.setPosition(_errorButton,x,y);
			var layer_y=y-_errorLayer.offsetHeight-1;
			if(layer_y<0)layer_y=y+_errorButton.offsetHeight+1;
			void pjd.setPosition(_errorLayer,x+8,layer_y);
			void pjd.hide(_errorButton);
			void pjd.hide(_errorLayer);
			void pjd.setZIndex(_errorLayer,999999);
		}
		void pjd[display?'addClassName':'removeClassName'](anchor,'form-error');
		void pjd[display?'show':'hide'](_errorButton);
		void pjd.events[(display?'add':'remove')+'Listener'](_errorButton,'mouseover',_host,_host.displayMessage,{display:true});
		void pjd.events[(display?'add':'remove')+'Listener'](_errorButton,'mouseout',_host,_host.displayMessage,{display:false});
	};
	this.displayMessage=function(event){void pjd[event.args.display?'show':'hide'](_errorLayer);};
	this.addElement=function(input){
		var type=input.type.toLowerCase();
		if(_type==null){_type=type;}
		else{
			if(_type!=type) return false;
			// Error : Elements that have the same name must be the same input type
		}
		_name=input.name;
		void _elements.push(input);
	};
	this.addValidation=function(type,param,message,id,initialValue,complementary){
		if(pjd.isString(initialValue)){
			_initialValue=initialValue;
			if(_type=='text'||_type=='password'){
				void pjd.events.addListener(_elements[0],'focus',null,function(event){
					if(_host.getValue()==_initialValue)void _host.setValue(true);
				});
				void pjd.events.addListener(_elements[0],'blur',null,function(event){
					if(pjd.isEmpty(_host.getValue()))void _host.setValue(false,_initialValue);
				});
			}
			if(complementary.dynamic){
				void pjd.events.addListener(_elements[0],'keyup',null,function(event){
					_host.validate(true);
				});				
			}
		}
		_validations[type]={type:type,param:param,message:message,anchorId:id,complementary:complementary};
		if(_type=='password'&&type=='strength'){
			void pjd.events.addListener(_elements[0],'keyup',_host,_host.displayPasswordStrength);
		}
	};
	this.displayPasswordStrength=function(event,reset){
		if(!_validations['length'])return;
		if(!_validations['strength'])return;
		var minimumLength=_validations['length'].param;
		var reset=reset||false;
		if(!minimumLength)return;
		var value=reset?'':_host.getValue();
		var score=0;
		if(value.length>=minimumLength){
			if(value.length>=minimumLength+5)score++;
			if(value.match(/[a-zA-Z]+/)!=null)score++;
			if(value.match(/\d+/)!=null)score++;
			if(value.match(/[\!\-\_\.\$\@\#\%\&\*\+\=]+/)!=null)score++;
		}
		var _scoreLabel={
			fr:['Faible','Moyen','Bon','Fort','Excellent'],
			en:['Weak','Medium','Good','Strong','Excellent']
		};		
		var module=pjd.getById(_validations['strength'].anchorId);
		var label=pjd.getByClassName('strength-label-display');
		var lang=_userSelectedLanguage;
		void pjd.setHtml(label,(lang=='fr'?'Force:':'Strength:')+_scoreLabel[lang][score]);
		void pjd.setClassName(pjd.getByClassName('password-strength-\\d'),'password-strength-'+score);
	};
}
