//-------------------------------------------------------------------------//
// Name          : Javascript validator Engine V4                          //
// Author        : LECLERE Frederic                                        //
// Date          : 18/07/2007                                              //
//                                                                         //
// Can accept Multiple checkbox and radio buttons verification             //
//-------------------------------------------------------------------------//  

// WE CREATE DIV TO CONTAIN MESSAGE //
var errorMessageId    = "errorMessage";
var errorMessageClass = "error";
var isIE              = browser.isIE; //generated by browser.js
var errorMessageTimeout;

function InitEngine() {
	var div = document.createElement("DIV");
	
	div.setAttribute("id",errorMessageId);
	
	if (isIE) div.className = errorMessageClass;
	else div.setAttribute("class",errorMessageClass);
	
	document.getElementsByTagName("BODY").item(0).appendChild(div);
	
	ToggleErrorMessage("");
}

function ToggleErrorMessage(message) {
	oDiv = document.getElementById(errorMessageId);
	
	if (oDiv ==  undefined) {
		alert("Engine was not properly initialized.");
		return;
	}
	
	window.clearTimeout(errorMessageTimeout);
	
	oDiv.innerHTML     = message + "<p align=\"right\"><a href=\"javascript:ToggleErrorMessage('');\">close</a></p>";
	oDiv.style.display = (message != "") ? "" : "none";	
	
	errorMessageTimeout = window.setTimeout("ToggleErrorMessage('')",4000);
}

function MoveErrorMessage(oField,padLeft,padTop) {
	oDiv = document.getElementById(errorMessageId);
	
	if (oDiv ==  undefined) {
		alert("Engine was not properly initialized.");
		return false;
	}
	
	if (oField ==  undefined) {
		alert("oField doesn't exists.");
		return false;
	}
	
	var left   = 0;
	var top    = 0;
	var object = oField;
	
	if (object.offsetParent) {
		left = object.offsetLeft;
		top  = object.offsetTop;
		
		while (object = object.offsetParent) {
			left += object.offsetLeft;
			top  += object.offsetTop;
		}
	}
	
	oDiv.style.left = left + oField.offsetWidth + padLeft + "px";
	oDiv.style.top  = top + oField.offsetHeight + padTop + "px";
}


function RegExpEngine(fieldValue,command,parameter) {
	var regString = "";

	switch(command) { 
		case "A":
			regString = "[a-zA-Z]";
			break;
			
		case "N":
			regString = "[0-9]";<!-- "\d"; -->
			break;
		
		case "AN":
			regString = "[a-zA-Z0-9]";<!-- \w -->
			break;

		case "AN+":
			regString = "[A-Za-z0-9\-_]";
			break;

		case "MIN":
			regString = "{"+parameter+",65535}";
			break;

		case "MAX":
			regString = "{0,"+parameter+"}";
			break;

		case "REG":
			regString = parameter;
			break;

		case "EMAIL":
			regString = "^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9]+)*$";
			break;
	}
	
	return (fieldValue.search(regString) != -1);
}

function IsNumeric(strString) {
	var strValidChars = "0123456789.-";
	var blnResult     = true;
	var strChar;
	
	if (strString.length == 0) return false;
	
	//  test strString consists of valid characters listed above
	for (i = 0; i < strString.length && blnResult == true; i++) {
		strChar = strString.charAt(i);
		if (strValidChars.indexOf(strChar) == -1) blnResult = false;
	}
	
	return blnResult;
}

function IsAPhoneNumber(strString) {
	var strValidChars = "0123456789 -()";
	var blnResult     = true;
	var strChar;
	
	if (strString.length == 0) return false;
	
	//  test strString consists of valid characters listed above
	for (i = 0; i < strString.length && blnResult == true; i++) {
		strChar = strString.charAt(i);
		if (strValidChars.indexOf(strChar) == -1) blnResult = false;
	}
	
	return blnResult;
}

function WordCount (string) {
	var char_count              = string.length;
	var fullStr                 = string + " ";
	var initial_whitespace_rExp = /^[^A-Za-z0-9]+/gi;
	var left_trimmedStr         = fullStr.replace(initial_whitespace_rExp, "");
	var non_alphanumerics_rExp  = rExp = /[^A-Za-z0-9]+/gi;
	var cleanedStr              = left_trimmedStr.replace(non_alphanumerics_rExp, " ");
	var splitString             = cleanedStr.split(" ");
	var word_count              = splitString.length -1;
	
	return word_count;
}

// FUNCTIONS TO CHECK VALID DATES //
function IsInteger(s) {
	var i;
	
    for (i = 0; i < s.length; i++) {   
        // Check that current character is number.
        var c = s.charAt(i);
        if (((c < "0") || (c > "9"))) return false;
    }
    // All characters are numbers.
    return true;
}

function StripCharsInBag(s, bag){
	var i;
    var returnString = "";
    // Search through string's characters one by one.
    // If character is not in bag, append to returnString.
    for (i = 0; i < s.length; i++){   
        var c = s.charAt(i);
        if (bag.indexOf(c) == -1) returnString += c;
    }
    return returnString;
}

function DaysInFebruary (year) {
	// February has 29 days in any year evenly divisible by four,
    // EXCEPT for centurial years which are not also divisible by 400.
    return (((year % 4 == 0) && ( (!(year % 100 == 0)) || (year % 400 == 0))) ? 29 : 28 );
}

function DaysArray(n) {
	for (var i = 1; i <= n; i++) {
		this[i] = 31;
		if ((i == 4) || (i == 6) || (i == 9) || (i == 11)) this[i] = 30;
		if (i == 2) this[i] = 29;
	} 
   
   return this;
}

function IsDate(dtStr) {
	var dtCh        = "/";
    var minYear     = 1900;
    var maxYear     = 2100;
	var daysInMonth = DaysArray(12);
	var pos1        = dtStr.indexOf(dtCh);
	var pos2        = dtStr.indexOf(dtCh,pos1 + 1);
	var strDay      = dtStr.substring(0,pos1);
	var strMonth    = dtStr.substring(pos1 + 1,pos2);
	var strYear     = dtStr.substring(pos2 + 1);
	strYr           = strYear;
	
	if ((strDay.charAt(0) == "0") && (strDay.length > 1)) strDay = strDay.substring(1);
	if ((strMonth.charAt(0) == "0") && (strMonth.length > 1)) strMonth = strMonth.substring(1);
	
	for (var i = 1; i <= 3; i++) if ((strYr.charAt(0) == "0") && (strYr.length > 1)) strYr = strYr.substring(1);
	
	var month = parseInt(strMonth);
	var day   = parseInt(strDay);
	var year  = parseInt(strYr);
	
	if ((pos1 == -1) || (pos2 == -1)) return false;
	
	if ((strMonth.length < 1) || (month < 1) || (month > 12)) return false;
	if ((strDay.length < 1) || (day < 1) || (day > 31) || ((month == 2) && (day > DaysInFebruary(year))) || (day > daysInMonth[month])) return false;
	if ((strYear.length != 4) || (year == 0) || (year < minYear) || (year > maxYear)) return false;
	if ((dtStr.indexOf(dtCh,pos2+1) != -1) || (IsInteger(StripCharsInBag(dtStr, dtCh)) == false)) return false;
	
	return true;
}


function CompareDate(dtStr1,dtStr2) {
	var dtCh = "/";
    var pos1 = 0;
	var pos2 = 0;
	
	pos1 = dtStr1.indexOf(dtCh);
	pos2 = dtStr1.indexOf(dtCh,pos1+1);
	
	var strDay1   = dtStr1.substring(0,pos1);
	var strMonth1 = dtStr1.substring(pos1+1,pos2);
	var strYear1  = dtStr1.substring(pos2+1);
	
	pos1 = dtStr2.indexOf(dtCh);
	pos2 = dtStr2.indexOf(dtCh,pos1+1);
	
	var strDay2=dtStr2.substring(0,pos1);
	var strMonth2=dtStr2.substring(pos1+1,pos2);
	var strYear2=dtStr2.substring(pos2+1);
	
	var date1 = strYear1 + strMonth1 + strDay1;
	var date2 = strYear2 + strMonth2 + strDay2;
	
	return (date1 > date2);
}

function Trim(stringToTrim, trimWay, trimChar) {
	var trimedString = "";
	var length       = stringToTrim.length -1;

	if (trimWay == "<" || trimWay == "<>" || trimWay =="><") {
		for (i = 0; i <= length; i++) {
			if (stringToTrim.charAt(i) != trimChar) {
				trimedString = stringToTrim.substring(i,length + 1);
				break;
			}
		}
		
		// used if we both trim from left & right
		if (trimWay == "<>" || trimWay =="><") {
			stringToTrim = trimedString;
			length       = stringToTrim.length - 1;
		}
	}
	
	if (trimWay == ">" || trimWay == "<>" || trimWay =="><") {
		for (i = length; i >= 0; i--) {
			if (stringToTrim.charAt(i) != trimChar) {
				trimedString = stringToTrim.substring(0,i + 1);
				break;
			}
		}
	}
	
	return trimedString;
}

function CheckField(oField,fullCommand,message,oAnchor) { 
	oDiv = document.getElementById(errorMessageId);
	
	if (oDiv ==  undefined) {
		alert("Engine was not properly initialized.");
		return false;
	}
	
	if(oField == undefined) {
		alert("oField was not found.");
		return false;
	}
	
	var equal     = fullCommand.search("="); 
	var command   = ""; 
	var parameter = "";
	var error     = false;
	
	if(equal >= 0) { 
		command    = fullCommand.substring(0,equal); 
		parameter  = fullCommand.substr(equal + 1); 
	} else command = fullCommand;
	
	switch(command) { 
		case "req": 
		case "required":
			error = (eval(Trim(oField.value,"<>", " ").length) == 0); 
			break;

		case "maxlength": 
		case "maxlen": 
			error = (eval(oField.value.length) >  eval(parameter));
			break;
		
		case "minlength": 
		case "minlen": 
			error = (eval(oField.value.length) <  eval(parameter));
			break;
		
		case "alnum": 
		case "alphanumeric": 
			if(oField.value.length > 0)
				error = !RegExpEngine(oField.value, "AN", "");
			break;
		
		case "num": 
		case "numeric": 
			if(oField.value.length > 0)
				error = !IsNumeric(oField.value);
			break;
		
		case "phone": 
			if(oField.value.length > 0)
				 error = IsAPhoneNumber(oField.value);
			break;
		
		case "alphabetic": 
		case "alpha": 
			if(oField.value.length > 0)
				error = !RegExpEngine(oField.value, "A", "");
			break;
		
		case "alnumhyphen":
			if(oField.value.length > 0)
				error = !RegExpEngine(oField.value, "AN+", ""); 			
			break;
		
		// REGEXP //
		// Check oField value with a regular expression
		case "regexp": 
			if(oField.value.length > 0)
				error = !RegExpEngine(oField.value, "REG", parameter);
			break;
		
		// email //
		// Check if a oField is a valid e-mail
		case "email": 
			if(oField.value.length > 0)
				error = !RegExpEngine(oField.value, "EMAIL", ""); 
			break; 
		
		// lt & lessthan //
		// Check if a numeric oField value is less than X
		case "lt": 
		case "lessthan": 
			if(isNaN(oField.value)) return false; 
			error = (eval(oField.value) >= eval(parameter));
			break;
		
		// gt & greaterthan //
		// Check if a numeric oField value is greater than X
		case "gt": 
		case "greaterthan": 
			if(isNaN(oField.value)) return false; 
			error = (eval(oField.value) <= eval(parameter));
			break;
		
		// NOSEL //
		//Determine if an item different than default one is selected
		case "nosel":
			error = (oField.value == parameter);
			break;
			
		// CHK & CHECK //
		//Determine if a checkbox or a radio button is selected
		case "chk":
		case "check":
			var occ = 0;
			
			if(oField.length != undefined) {
				for (var i = 0; i < oField.length; i++) if ((oField[i].selected) || (oField[i].checked)) occ++;
			} else occ = oField.checked * 1;
			
			error = (occ == 0);
			break;
		
		case "countwords":
			 error = (WordCount(oField.value) > eval(parameter));
			break;
			
		case "date":			
			error = !IsDate(oField.value);
			break;

		case "dategt":
			error = CompareDate(oField.value,parameter);
			break;
			
		case "sel": 
			if(oField.value == 'Any')
				error = oField.value;
			break;
	}
	
	if(error) {		
		if (((command == "chk") || (command == "check")) && (oField.length != undefined)) oField = oField[0];
		
		if(oAnchor == undefined) {
			MoveErrorMessage(oField,-30,-5);
			oField.focus();
		} else {
			MoveErrorMessage(oAnchor,-30,-5);
			document.location.href = "#" + oAnchor.name;
		}
		
		ToggleErrorMessage(message);
	}
	
	return !error;
}
