/**
 * Check Attributs for an Element
 *
 * @param		oSrc				element object
 * @param		myValue 			element Value
 *
 * @property	nospace 			all whitespace is removed from the field.
 * @property	uppercase			all letters become uppercase.
 * @property	lowercase			all letters become lowercase.
 * @property	minLen				defines the minimum len value the field may have. 
 * @property	maxLen				defines the maximum len value the field may have.
 * @property	format				the field must contain a valid date as specified by the property (e.g. date="YYYY/MM/DD").
 * @property	floatPoint			the field must contain a valid floating point number. The value of the attribute (e.g., float=","). 
 * @property	signed				when used this attribute further allows the user to use plus (+) or minus (-) sign in element.
 * @property	min 				defines the minimum value the field may have. 
 * @property	max 				defines the maximum value the field may have.
 * @property	required			the field must have a non-whitespace value.
 * @property	regexp				the field value must be consistent with the given regular expression.
 * @property	mask				the mask allows you to define an expected format for the given field.
 * @property	filter				only the specified key characters are accepted as input.
 * @property	and 				if the field contains a value, all the fields whose names appear in this comma-delimited list must also contain values.
 * @property	or					if the field does not contain a value, at least one of the fields whose names appear in this comma-delimited list must contain a value. Use this validation on the default field for the group.
 * @property	div 				div ID for displayin g error message for this element.
 *
 * @return							Boolean
 */
Validation.prototype.checkAttributes=function (oSrc,myValue){ 
	if (!this.isAbsent(myValue)) {
		
		// --------------------------------
		// Check specific attributes by type
		// --------------------------------
		switch (oSrc.datatype){
		
			// --------------------------------
			// check STRING specifics attributes
			// --------------------------------
			case "string" :

				// NOSPACE
				if (oSrc.nospace)
					oSrc.value = oSrc.value.replace(/\s/g,"");
	
				// UPPERCASE
				if (oSrc.uppercase)
					oSrc.value=oSrc.value.toUpperCase();
	
				// LOWERCASE
				if (oSrc.lowercase) 
					oSrc.value=oSrc.value.toLowerCase();	
		
				// MINLEN
				if(oSrc.minLen && this.isNum(oSrc.minLen) && myValue.length < oSrc.minLen) {
					this.Err.add(oSrc, this.OCME_MINLEN.replace("&MINLEN",this.formatNumber(oSrc.minLen)));
					return false;
				}
				
				// MAXLEN
				if(oSrc.maxLen && this.isNum(oSrc.maxLen) && myValue.length > oSrc.maxLen) {
					this.Err.add(oSrc, this.OCME_MAXLEN.replace("&MAXLEN",this.formatNumber(oSrc.maxLen)));
					return false;
				}
				break;

			// --------------------------------
			// check DATE specifics attributes
			// --------------------------------
			case "date" :
			
				// FORMAT
				var sFormat=oSrc.format;

				// Set default date format
				sFormat = this.setDefault(sFormat, "MM/DD/YYYY");
				if (!this.isDate(oSrc,sFormat)){
					this.Err.add(oSrc, this.OCME_FORMAT.replace("&FORMAT",sFormat));
					return false;
				}
				break;

			// --------------------------------
			// check REAL specifics attributes
			// --------------------------------
			case "real" :
				var sFloatDelimiter = oSrc.floatPoint;
				var bSigned = (oSrc.signed != false) && (oSrc.signed != null);
	
				// Assign default value to delimiter
				sFloatDelimiter=(sFloatDelimiter==",")?",":"\\.";
				var re=new RegExp("^("+((bSigned)?"[\\-\\+]?":"")+"(\\d*"+sFloatDelimiter+"?\\d+)|(\\d+"+sFloatDelimiter+"?\\d*))$");
				if (!re.test(myValue)){
					this.Err.add(oSrc, this.OCME_FLOAT);
					return false;
				}

				// MIN
				if(this.isMin(oSrc)==false) {
					this.Err.add(oSrc, this.OCME_MIN.replace("&MIN",oSrc.min));
					return false;
				}

				// MAX
				if(!this.isMax(oSrc)) {
					this.Err.add(oSrc, this.OCME_MAX.replace("&MAX",oSrc.max));
					return false;
				}
				break;

			// --------------------------------
			// check INTEGER specifics attributes
			// --------------------------------
			case "integer" :
				var bSigned = (oSrc.signed != false) && (oSrc.signed != null);
				var re=new RegExp("^"+((bSigned)?"[\\-\\+]?":"")+"\\d+$");
				if (!re.test(myValue)){
					this.Err.add(oSrc, this.OCME_INTEGER);
					return false;
				}
		
				// MIN
				if(!this.isMin(oSrc)) {
					this.Err.add(oSrc, this.OCME_MIN.replace("&MIN",oSrc.min));					
					return false;
				}

				// MAX
				if(!this.isMax(oSrc)) {
					this.Err.add(oSrc, this.OCME_MAX.replace("&MAX",oSrc.max));
					return false;
				}
				break;
		}				
	}	
	
	// --------------------------------
	// Check general attributes
	// --------------------------------

	// --------------------------------
	// REQUIRED
	// --------------------------------
	if (oSrc.required) {
		if (oSrc.type == "radio") {
			var i, iFields = this.elements[oSrc.name].length;
			var bAccum = false;
			for(i=0; i<iFields; i++){
		
				// --------------------------------
				// Search in the "elements" Collection 
				// --------------------------------
				var oNewElement= this.elements[oSrc.name][i];
				var sReturnValue = null;
				if(oNewElement.checked){
					sReturnValue = oNewElement.value ? oNewElement.value : true;
				}	
				bAccum |= !this.isAbsent(sReturnValue);		
			}
			if(!bAccum){
				this.Err.add(oSrc, this.OCME_REQUIRED);
				return false;
			}
		}
		else {
			if (this.isAbsent(myValue)) {
				this.Err.add(oSrc, this.OCME_REQUIRED);
				return false;
			}
		}	
	}
	
	// --------------------------------
	// REGEXP
	// --------------------------------
	var sRegexp=oSrc.regexp;
	if(sRegexp && myValue){
		var re=new RegExp(sRegexp);
		if(!re.test(myValue)){
			this.Err.add(oSrc, this.OCME_REGEXP);
			return false;
		}
	}
	
	// --------------------------------
	// MASK
	// --------------------------------
	var sMask=oSrc.mask;
	if(sMask && myValue){
		var sPattern=sMask.replace(/(\$|\^|\*|\(|\)|\+|\.|\?|\\|\{|\}|\||\[|\])/g,"\\$1");
		sPattern=sPattern.replace(/9/g ,"\\d");
		sPattern=sPattern.replace(/x/ig,".");
		sPattern=sPattern.replace(/z/ig,"\\d?");
		sPattern=sPattern.replace(/a/ig,"[A-Za-z]");
		var re=new RegExp("^"+sPattern+"$");
		if(!re.test(myValue)){
			this.Err.add(oSrc, this.OCME_MASK.replace("&MASK", sMask));
			return false;
		}
	}
	
	// --------------------------------
	// AND
	// --------------------------------
	var sAnd=oSrc.and;
	var sIndex = new String(oSrc.index);
	if (sIndex == "undefined")
		sIndex = false;
	if(sAnd){
		if (this.isAbsent(myValue)){
			this.Err.add(oSrc, this.OCME_REQUIRED);
			return false;
		}
	
		var aAnd = sAnd.split(/,/);
		var i, iFields=aAnd.length;
	
		// --------------------------------
		// Require each element in the list if this element is valued
		// --------------------------------
		for(i=0; i<iFields; i++){
		
			// Search in the "elements" Collection 
			if (sIndex){
				var oNewElement= this.elements[aAnd[i]][oSrc.index];
			}
			else{
				var oNewElement = this.elements[aAnd[i]];					
			}
			if(oNewElement && this.isAbsent(this.getValueOf(oNewElement))){
				this.Err.add(oNewElement, this.OCME_REQUIRED);
				return false;
			}
		}
	}

	// --------------------------------
	// OR
	// --------------------------------
	var sOr=oSrc.or;
	var sIndex = new String(oSrc.index);
	if (sIndex == "undefined")
		sIndex = false;
	if(sOr && this.isAbsent(myValue)){
		var aOr=sOr.split(/,/);
		var i, iFields=aOr.length;
		var bAccum = false;
		for(i=0; i<iFields; i++){
		
			// --------------------------------
			// Search in the "elements" Collection 
			// --------------------------------
			if (sIndex){
				var oNewElement = this.elements[aOr[i]][oSrc.index];
			}
			else {
				var oNewElement = this.elements[aOr[i]];
			}	
			bAccum |= !this.isAbsent(this.getValueOf(oNewElement));		
		}
		if(!bAccum){
			this.Err.add(oSrc, this.OCME_REQUIRED);
			return false;
		}
	}
	return true;
}

/**
 * Set value for variable v if v is zero, empty string or undefined
 *
 * @param		v					variable (passed by value)
 * @param		d					default value
 *
 * @return							v or d
 */
Validation.prototype.setDefault = function(v, d){
	return (v)?v:d;
}

/**
 * Check that value is a date of the correct format
 *
 * @param		oElement			form element
 * @param		sFormat 			string format
 *
 * @return							boolean
 */
Validation.prototype.isDate = function(oElement,sFormat){
	var sDate=oElement.value;
	var aDaysInMonth=new Array(31,28,31,30,31,30,31,31,30,31,30,31);

	// --------------------------------
	// Fetch the date separator from the user's input
	// --------------------------------
	var sSepDate=sDate.charAt(sDate.search(/\D/));

	// --------------------------------
	// Fetch the date separator from the format
	// --------------------------------
	var sSepFormat=sFormat.charAt(sFormat.search(/[^MDY]/i));

	// --------------------------------
	// Compare separators
	// --------------------------------
	if (sSepDate!=sSepFormat)
		return false;

	// --------------------------------
	// Fetch the three pieces of the date from the user's input and the format
	// --------------------------------
	var aValueMDY=sDate.split(sSepDate);
	var aFormatMDY=sFormat.split(sSepFormat);
	var iMonth,iDay,iYear;

	// --------------------------------
	// Validate that all pieces of the date are numbers
	// --------------------------------
	if ( !this.isNum(aValueMDY[0])
		||!this.isNum(aValueMDY[1])
		||!this.isNum(aValueMDY[2]))
		return false;

	// --------------------------------
	// Assign day, month, year based on format
	// --------------------------------
	switch (aFormatMDY[0].toUpperCase()){
		case "YYYY" :
			iYear=aValueMDY[0];
			break;
		case "DD" :
			iDay=aValueMDY[0];
			break;
		case "MM" :
			iMonth=aValueMDY[0];
			break;
		default :
			return false;
	}
	switch (aFormatMDY[1].toUpperCase()){
		case "YYYY" :
			iYear=aValueMDY[1];
			break;
		case "MM" :
			iMonth=aValueMDY[1];
			break;
		case "DD" :
			iDay=aValueMDY[1];
			break;
		default :
			return false;
	}
	switch(aFormatMDY[2].toUpperCase()){
		case "MM" :
			iMonth=aValueMDY[2];
			break;
		case "DD" :
			iDay=aValueMDY[2];
			break;
		case "YYYY" :
			iYear=aValueMDY[2];
			break;
		default :
			return false;
	}

	// --------------------------------
	// Require 4 digit year
	// --------------------------------
	if(oElement.year4 !=null && iYear.length!=4)
		return false;

	// --------------------------------
	// Process pivot date and update field
	// --------------------------------
	var iPivot = this.setDefault(oElement.pivot,this.pivot);
	if(iPivot && iPivot.length==2 && iYear.length==2){
		iYear=((iYear>iPivot)?19:20).toString()+iYear;
		var sValue=aFormatMDY.join(sSepFormat).replace(/MM/i,iMonth);
		sValue=sValue.replace(/DD/i,iDay).replace(/YYYY/i,iYear);
		oElement.value=sValue;
	}

	// --------------------------------
	// Check for leap year
	// --------------------------------
	var iDaysInMonth=(iMonth!=2)?aDaysInMonth[iMonth-1]:
		((iYear%4==0 && iYear%100!=0 || iYear % 400==0)?29:28);
		return (iDay!=null && iMonth!=null && iYear!=null
				&& iMonth<13 && iMonth>0 && iDay>0 && iDay<=iDaysInMonth);
}

/**
 * Check that if value is present
 *
 * @param		sValue				element value
 *
 * @return							boolean
 */
Validation.prototype.isAbsent = function(sValue) {
	if (!sValue || sValue == '' || sValue == null || sValue == undefined || sValue == "undefined") {
		return true;
	}	
	else {
		return false;
	}	
}

/**
 * Check that parameter is a number
 *
 * @param		v					string value
 *
 * @return							boolean
 */
Validation.prototype.isNum = function (v) {
	return (typeof v!="undefined" && v.toString() && !/\D/.test(v));
}

/**
 * Check that value is > min parameter
 *
 * @param		oElement			element object
 *
 * @return							boolean
 */
Validation.prototype.isMin = function(oElement) {
	var  iMin = oElement.min;
	var rValue = oElement.value;
	if(iMin==parseFloat(iMin) && parseFloat(rValue.replace(",",".")) < iMin) {
		return false;
	}	
	else {
		return true;
	}	
}

/**
 * Check that value is < max parameter
 *
 * @param		oElement			element object
 *
 * @return							boolean
 */
Validation.prototype.isMax = function(oElement) {
	var iMax = oElement.max;
	var rValue = oElement.value;
	if(iMax==parseFloat(iMax) && parseFloat(rValue.replace(",",".")) > iMax){
		return false;
	}	
	else {
		return true;	
	}	
}

/**
 * Format an integer for display
 *
 * @param		i					integer value (as string)
 *
 * @return							string
 */
Validation.prototype.formatNumber = function(i){
	var sEnd="$";
	i = i.toString();
	if (/\./.test(i))
		sEnd="\\.";
	var re = new RegExp("(\\d)(\\d{3})(,|"+sEnd+")");
	if(re.test(i))
		i = this.formatNumber(i.replace(re, "$1 $2$3"));
	return i;
}



