/* to add validation to an item, see documentation for usage.
* if error occures see cError of error log. this is an array
* documentation not. Params are displayed as
* @param :: NAME - type expected :: [Default Value if not set] :: explanation
* 		double indented items after a param are child params or accepted values
*/

/** Class window.validateObject
* @purpose :: takes form element registration and establishes actions based on definition
* @author :: Scott McDonald
* @version :: 2.1
* @revision :: Thursday, October 16, 2008 - added delied registration to allow elements
*		to load - this is used for DOM level creation of elements. To use this, set this.waitForInit=true
*		then call this.initList() after DOM created elements have completely loaded to page
*
* /// Properties
*
* /// Methods
* @Method :: setRequired
* @purpose sets/unsets required for a given item
* @param :: bRequired as boolen [true]
* @param :: nIndex as int [all items] valid 0 based index (check item.index)
* @param :: args as Object [null] used for future features
* @return void
*/

window.validationObject = function(){
	var target = this;
	this.typename = "inc.js.objects.validationObject";
	this.items = new Array();
	this.form = undefined;
	this.cError = new Array();
	this.addToValidate = function(){return("");}
	this.submitButton = undefined;
	this.waitForInit = false; // if true, then register will not occure until initList is called

	AddListener(window,"load",function(){target.init();});



	this.setRequired = function(bRequired, nIndex, args){
		bRequired = (bRequired!=false)
		if(nIndex=="all"){nIndex=undefined;}
		startat = (nIndex==undefined)?0:nIndex;
		stopat = (nIndex==undefined)?this.items.length:nIndex+1;
		for(startat;startat<stopat;startat++){
			try{
				this.items[startat].required = bRequired;
				this.markLabel(this.items[startat].element.id, bRequired);
			} catch(e){
				Catch(this.typename + ".setRequired",e);
			}
		}
	}

	/** performs validation on a specific item
	* @param :: me as object pointer
	*/
		this.validateMe = function(me, o){
			var _return = {valid:true,error:""}
			var target = this;
			if(!o){o = this.getInfoForObject(me.id);}
			if(!o){return({valid:false,error:"\t- Cannot find element.\n"});}

			try {
				/* check for required and empty */
				if(o.required && me.value==""){
					_return.valid = false;
					_return.error = "\t- " + this.getItemFromLabel(o) +  " is Empty.\n"
					return(_return);
				} else if(!o.required && me.value==""){
					return({valid:true,error:""});
				}
			} catch(e){
				Catch(this.typename + ".this.validateMe",e)
			}
			switch(o.type.toLowerCase()){
				case("string"):{break;}
				case("zip"):{
					if(!isZip(me.value)){return({valid:false,error:"\t- " + this.getItemFromLabel(o) +  " is Invalid.\n"});}
					break;
				}
				case("phone"):{
					var isValid = validPhone(me.value);
					me.value = isValid.value;
					if(!isValid.valid){return({valid:false,error:"\t- " + this.getItemFromLabel(o) +  " is Invalid. [" + isValid.error + "]\n"});}
					break;
				}
				case("email"):{
					var isValid = evalEmail(me.value);
					me.value = isValid.value;
					if(!isValid.valid){return({valid:false,error:"\t- " + this.getItemFromLabel(o) +  " is Invalid. [" + isValid.error + "]\n"});}
					break;
				}
				case("select"):{
					if(me.value==".none"){return({valid:false,error:"\t- " + this.getItemFromLabel(o) +  " Has No Option Selected.\n"});}
					break;
				}
				case("numeric"):{
					me.value = numOnly(me.value);
					if(me.value==""){
						return({valid:false,error:"\t- " + this.getItemFromLabel(o) +  " is Empty.\n"});
					}
					break;
				}
				case("CheckBox" || "Radio"):{
					return({valid:true,error:""});
					break;
				}
			}
			return({valid:true,error:""});
		}
	/** performs validation on all items in form
	*/
		this.validateForm = function(displayAlert,args){
			displayAlert = (displayAlert!=false);
			var r = "";
			var i = 0;
			var l = this.items.length;
			var me
			var v;
			for(i;i<l;i++){
				me = this.items[i];
				v = this.validateMe(me.element,me)
				if(!v.valid){
					markit(me.element,true);
					me.element.title = v.error
					r += v.error;
				} else {
					me.element.title = "";
					markit(me,false);
				}
			}

			r += this.addToValidate();

			if(r != ""){
				if(!displayAlert){
					return(r);
				} else {
					alert("The form cannot be submitted; please correct the following and resubmit:\n\n" + r);
					return(false);
				}
			} else {
				if(!displayAlert){
					return("");
				} else {
					return(true);
				}
			}
		}

	/** @method :: register
	* @purpose adds an item to the validation object
	* @param id :: as String :: [exception] :: name/id as string of item to add to validation
	* @param type :: as String :: [string] :: type method to perform on item for validation
	* 	@type :: String - Performs simple "HAS_VALUE" check
	* 	@type :: Phone - Performs check on valid phone number
	*		@type :: Zip - Performs US Zipcode check
	*		@type :: Email - Performs Email Check
	*		@type :: Select - defines a select-list (combo box)
	*		@type :: CheckBox - defines a Checkbox (Note: will only fire callback on blur after change)
	*		@type :: Radio - defines a Radio List
	*		@type :: Numeric - string check that only numbers exist
	* @param required :: as Boolean :: [true] :: some fields are validated IF they have a value, otherwise should be left alone.
	*		(example, fax number should resolve to a phone number if it's populated, but if it's empty then the form
	* 	should still be able to be submitted) Setting this to false, will allow you to define those fields.
	* @param args :: as Object :: [null] :: allows for options
	* 	@arg :: onsuccess :: as function :: [null] :: called if validate is successfull
	* 	@arg :: onfailed :: as function :: [null] :: called if validate failes
	* 	@arg :: callback :: as function :: [null] :: called regardless of validation
	*	@return :: Boolean - True if successfully registered, False if not. If not, check the cError property for info
	*/
	this.register = function(id, type, required, args){
		var newindex;
		var thisItem;

		if(typeof(id)=="object"){
			thisItem = id;
			newindex = thisItem.index;
			id = thisItem.id;
			type = thisItem.type;
			required = thisItem.required;
			args = thisItem.args;
		} else {
			newindex = this.items.length;
			thisItem = {
				typename:"window.validationObject.item",
				id:id,
				type:type,
				required:required,
				index:newindex,
				args:args
			}
			this.items[newindex] = thisItem;
			if(this.waitForInit){
				return(this.items[newindex]);
			}
		}

		var target = this;
		if(id==undefined){
			this.addError("Form Element ID required to register element");
			return(false);
		}
		if(type==undefined){type = "string";}
		if(required == undefined){required = true;}

		var o = getElem(id);

		if(o){
			var label  = this.markLabel(id, required)

				var arr;
				try {
					var theaction;
					if(o.type=="radio"){
						theaction = "mouseup"
						o = o.form[o.id]
						var i = 0;
						var l = o.length;
						var elem;
						for(i;i<l;i++){
							elem = o[i];
							this.addTheListener(elem,theaction,args);
						}
					} else {
						if(o.type=="hidden"){
							theaction = "change";
						} else {
							theaction = "blur";
						}
						this.addTheListener(o,theaction,args);
					}
				} catch(e){
					Catch(this.typename + ".register(187)",e);
				}


			thisItem.parent = this;
			thisItem.id = id;
			thisItem.type = type;
			thisItem.required = required;
			thisItem.element = o;
			thisItem.label = label;
			thisItem.setRequired = function(bool){this.parent.setRequired(bool,this.index);}

			this.items[newindex] = thisItem;
			return(this.items[newindex]);
		} else {
			this.addError("Could not find form item object - be sure you do not register it until AFTER it is defined in the HTML");
			return(false);
		}
	}

	this.markLabel = function(id, required){
		try {
			/* alter item label to add required marks and remove breakable spacing */
			var label = document.getElementById(id + "_label");
			if(label && required){
				if(label.innerHTML.indexOf("*")==-1){
					/* add astick to label */ var temp = "* " + label.innerHTML;
					/* replace spaces with &nbsp; */ temp = temp.replace(/ /gi, "&nbsp;");
					/* reset label */ label.innerHTML = temp;
				}
			} else if(label){
				var temp = label.innerHTML;
				temp = temp.replace(/\*\&nbsp;/,"");
				label.innerHTML = temp;
			} else {
				alert("LABEL: \"" + id + "_label\" not found. Resolve this issue before going live or validator will not function properly.");
			}
			return(label);
		} catch(e){
			Catch(this.typename + ".markLabel" + e.message);
		}
	}

	this.addTheListener = function(o, theaction, args){
		var target = this;
		AddListener(o,theaction,function(){
				/* validate form element content
				*/ var valid = target.validateMe(o);
				/* mark or unmark visual element
				*/ markit(o,valid.valid==false);
				if(args){
					/* if the validate is true look for onsuccess callback
					*/ if(valid.valid){if(args.onsuccess){args.onsuccess(o);};
					/* if the validate is false look for onfailed callback
					*/ } else if(!valid.valid){if(args.onfailed){args.onfailed(o);};}
					/* no matter how the validation goes, look for the callback callback
					*/ if(args.callback){args.callback(o);};
				}
				/* always return false
				*/ return(false);
			});
	}

	this.getItemFromLabel = function(o){return(o.label.innerHTML.replace(/\*/gi,"").replace(/:/gi,"").replace(/&nbsp;/gi," ").replace(/ /gi,""));}
	this.getInfoForObject = function(name){
		var i = 0;
		var l = this.items.length;
		for(i;i<l;i++){
			if(this.items[i].id==name){
				return(this.items[i]);
			}
		}
	}
	this.addError = function(text){
		this.cError[this.cError.length]=text;
	}

	this.registerSubmit = function(){
		var target = this;
		if(this.submitButton && this.form){
			this.submitButton.onclick = function(){
				target.onsubmit(target);
			}
		}
	}


	this.init = function(){
		if(this.form !=undefined){
			if(typeof(this.form)=="string"){
				this.form = getElem(this.form);
			}
		}
		if(this.submitButton!=undefined){
			if(!this.submitButton.type && typeof(this.submitButton)=="string"){
				this.submitButton = getElem(this.submitButton);
			}
		}
		if(this.form && this.onsubmit){
			this.registerSubmit();
		}
	}


	this.initList = function(){
		var i = 0;
		var l = this.items.length;
		for(i;i<l;i++){
			this.register(this.items[i]);
		}
	}
}

