//###############################################################################
//#
//# Copyright © 2002 Simon Dowdell 
//#
//# Filename     : clientvalidation.js
//# Author       : Simon Dowdell
//# Date Written : 1st May 2002
//# Purpose      : Client validation routines
//# Objects      : None
//#
//#                             File Change History
//#	
//###############################################################################
//** Global variables
var constString="String"
var constNumber="Number"
var constDate="Date"
var constEmail="Email"
var constSelect="Select"
var constOption="Option"
var constRegExp="RegExp"
var constIgnore="Ignore"

var constErrorMandatory="Mandatory"
var constErrorMin="MinValue"
var constErrorMax="MaxValue"
var constErrorNotNumber="NotNumber"
var constErrorPrecision="Precision"
var constErrorNotDate="NotDate"
var constErrorMinDate="MinDate"
var constErrorMaxDate="MaxDate"

//** Browser detection ------------------------------------------------------------------------------------------------------------------------------
var UserAgent = navigator.userAgent.toLowerCase(); 
var IsNetscape = ((UserAgent.indexOf('mozilla')!=-1) && (UserAgent.indexOf('spoofer')==-1) && (UserAgent.indexOf('compatible') == -1) && (UserAgent.indexOf('opera')==-1)  && (UserAgent.indexOf('webtv')==-1)); 
var BrowserMinorVersion = parseFloat(navigator.appVersion); 


//** Validation collection constructor ------------------------------------------------------------------------------------------------------------------------------
function ValidationCollection () {
	this.ErrorCollection = new Array();
	this.ValidationItemArray = new Array();
	this.BlankCount = 0
	this.AllBlank = false
}

//** Error item constructor------------------------------------------------------------------------------------------------------------------------------
function ErrorItem(Id,ErrorMessage) {
	this.Id=Id
	this.ErrorMessage=ErrorMessage
}


//**ValidationItemDefinition construtor ------------------------------------------------------------------------------------------------------------------------------
function ValidationItemDefinition(DataType,Id,Description,MandatoryFlag,Min,Max,Precision,Format,SpecialCharacters,FormName,LinkField) {
	var today=  new Date()
	this.DataType = DataType;
	this.Id = Id;
	this.Description = Description;
	this.MandatoryFlag = UseDefaultIfBlank(MandatoryFlag,false);
	this.Min = UseDefaultIfBlank(Min,"undefined");
	this.Max = UseDefaultIfBlank(Max,"undefined");
	this.Precision = Precision;
	this.Format=Format;
	this.SpecialCharacters = SpecialCharacters;
	this.FormName = UseDefaultIfBlank(FormName,mstrDefaultForm)
	this.LinkField = UseDefaultIfBlank(LinkField,"undefined")
	
	if ('true'==this.MandatoryFlag) this.MandatoryFlag=true;
	if ('false'==this.MandatoryFlag) this.MandatoryFlag=false;

	this.DataType = ConvertDataType(DataType)

	switch(this.DataType) {
		case constString: 
			this.SpecialCharacters=UseDefaultIfBlankOrNull(SpecialCharacters,"\"'%?&|<>\*");
			break;
			
		case constDate:
			if (this.Min=="today") Min =  DateToString(today);
			this.Min=UseDefaultIfBlankOrNull(Min,"01/01/1900");
			if (4==this.Min.length) this.Min = "01/01/"+this.Min
			if (this.Max=="today") Max =DateToString(today);
			this.Max=UseDefaultIfBlankOrNull(Max,"31/12/9999");
			if (4==this.Max.length) this.Max = "31/12/"+this.Max
			this.Format=UseDefaultIfBlankOrNull(Format,"dd/mm/yyyy");
			if (this.Format.substr(6,4)=="yyyy" && this.Min.substr(6,4)=="1753") this.Min="01/01/1900"
			break;
		case constNumber:
			this.Precision = UseDefaultIfBlankOrNull(Precision,0);
			break;
		default:
			break;
	}			 
}


function ConvertDataType(DataType) {

	switch(DataType) {
		//Ignore
		case "0": 
			return constIgnore
			break;
			
		// Datatypes
		case "2": 
			return constNumber			//Integer
			break;
		
		case "3": 
			return constNumber			//Long
			break;
					
		case "4": 
			return constNumber			//String
			break;		
			
		case "5": 
			return constNumber			//Double
			break;		
			
		case "6": 
			return constNumber			//Currency
			break;	
				
		case "7": 
			return constDate				//Date
			break;	
				
		case "8": 
			return constString			//String
			break;	
				
		case 9: 
			return constEmail			//String
			break;		
		
		case 11: 
			return constNumber			//Bit
			break;
		
		//Field types		
		case 101: 
			return constSelect
			break;
		
		case 102: 
			return constOption
			break;
	
		default:
			return DataType;
			break;	
	}
}

//**PerformValidation  ------------------------------------------------------------------------------------------------------------------------------
function ValidationItemDefinitionPerformValidation(Parent) {
	var strCurrentDefaultForm = mstrDefaultForm;
	mstrDefaultForm	   = this.FormName;
	var objForm = document.forms[mstrDefaultForm]
	var FieldValue = GetFormValue(this.Id);
	var strErrorMessage="";
	var blnFieldBlank = IsBlank(FieldValue);
	var intRadioPosition = -1;
	
	if (constIgnore==this.DataType) return "";
	
	//Find mandatory fields
	if (constOption==this.DataType && true==this.MandatoryFlag) {
		intRadioPosition = GetRadioPosition(this.Id);
		blnFieldBlank = (-1==intRadioPosition);		
	}
	if (blnFieldBlank) Parent.BlankCount++;
	
	if (true==blnFieldBlank && true==this.MandatoryFlag) strErrorMessage="The "+this.Description+" field is blank. It must contain a value"
	else if (true==this.MandatoryFlag || false==blnFieldBlank) {
		//FieldValue=Trim(FieldValue)
		switch (this.DataType) {
			case constString:
				if (IsLessThan(FieldValue.length,this.Min)) strErrorMessage="The "+this.Description+" field must be at least " + this.Min+" characters in length."
				else if (IsGreaterThan(FieldValue.length,this.Max)) strErrorMessage="The "+this.Description+" field cannot exceed "+this.Max+" characters in length"
				else if (isNotValid(FieldValue,this.SpecialCharacters)) strErrorMessage="The "+this.Description+" field should not contain the following special characters (" + this.SpecialCharacters+")."
				break;
			
			case constNumber:
				if (!IsNumeric(FieldValue)) strErrorMessage="The "+this.Description+" field does not contain a valid number."
				else {
					var thisMin = this.Min
					if (!IsUndefined(this.LinkField)) {
						thisMin = GetFormValue(this.LinkField)
					}
					if (IsLessThan(FieldValue,thisMin)) strErrorMessage="The "+this.Description+" field is less than the minimum allowable value of "+thisMin
					else if (IsGreaterThan(FieldValue,this.Max)) strErrorMessage="The "+this.Description+" field is greater than the maximum allowable value of "+this.Max
					else if (!IsPrecisionCorrect(FieldValue,this.Precision)) {
						if (this.Precision==0) strErrorMessage="The "+this.Description+" field must be a whole number"
						else strErrorMessage="The "+this.Description+" field contains a precision greater than the allowable precision of "+this.Precision
					}
				}
				break;
				
			case constDate:
				if (!IsDate(FieldValue,this.Format)) strErrorMessage="The "+this.Description+" field does not contain a valid date."
				else {
					var datFieldValue=ToDate(FieldValue,this.Format);
					if (!IsUndefined(this.LinkField)) {
						if (IsDate(GetFormValue(this.LinkField))) this.Min = GetFormValue(this.LinkField)
					}
					if (!IsUndefined(this.Min)) {
						var datMinValue=ToDate(this.Min,this.Format);
						if (datFieldValue.getTime() < datMinValue.getTime()) strErrorMessage="The "+this.Description+" field is less than the minimum allowable date of "+this.Min
					}
					if (""==strErrorMessage && !IsUndefined(this.Max)) {
						var datMaxValue=ToDate(this.Max,this.Format);
						if (datFieldValue.getTime() > datMaxValue.getTime()) strErrorMessage="The "+this.Description+" field is greater than the maximum allowable date of "+this.Max		
					}
				}
				
			case constSelect:
				break;
			
			default:
				break;
				
			
		}
	}	
	
	mstrDefaultForm = strCurrentDefaultForm;
	return strErrorMessage;

}

function IsLessThan(ValueToCheck,MinValue) {
	var blnReturn = false;
	if (!IsUndefined(MinValue)) {
		if (Number(ValueToCheck)<Number(MinValue)) blnReturn = true;
	}
	return blnReturn;
}
function IsGreaterThan(ValueToCheck,MaxValue) {
	var blnReturn = false;
	if (!IsUndefined(MaxValue)) {
		if (Number(ValueToCheck)>Number(MaxValue)) blnReturn = true;
	}
	return blnReturn;
}
function IsPrecisionCorrect(ValueToCheck,Precision) {
	var blnReturn = true;
	if (!IsUndefined(Precision)) {
		var arrData = ValueToCheck.split(".");
		if (2==arrData.length) {
			if (0==String(arrData[1]).length || String(arrData[1]).length>Precision) blnReturn=false;
		}
	}
	return blnReturn;
}

function isNotValid(string,notallowed) {
    for (var i=0; i< string.length; i++) {
       if (notallowed.indexOf(string.charAt(i)) != -1)
          return true;
    }
    return false;
}

//**ValidationCollectionAddItem  ------------------------------------------------------------------------------------------------------------------------------
function ValidationCollectionAddItem(DataType,Id,Description,MandatoryFlag,Min,Max,Precision,Format,SpecialCharacters,FormName,LinkField) {
  this.ValidationItemArray[this.ValidationItemArray.length]=new ValidationItemDefinition(DataType,Id,Description,MandatoryFlag,Min,Max,Precision,Format,SpecialCharacters,FormName,LinkField)	
}

//**ValidationCollectionUpdateRule  ------------------------------------------------------------------------------------------------------------------------------
function ValidationCollectionUpdateRule(Id,RuleName,NewValue) {
	var blnFound = false;
	for (var intItemPtr=0;intItemPtr<this.ValidationItemArray.length && blnFound==false;intItemPtr++) {
		if (Id==this.ValidationItemArray[intItemPtr].Id) {
			blnFound=true;
			switch (RuleName) {
				case "DataType": 
					this.ValidationItemArray[intItemPtr].DataType=ConvertDataType(NewValue);
					break;

				case "Id":       
					this.ValidationItemArray[intItemPtr].Id = NewValue;
					break;

				case "Description": 
					this.ValidationItemArray[intItemPtr].Description = NewValue;
					break;

				case "MandatoryFlag": 
					this.ValidationItemArray[intItemPtr].MandatoryFlag = NewValue;
					break;

				case "Min": 
					this.ValidationItemArray[intItemPtr].Min = NewValue;
					break;

				case "Max": 
					this.ValidationItemArray[intItemPtr].Max = NewValue;
					break;

				case "Precision": 
					this.ValidationItemArray[intItemPtr].Precision = NewValue;
					break;

				case "Format": 
					this.ValidationItemArray[intItemPtr].Format = NewValue;
					break;

				case "SpecialCharacters": 
					this.ValidationItemArray[intItemPtr].SpecialCharacters = NewValue;
					break;

				case "FormName": 
					this.ValidationItemArray[intItemPtr].FormName = NewValue;
					break;

				case "LinkField": 
					this.ValidationItemArray[intItemPtr].LinkField = NewValue;
					break;				
			}
		}
	}	
}

//**ItemExists ------------------------------------------------------------------------------------------------------------------------------
function ItemExists(Array,Id) {
	for (var intItemPtr=0;intItemPtr<Array.length;intItemPtr++) {
		if (Id==Array[intItemPtr].Id) return true;
	}
	return false;
}


//**ValidationCollectionValidateItems  ------------------------------------------------------------------------------------------------------------------------------
function ValidationCollectionValidateItems() {
	var strErrorMessage=""
	this.BlankCount = 0
	this.AllBlank = false;
	this.ErrorCollection = new Array();
	for (var intItemPtr=0;intItemPtr<this.ValidationItemArray.length;intItemPtr++) {
		strErrorMessage=this.ValidationItemArray[intItemPtr].Validate(this);
		if (""!=strErrorMessage) {
			var objErrorItem = new ErrorItem(this.ValidationItemArray[intItemPtr].Id,strErrorMessage)
	   	    this.ErrorCollection[this.ErrorCollection.length]=objErrorItem;
		}
	}
	if (this.BlankCount==this.ValidationItemArray.length) this.AllBlank=true;
	return this.ErrorCollection

}

//**ValidationCollectionResetAllFields  ------------------------------------------------------------------------------------------------------------------------------
function ValidationCollectionResetAllFields() {
	
	for (var intItemPtr=0;intItemPtr<this.ValidationItemArray.length;intItemPtr++) {
		SetValue(this.ValidationItemArray[intItemPtr].Id,"")
	}
	return true;

}


//**ValidationCollectionDisplayRules  ------------------------------------------------------------------------------------------------------------------------------
function ValidationCollectionDisplayRules() {
	var strRules=""
	
	for (var intItemPtr=0;intItemPtr<this.ValidationItemArray.length;intItemPtr++) {
		strRules=""
		strRules+="Datatype:"+this.ValidationItemArray[intItemPtr].DataType+"\n"
		strRules+="Id:"+this.ValidationItemArray[intItemPtr].Id+"\n"
		strRules+="Description:"+this.ValidationItemArray[intItemPtr].Description+"\n"
		strRules+="MandatoryFlag:"+this.ValidationItemArray[intItemPtr].MandatoryFlag+"\n"
		strRules+="Min:"+this.ValidationItemArray[intItemPtr].Min+"\n"
		strRules+="Max:"+this.ValidationItemArray[intItemPtr].Max+"\n"
		strRules+="Precision:"+this.ValidationItemArray[intItemPtr].Precision+"\n"
		strRules+="Format:"+this.ValidationItemArray[intItemPtr].Format+"\n"
		strRules+="SpecialCharacters:"+this.ValidationItemArray[intItemPtr].SpecialCharacters+"\n"
		strRules+="FormName:"+this.ValidationItemArray[intItemPtr].FormName+"\n"
		strRules+="LinkField:"+this.ValidationItemArray[intItemPtr].LinkField+"\n"
		alert(strRules)	
	}
	return true
}


function ValidationCollectionAddError(Id,ErrorMessage) {
	var objErrorItem = new ErrorItem(Id,ErrorMessage)
	this.ErrorCollection[this.ErrorCollection.length]=objErrorItem;
	return this.ErrorCollection
}

function HandleValidateErrors(collErrors,strAction) {
	var strErrorMessage="To "+strAction+", you must correct the following errors:-\n\n"
	for (var icnt=0;icnt<collErrors.length;icnt++) {
		strErrorMessage+=(icnt+1)+") "+collErrors[icnt].ErrorMessage+"\n"
	}
	alert(strErrorMessage);
	SetFocus(collErrors[0].Id)
	return strErrorMessage
}

function ValidationCollectionClearErrors() {
	this.ErrorCollection = new Array();
}

//**UseDefaultIfBlank  ------------------------------------------------------------------------------------------------------------------------------
function UseDefaultIfBlank(Item,DefaultValue) {
	if (IsUndefined(Item)) return DefaultValue
	else return Item;
}

//** OBJECT CONSTRUCTION -------------------------------------------------------------------------------------------------
new ValidationItemDefinition;
new ErrorItem;
new ValidationCollection;

//** PROTOTYPE CONSTRUCTION -------------------------------------------------------------------------------------------------
ValidationItemDefinition.prototype.Validate = ValidationItemDefinitionPerformValidation;

ValidationCollection.prototype.AddItem = ValidationCollectionAddItem;
ValidationCollection.prototype.Validate = ValidationCollectionValidateItems;
ValidationCollection.prototype.UpdateRule = ValidationCollectionUpdateRule;
ValidationCollection.prototype.AddError = ValidationCollectionAddError;
ValidationCollection.prototype.DisplayRules = ValidationCollectionDisplayRules;
ValidationCollection.prototype.ClearErrors = ValidationCollectionClearErrors;
ValidationCollection.prototype.ResetInputFields = ValidationCollectionResetAllFields;



