/* 
 * THIS IS CODE REQUIRED BY STRUTS VALIDATION!!! 
 *	
 * DON'T MESS WITH UNLESS YOU KNOW WHAT YOU'RE DOING
*/

function Validator(){
	if(typeof(this.isInitialized)== 'undefined'){
		this.errors= [];
		this.changedFields= [];
		
		this.LC_ALPHA_CHARS= "abcdefghijklmnopqrstuvwxyz";
		this.UC_ALPHA_CHARS= this.LC_ALPHA_CHARS.toUpperCase();
		this.ALPHA_CHARS= this.UC_ALPHA_CHARS+ this.LC_ALPHA_CHARS;
		this.NUM_CHARS= "1234567890";
		this.ALPHANUM_CHARS= this.ALPHA_CHARS+ this.NUM_CHARS;

		this.CARD_TYPE_DEMO= "Demo"
		this.CARD_TYPE_AMEX = "AMEX"; 
		this.CARD_TYPE_VISA = "Visa";
		this.CARD_TYPE_DISCOVER = "Discover";
		this.CARD_TYPE_MASTERCARD = "MasterCard";
		this.DEMO_CARD_NUMBER= '1111222233334444'
	

	// MASK/ MATCH PATTERN
		Validator.prototype.matchPattern= function(value, mask) {
			if((value+'').length== 0)
				return true;
			else
				return mask.exec(value);
		}


	// REQUIRED IF
		Validator.prototype.jsEval= function(value, test) {
		  try{
			 if(eval(test) && ((value+'').length== 0)){
			 	return false;
			 } else{
			 	return true;
			 }
		  } catch(e){
		  	alert('Error attempting to eval: '+ test+ '\n'+ e)
			 return false;
		  }
		}
		
		
	// MATCH FIELDS
		Validator.prototype.fieldsMatch= function(value, field) {
		  try{
			 return(value== field.value);
		  } catch(e){
			 return false;
		  }
		}

	// PHONE NUMBER
 		Validator.prototype.isPhoneNumber= function(p){
 			var stripped= p.replace(/ /g,'').replace(/\(/g,'').replace(/\)/g,'').replace(/\-/g,'').replace(/\./g,'')

 			if(isNaN(parseInt(stripped))) {return false;} 
 			return((parseInt(stripped)+'').length>= 10);
 		}


	// MAX/MIN/RANGE -- STRING LENGTH
		Validator.prototype.isLengthAtLeast= function(v, min) {return this.isLengthInRange(v, min, null)}
		Validator.prototype.isLengthAtMost= function(v, max) {return this.isLengthInRange(v, null, max)}

		Validator.prototype.isLengthInRange= function(v, min, max) {
			var testPassed=true
			var length=(""+v).length
			if (max==null) {testPassed=(length>=min)}
			else if (min==null) {testPassed=(length<=max)}
			else {testPassed=(!(length>max || length<min))}
			
			return testPassed;
		}
		
		
	// CREDIT CARD VALIDATOIN
		Validator.prototype.isValidCreditCard= function(cardNumber){
				cardNumber= cardNumber.replace(/ /g,"").replace(/-/g,"");
				return(this.luhnCheck(cardNumber));
		}
		
		Validator.prototype.isValidCreditCardType= function(cardNumber){
			var idf= cardNumber.substring(0,4);
			if(cardNumber.length== 15){
				//AMEX
				if((idf< 3800) && (idf>3699))
					return true;
			}
			if(cardNumber.length== 16){
				//VISA
				if((idf< 5000) && (idf>3999))
					return true;
				//MASTERCARD
				if((idf< 6000) && (idf>5099))
					return true;
			}
			if(cardNumber.length== 13){
				//VISA
				if((idf< 5000) && (idf>3999))
					return true;			
			}
			if(cardNumber== this.DEMO_CARD_NUMBER){
				return true;
			}
			return false;
		}

		Validator.prototype.getCreditCardType= function(cardNumber){
			var cardType= "";
			
			if(this.isValidCreditCard(cardNumber)){
				var idf= cardNumber.substring(0,4);

				if(cardNumber.length== 15){
					//AMEX
					if(((idf< 3800) && (idf>3699)) || (idf< 3500) && (idf>3399))
						cardType= this.CARD_TYPE_AMEX;
				}
				if(cardNumber.length== 16){
					//VISA
					if((idf< 5000) && (idf>3999))
						cardType=  this.CARD_TYPE_VISA;
					//MASTERCARD
					if((idf< 6000) && (idf>5099))
						cardType= this.CARD_TYPE_MASTERCARD;
				}
				if(cardNumber.length== 13){
					//VISA
					if((idf< 5000) && (idf>3999))
						cardType= this.CARD_TYPE_VISA;	
				}
				if(cardNumber== this.DEMO_CARD_NUMBER){
					return this.CARD_TYPE_DEMO;
				}
			}
			return cardType;
		}


		Validator.prototype.luhnCheck= function(cardNumber){
			 if (this.isLuhnNum(cardNumber)) {
				  var no_digit = cardNumber.length;
				  var oddoeven = no_digit & 1;
				  var sum = 0;
				  for (var count = 0; count < no_digit; count++) {
						var digit = parseInt(cardNumber.charAt(count));
						if (!((count & 1) ^ oddoeven)) {
							 digit *= 2;
							 if (digit > 9) digit -= 9;
						};
						sum += digit;
				  };
				  if (sum == 0) return false;
				  if (sum % 10 == 0) return true;
			 };
			 return false;
		}
		
		Validator.prototype.isLuhnNum= function(argvalue) {
			 argvalue = argvalue.toString();
			 if (argvalue.length == 0) { return false; }
			 for (var n = 0; n < argvalue.length; n++) {
				  if ((argvalue.substring(n, n+1) < "0") ||
						(argvalue.substring(n,n+1) > "9")) {
						return false;
				  }
			 }
			 return true;
		}		


// DATE VALIDATION ***************************************************

	// VALID DATE
		// Takes date in format MM/DD/YYYY or MM-DD-YYYY
		// returns false if not a valid date.
		// add to as necessary
		Validator.prototype.isValidDate= function(dateString) {
		  try{
			 var date=new Date(Date.parse(dateString));
			 if(isNaN(date)) return false;

			 var dateArr= (dateString.indexOf("-")!=-1) ? dateString.split("-") : dateString.split("/");
			 if(dateArr.length!= 3) return false;    
			 if(dateArr[2].trim().length!=4) return false;

			 var dateString1=(date.getMonth()+1)+"/"+(date.getDate())+"/"+(date.getFullYear());
			 var dateString2=(Math.abs(dateArr[0]))+"/"+(Math.abs(dateArr[1]))+"/"+(Math.abs(dateArr[2]));
			 if(dateString1 != dateString2) return false;

			 return dateString;
		  } catch(e){
			 return false;
		  }
		}
			
	// FUTURE DATE
		Validator.prototype.isFutureDate= function(dateString){
			var date= this.isValidDate(dateString);
			if(!date) return false;
			else{
				var date1= new Date();
				var date2= new Date(dateString);
				if(date1 < date2)
					return true;
				else
					return false;
			}
		}

	// DATE AFTER
		Validator.prototype.isDate1AfterDate2= function(date1, date2){
			var date1= this.isValidDate(date1);
			var date2= this.isValidDate(date2);
			
			if(!date1) return true;
			
			else{
				var date1= new Date(date1);
				var date2= new Date(date2);
				
				if(date1 > date2)
					return true;
				else
					return false;
			}
		}

// MATH/ NUMBER VALIDATION ***************************************************


	// VALID NUMBER
		Validator.prototype.isNumber= function(v) {
			var testPassed=true
			v=""+v
			var charsOk=v.containsOnly(this.NUM_CHARS+"-.")
			if (!charsOk) {testPassed=false}
			if (testPassed && v.indexOf("-")>0) {testPassed=false}
			return testPassed;
		}

	// NUMBERS ONLY
		Validator.prototype.containsNumbersOnly= function(v) {
			var testPassed=true
			v=""+v
			var charsOk=v.containsOnly(this.NUM_CHARS)
			if (!charsOk) {testPassed=false}
			if (testPassed && v.indexOf("-")>0) {testPassed=false}
			return testPassed;
		}
		
	// MAX/MIN/RANGE -- INT VALUE
		Validator.prototype.isAtLeast= function(v, min) {return this.isInRange(v, min, null)}
		Validator.prototype.isAtMost= function(v, max) {return this.isInRange(v, null, max)}
		
		Validator.prototype.isInRange= function(v, min, max) {
			var testPassed=true
			if (max==null) {testPassed=(v>=min)}
			else if (min==null) {testPassed=(v<=max)}
			else {testPassed=(!(v>max || v<min))}
			return testPassed;
		}

	// INTEGER
		Validator.prototype.isInteger= function(v){
			if(!this.isNumber(v)){
				return false;
			} else {
				var iValue = parseInt(v);
				
				if (isNaN(iValue) ||  !(iValue >= -2147483648 && iValue <= 2147483647) || ((iValue+'')!= v)) {
					return false;
				}
			}
			return true;
		}

	// BYTE
		Validator.prototype.isByte= function(v){
			if(!this.isNumber(v)){
				return false;
			} else {	
				var iValue = parseInt(v);
				if (isNaN(iValue) || !(iValue >= -128 && iValue <= 127)) {
					return false;
				}
			}
			return true;
		}
		
	// FLOAT
		Validator.prototype.isFloat= function(v){			
			if(!this.isNumber(v)){
				return false;
			} else {
			 	var iValue = parseFloat(v);
				if (isNaN(iValue)) {
					return false;
				}
			}
			return(true);
		}
	
	// LONG
		Validator.prototype.isLong= function(v){
			if(!this.isNumber(v)){
				return false;
			} else {
				var iValue = parseInt(v);
				
				if (isNaN(iValue) ||  !(iValue >= -9223372036854775808 && iValue <= 9223372036854775808) || ((iValue+'')!= v)) {
					return false;
				}
			}
			return true;
		}


	// VALID EMAIL
		Validator.prototype.isValidEmail= function(emailStr) {
			if (emailStr.length == 0) {
				 return false;
			}
			var emailPat=/^(.+)@(.+)$/;
			var specialChars="\\(\\)<>@,;:\\\\\\\"\\.\\[\\]";
			var validChars="\[^\\s" + specialChars + "\]";
			var quotedUser="(\"[^\"]*\")";
			var ipDomainPat=/^(\d{1,3})[.](\d{1,3})[.](\d{1,3})[.](\d{1,3})$/;
			var atom=validChars + '+';
			var word="(" + atom + "|" + quotedUser + ")";
			var userPat=new RegExp("^" + word + "(\\." + word + ")*$");
			var domainPat=new RegExp("^" + atom + "(\\." + atom + ")*$");
			var matchArray=emailStr.match(emailPat);
			if (matchArray == null) {
				 return false;
			}
			var user=matchArray[1];
			var domain=matchArray[2];
			if (user.match(userPat) == null) {
				 return false;
			}
			var IPArray = domain.match(ipDomainPat);
			if (IPArray != null) {
				 for (var i = 1; i <= 4; i++) {
					 if (IPArray[i] > 255) {
						 return false;
					 }
				 }
				 return true;
			}
			var domainArray=domain.match(domainPat);
			if (domainArray == null) {
				 return false;
			}
			var atomPat=new RegExp(atom,"g");
			var domArr=domain.match(atomPat);
			var len=domArr.length;
			if ((domArr[domArr.length-1].length < 2) ||
				 (domArr[domArr.length-1].length > 3)) {
				 return false;
			}
			if (len < 2) {
				 return false;
			}
			return true;
		}

	// BULK EMAIL
		Validator.prototype.isValidBulkEmail= function(s){
			if(s== ''){
				return true;
				
			}
			s= s.replace(/ /g,'');
			s= s.replace(/\n/g,'');
			s= s.replace(/\t/g,'');
			s= s.replace(/\r/g,'');
			s= s.replace(/\f/g,'');
			
			var emailArray= s.split(',');
			
			if(emailArray.length< 1){
				return false;
			} else {
				for(var i= 0; i< emailArray.length; i++){
					if(!this.isValidEmail(emailArray[i])){
						alert("_"+emailArray[i]+"_")
						return false;
					}
				}
			}
			return true;
		}


 // INTERNAL UTILITY FUNCTIONS *************************************
 		Validator.prototype.getValidationObject= function(formObject, functionName){
 			var formName= formObject.name;
 			
 			//Sometimes, a form has a child with the name equal to a
 			//a js form property, so form.name, form.submit, form.action can
 			//cause problems, this next part should eliminate this issue.
 			if((typeof(formName)!= 'string') && (typeof(formName)== 'object')){
 				formName= getFormPropertyValue(formObject, 'name');
 			}
 			
 			return(eval('new '+ formName+ '_'+ functionName+ '()'));
 		}
 
 	//  Returns Field Value as Array(). Normally, this will mean
 	//	an array of length 1.
		Validator.prototype.getFieldValueArray= function(form, field) {

			if(typeof(field!= 'undefined') && (field.type || field.length && field[0].type)){				
				var valueArray= [];
				if (field.type=="text" || field.type=="password" || field.type=="hidden" || field.type=="textarea" || field.type=="file" ) {
					valueArray= [field.value];
				} 
				else if (field.type && field.type.indexOf("select")>-1) {
					// a select menu; which kind? --
					if (field.type.indexOf("multi")>-1) {
						// a multi-select menu with zero, one, or multiple options selected:
						var ops=field.options;
						for (var i=0; i<ops.length; i++) {
							var op=ops[i];

							if (op.selected) {
								valueArray[valueArray.length]= op.value;
							}
						}
					} else {
						// a single-select menu with exactly one option selected:
						valueArray= [field.options[field.selectedIndex].value];
					}
					if(valueArray.length ==0){
						valueArray[0]= '';
					}
				} else if(field.length && field[0].type && field[0].type== 'radio'){
					//radio
					valueArray= [''];
					for (var i= 0; i< field.length; i++) {
						if(field[i].checked) {
							valueArray= [field[i].value];
						}
					}
				} else{
					// checkbox group (or it doesn't exist):
					var els= form.elements;
					for (var i=0; i< els.length; i++) {
						var el= els[i]
						if (el.type=="radio" || el.type=="checkbox") {
							if (el.name== field.name) {
								if (field.checked) {
									valueArray[valueArray.length]= field.value;
								} else{
									valueArray[valueArray.length]= '';
								}
							}
						}
					}
				}
				
				return valueArray;
			} else if(!field.type){
				alert("Validation Error: Object is not a form field");
			} else {
				alert("Validation Error: A form element with name '"+elName+"' was not found.");
			}
		}

	// call by setting onchange="validator.setFormChanged(this);" on any input
		Validator.prototype.setFormChanged= function(fieldName){
			this.changedFields[this.changedFields.length]= fieldName;
		}
		
	// returns changed input values
		Validator.prototype.getFormChanged= function(){
			return(this.changedFields.length> 0);
		}

	// call onSubmit if you want to prevent leaving with changes unsaved.
		Validator.prototype.checkChangedFields= function(){
			if(this.getFormChanged()){
				var s='You have made changes to the following fields:\n';
				for(var i= 0; i< this.changedFields.length; i++){
					s+= this.changedFields[i]+'\n'
				}
				s+= 'Are you sure you want to leave without saving?'
				return(confirm(s));
			}
			return true;
		}

// ERRORS ************************************************************

		Validator.prototype.addError= function(error){
			if(error.constructor && error.constructor== Array){
				this.errors[this.errors.length]= error;
			}
		}
		
		Validator.prototype.clearErrors= function(){
			/*
			for(var i= 0; i< this.errors.length; i++){
				var eNode= this.errors[i][2];
				eNode.parentNode.removeChild(eNode);
			}
			*/			
			for(var i= 0; i< this.errors.length; i++){
			   var labelId= (this.errors[i][0].name+ '_l');
			   var labelContainer= document.getElementById(labelId);
			   labelContainer.style.color= "#000";
			}
			this.errors= [];
		}
		
		Validator.prototype.addErrorEvents= function(target){
			var ref= e;
			var idRef= target.id;
		
			if(document.addEventListener){
				target.addEventListener(
					'mouseover'
					,function(event) { ref.showErrorWindow(event, idRef, true) }
					,false
				);
				target.addEventListener(
					'mouseout'
					,function(event) { ref.hideErrorWindow() }
					,false
				);
			} else{
				target.attachEvent(
					'onmouseover',
				 	function(event) {ref.showErrorWindow(event, idRef)}
				);
				target.attachEvent(
					'onmouseout',
				 	function(event) {ref.hideErrorWindow()}
				);
			}
		}
		
		Validator.prototype.showErrors= function(){
			for(var i= 0; i< this.errors.length; i++){
			   var labelId= (this.errors[i][0].name+ '_l');
			   var labelContainer= document.getElementById(labelId)
			   try{
				   labelContainer.style.color= "#ff0000";				   
				   this.addErrorEvents(labelContainer);
				} catch(e){
					alert('the error label container with id: '+this.errors[i][0].name+ '_l does not exist');
				}
			}
			/*
			// asterisk code
			for(var i= 0; i< this.errors.length; i++){
				var input= this.errors[i][0];
				
				var eNode= document.createElement('SPAN');
				var eNodeId= (input.name+'___e');
					 eNode.setAttribute("id", eNodeId);
			
				input.parentNode.insertBefore(eNode, input);
				eNode.innerHTML='<sup><font color="red">*</font></sup>';
				
				this.errors[i][2]= eNode;
			}
			*/
			return(false);
		}
		
		Validator.prototype.alertErrors= function(){
			if(this.errors.length> 0){
			this.showErrors();
			//alerting disabled, showing enabled
			/*
				var s= '';

				for(var i= 0; i< this.errors.length; i++){
					s+= this.errors[i][1]+'\n';
				}
				alert(s);
			*/
				if(this.errors[0][0]!= null && this.errors[0][0].type!= "hidden" && this.errors[0][0].focus){
					this.errors[0][0].focus();
				}
				return false;
			}
		}


// BUTTON DISABLING **************************************************		
		Validator.prototype.disableButton= function(target){
			this.setDisabledButton(target);
			target.className= target.className+'_d';
		}

		Validator.prototype.enableButton= function(){
			if(this.getDisabledButton()){
				var button= this.getDisabledButton();
				button.className= button.className.substring(0, (button.className.length-2))
				this.setDisabledButton(false);
			}
		}
		
		Validator.prototype.setDisabledButton= function(disabledButton){
			this.disabledButton= disabledButton;
		}
		
		Validator.prototype.getDisabledButton= function(){
			return(typeof(this.disabledButton)== 'undefined' ? false : this.disabledButton);
		}				
		
		this.isInitialized= true;
	}



// ERROR DISPLAY **************************************************
	Validator.prototype.getErrorWindow= function(){
		if (typeof(this.errorWindow)== 'undefined'){
			var ew= document.createElement('div');
			var body= document.getElementsByTagName("body").item(0);
			
			body.appendChild(ew);
			this.errorWindow= ew;
		}

		return this.errorWindow;
	}
	
} validator= new Validator();



/* *** EXTERNAL VALIDATION CALLS ************************/

//This is the main function you call from a button onclick, it checks the validations,
//takes care of the locking, and submits if validations pass.
/**
 * @param validate - possilbe values are 'always', 'onchange', and false
 * @param formName - the name of the form from StrutsConfig. 
 * @param forwardValue - null, or set if you would like to change the forwardValue before submitting
 * @param actionValue - null, or set if you would like to change the actionValue before submitting
 * @param disabledButton - null, or this (or any js object), refering to the button you would like greyed out.
 *									NOTE: the button Must have a className, and a className identical to it
 *									ending in '_d' must be defined in your style definitions. 
 *									example: .buttonStyle{} and .buttonStyle_d{}
 */
function submitForm(validate, formName, forwardValue, actionValue, disabledButton){
	if(!validator.getDisabledButton()){
		if(disabledButton)
			validator.disableButton(disabledButton);

		if(validate){
			if((validate== 'always') && returnValidation(formName)){			
				executeSubmit(formName, forwardValue, actionValue)
			}else if(validate== 'onchange'){
				if(!validator.getFormChanged())
					executeSubmit(formName, forwardValue, 'forward')
				else if(validator.getFormChanged() && returnValidation(formName))
					executeSubmit(formName, forwardValue, actionValue)
				else
					return false;	
			}
			else {
				return false;
			}
		} else{
			executeSubmit(formName, forwardValue, actionValue)
		}
	}
}

//checks the validations
function returnValidation(formName){
	validator.clearErrors();
	var f= document[formName];

	if(f== null){
		f== document.getElementById(formName);		
		if(f== null){
			alert("Validation Error: form:\n"+ formName+ "\nwas not found");
			return;
		}
	}	
	
	if(!eval('validate'+formName.capitalize()+'(document[\''+formName+'\'])')){
		validator.enableButton();
		return(validator.alertErrors());
	} else{
		return true ;
	}
}

//submits the form, sets any forwards and actions you may need to change.
function executeSubmit(formName, forwardValue, actionValue){
try{
	if(actionValue && (actionValue!= null))
		document[formName].m.value= actionValue;
	if(forwardValue && (forwardValue!= null))
		document[formName].forwardValue.value= forwardValue;
	
	document[formName].submit(); 
}catch(e){
  //alert(e.message);
  }
}

//sets the CC type by inference from the number.

function setCardType(){
	document.orderForm.cardType.value= 
		validator.getCreditCardType(document.orderForm.cardNumber.value);

}



/*  CODE FOR DISPLAYING ERRORS */
// CODE REQUIRES FURTHER INTEGRATION INTO VALIDATOR, dynamically add events, etc.
function ErrorWindow(){	
	ErrorWindow.prototype.getContainer= function(){
		if (typeof(this.container)== 'undefined'){
			var ew= document.createElement('div');
			var body= document.getElementsByTagName("body").item(0);
			
			ew.setAttribute('id','validation_error_window');
			body.appendChild(ew);
			this.container= ew;
		}

		return this.container;
	}
	
	ErrorWindow.prototype.hideErrorWindow= function (){
		if ( validator.errors.length>0){	
			this.getContainer().style.display= 'none';
		}
	}

	ErrorWindow.prototype.showErrorWindow= function(event, objId){
		var obj= document.getElementById(objId);
	
		if ( validator.errors.length>0){
			xy= getXY(obj, false, true);
				
			var testString = obj.id;						
			
			var errorText = this.searchForErrors(testString);
			
			if(errorText!=null){
				this.getContainer().innerHTML=errorText;		
				
				var x= xy[0]-85 < 0 ? 0 : xy[0]-85;
				
				 this.getContainer().style.left= x+ 'px';
				 this.getContainer().style.display= 'block';
				 //order matters here, object has offsetHeight of zero when display=none
				 var y= xy[1]- this.getContainer().offsetHeight;
			  	 this.getContainer().style.top= y+ 'px';
			}
		}
	}

	ErrorWindow.prototype.searchForErrors= function(testString){
		var displayTxt;
		
		var id = testString.split('_')[0];
		for ( i=0; i<validator.errors.length; i++){
			
			if (validator.errors[i][0].name==id)
			{
				displayTxt= validator.errors[i][1];
				break;
			}
		}
		
		return(displayTxt);
	}
} var e= new ErrorWindow();
