var FormValidator = new Object();

/* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
STARTERS
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ */
//Run Check and if Pass, Submit
FormValidator.Run = function(frm){
	if(this.Check(frm)) frm.submit();
	else this.onRunFail();
}//func

FormValidator.onRunFail = function(){};

FormValidator.Check = function(frm){
	//'''''''''''''''''''''''''''''''''
	//Check if form exists
	frm = this.GetForm(frm);
	if(frm == null) return false;
	
	//'''''''''''''''''''''''''''''''''
	var isOk = true, rtn = true;
	var list = frm.getElementsByTagName("validator");
	
	for(var x=0; x < list.length; x++){
		// Is there check functions ----------------
		if(!list[x].getAttribute("check")) continue;
		
		// Prepare Validator -----------------------
		if(!this.CompileValidator(frm,list[x])) this.RunArgs(list[x]); //refresh arguments if already compiled;
		
		// Run Check functions on Element ----------
		isOk = this.ExecuteAll(list[x].checkCmd);
		
		// Run Results -----------------------------
		this.ExecuteEvents(isOk,list[x]);
		if(!isOk) rtn = false;
	}//for

	return rtn;
}//func


FormValidator.CheckElement = function(elm){
	var v = this.getValidator(elm.form,elm.name);
	if(v == null) return false;
	
	if(!this.CompileValidator(elm.form,v)) this.RunArgs(v);
	var isOk = this.ExecuteAll(v.checkCmd);
	this.ExecuteEvents(isOk,v);
	
	return isOk;
}//func


/* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
HELPER AND EXECUTE FUNCTIONS
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ */

//Run the events triggers depending on the results of the checks
FormValidator.ExecuteEvents = function(isOk,v){
	if(isOk){
		if(typeof v.onSuccessCmd == "object") this.Execute(v.onSuccessCmd);			
	}else{
		if(typeof v.onFailCmd == "object") this.Execute(v.onFailCmd);
	}//if
}//func


//Execute all the check commands
FormValidator.ExecuteAll = function(checkCmd){
	var rtn = true;
	for(var y=0; y < checkCmd.length; y++){
		if(this.Execute(checkCmd[y]) == false) rtn = false;
	}//for
	
	return rtn;
}//func


//Execute a Parsed Javascript Function
FormValidator.Execute = function(cmd){
	var func,rtn;
	func = window[cmd.Name];
	if(func != undefined) rtn = func.apply(this,cmd.Args);

	return rtn;
}//func


//Get the form object
FormValidator.GetForm = function(frmName){
	var frm = (typeof frmName == "object")? frmName:document.forms[frmName];
	if(frm == undefined && frm.tagName == "FORM"){
		alert('Form not found');
		return null;
	}//if
	
	return frm;
}//func


//Check if string starts with another string
FormValidator.StartsWith = function(chk,txt){
	return txt.toString().substr(0,chk.length) == chk;
}//func


//Get the element list through the validator tags
FormValidator.getElements = function(frm){
	var itm = new Array();
	var elmRef,elmName;
	var list = frm.getElementsByTagName("validator");
	
	for(var x=0; x < list.length; x++){
		if(!list[x].getAttribute("check")) continue;
		elmName = list[x].getAttribute("for");	
		elmRef = frm.elements[elmName];
		if(elmRef != null) itm.push(elmRef);
	}//for
	
	return itm;
}//func

//Get the validator of an element
FormValidator.getValidator = function(frm,n){
	var list = frm.getElementsByTagName("validator");	
	for(var x=0; x < list.length; x++){
		if(list[x].getAttribute("for") == n) return list[x];
	}//for

	return null;
}//func


/* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
PARSE AND COMPILE FUNCTIONS
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ */

//Parse Javascript Function Calls
FormValidator.Parse = function(pTxt,opt){
	var rtn = new Array();
	var reFunc = /(\w+)\(([^\(]*)\)/g; //Parse func(arg1,arg2,etc)
	var reArg = /'([^']+)'|"([^"]+)"|([^,]+)/g; //Parse 'test',"test",test,'a,b,c,d'
	var func = "";
	var args,tmp,x;
	
	while(func != null){
		//Parse String Looking for Function Calls =================
		func = reFunc.exec(pTxt);
					
		if(func != null){
			//Make Command Object
			var obj = {Name:func[1],Args:new Array(),OrigArgs:new Array()};
			
			//Check if there is any arguments ---------------------
			if(func[2] != ""){
				reArg.lastIndex = 0;
				args = "";
				while(args != null){
					args = reArg.exec(func[2]);
					
					//Find Data in SubGroups '''''''''''''''''
					if(args != null){
						tmp = "";
						for(x=1; x < args.length; x++){
							if(args[x] != "" && args[x] != undefined){ 
								tmp = args[x];
								break;
							}//if
						}//for
						
						//Do Object Parsing
						chk = this.ObjectParse(tmp,opt)

						if(chk != null) obj.Args.push(chk);
						else obj.Args.push(tmp);
						
						obj.OrigArgs.push(tmp);
					}//if ''''''''''''''''''''''''''''''''''''
					
				}//while
			}//if -------------------------------------------------
			
			rtn.push(obj);
		}//if =====================================================
	}//while
	
	return rtn;
}//func


//Compile all the information in validator tag for use.
FormValidator.CompileValidator = function(frm,v){
	var elmRef = v.elmRef;
	if(elmRef == null){
		var elmName = v.getAttribute("for");	
		elmRef = frm.elements[elmName];
			
		//Check if form element exists
		if(elmRef == undefined){
			alert("Unable to find form element. Check validator for = " + elmName);
			return;
		}//if	
		var opt = {element:elmRef,validator:v};

		v.elmRef = elmRef;
		v.checkCmd = this.Parse(v.getAttribute("check"),opt);
		if(v.getAttribute("onSuccess") != undefined)
			v.onSuccessCmd = this.Parse(v.getAttribute("onSuccess"),opt)[0];
		if(v.getAttribute("onFail") != undefined)
			v.onFailCmd = this.Parse(v.getAttribute("onFail"),opt)[0];
		
		return true;
	}//if
	
	return false;
}//func


//Quick Replace of Predefined Keywords into object references
FormValidator.ObjectParse = function(arg,opt){
	if( this.StartsWith("form.",arg) ){
		var ary = arg.split(".");
		var frm = opt.element.form;

		if(ary.length == 2) return frm.elements[ary[1]];
		else if(ary.length == 3) return frm.elements[ary[1]][ary[2]];
	}else if( this.StartsWith("input",arg) ){
		var ary = arg.split(".");

		if(ary.length > 1) return opt.element[ary[1]];	
		else if(ary[0] == "input") return opt.element;
	}else if(arg == "validator"){
		return opt.validator;
	}//if

	return null;
}//func


//Refresh dynamic argument values of cached commands
FormValidator.RunArgs = function(v){	
	var tmp = null;
	var opt = {element:v.elmRef,validator:v};
	
	for(var x = 0; x < v.checkCmd.length; x++){
		for(var y=0; y < v.checkCmd[x].OrigArgs.length; y++){
			tmp = this.ObjectParse(v.checkCmd[x].OrigArgs[y],opt);
			if(tmp != null) v.checkCmd[x].Args[y] = tmp;
		}//for
	}//for
}//func

/* @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
FORM MODIFICATION
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ */



//Apply some event handlers to form elements
FormValidator.ApplyEvents = function(frm,eObj,doAll){
	//-----------------------------------
	frm = this.GetForm(frm);
	var itm = (doAll)?  frm.elements : this.getElements(frm);

	//-----------------------------------
	for(var x=0; x < itm.length; x++){
		if(itm[x].tagName == null) continue;
		
		//Only allow to modify Form Elements
		switch(itm[x].tagName.toLowerCase()){
			case "input":
			case "select":
			case "textarea": 
				if(itm[x].name == "" && itm[x].type != "button") continue;
				break;
			default: continue; break; //skip to next element
		}//switch
		
		switch(itm[x].type){
			case undefined: case "hidden": case "button": 
				break;
			
			case "radio": case "checkbox":
				//itm[x].onclick = this.OnRadioChangeEvent;
				break;

			default:
				if(eObj.onChange) itm[x].onchange = eObj.onChange;
				break;
		}//switch				
	}//for
}//func +++++++++++++++++++++++++++++++++++++++++++++