/*******************************************************************************
$Id: RegExpValidate.js,v 1.6 2009/02/25 13:36:14 Riccardo Exp $
FILE: RegExpValidate.js

VALIDATION FUNCTIONS:
  validateNumeric - checks for valid numeric value
  validateInteger - checks for valid integer value
  validateNotEmpty - checks for blank form field
  validateEmail - checks format of email address
  validateUSPhone - checks format of US phone number
  validateUSZip - checks for valid US zip code
  validateUSDate - checks for valid date in US format
  validateValue - checks a string against supplied pattern
  
FORMAT FUNCTIONS:  
  rightTrim - removes trailing spaces from a string
  leftTrim - removes leading spaces from a string
  trimAll - removes leading and trailing spaces from a string
  removeCurrency - removes currency formatting characters (), $ 
  addCurrency - inserts currency formatting characters
  removeCommas - removes comma separators from a number
  addCommas - adds comma separators to a number
  removeCharacters - removes characters from a string that match passed pattern

SAMPLE:
  VALIDATE:
  if(!validateNumeric(field.value)){alert('Invalid Number')};
  if(!validateEmail(field.value)){alert('Invalid Email')};
  if(!validateInteger(field.value)){alert('Invalid Integer')};
  if(!validateUSPhone(field.value)){alert('Invalid Phone')};
  if(!validateUSDate(field.value)){alert('Invalid Date')};
  if(!validateNotEmpty(field.value)){alert('Empty')};
  if(!validateUSZip(field.value)){alert('Invalid Zip Code')};
  if(!validateValue(field.value, '^[a-zA-Z0-9]+$')){alert('Not alphanumeric')};

  FORMAT:
  field.value=rightTrim(field.value)); 
  field.value=leftTrim(field.value));
  field.value=addCommas(field.value)); 
  field.value=removeCommas(field.value));
  field.value=addCurrency(field.value));
  field.value=removeCurrency(field.value));
  field.value=removeCharacters(field.value,'[ ]'));
  field.value=trimAll(field.value));
  

*******************************************************************************/

function  validateNumeric( strValue ) {
/******************************************************************************
DESCRIPTION: Validates that a string contains only valid numbers.
PARAMETERS: strValue - String to be tested for validity
RETURNS: True if valid, otherwise false.
******************************************************************************/
  var objRegExp  =  /(^-?\d\d*\,\d*$)|(^-?\d\d*$)|(^-?\,\d\d*$)/; 
  //check for numeric characters 
  return objRegExp.test(strValue);
}

function validateInteger( strValue ) {
/************************************************
DESCRIPTION: Validates that a string contains only valid integer number.
PARAMETERS: strValue - String to be tested for validity
RETURNS: True if valid, otherwise false.
******************************************************************************/
  var objRegExp  = /(^-?\d\d*$)/;
 
  //check for integer characters
  return objRegExp.test(strValue);
}

function validateNotEmpty( strValue ) {
/************************************************
DESCRIPTION: Validates that a string is not all blank (whitespace) characters.
PARAMETERS: strValue - String to be tested for validity
RETURNS: True if valid, otherwise false.
*************************************************/
   var strTemp = strValue;
   strTemp = trimAll(strTemp);
   if(strTemp.length > 0){
     return true;
   }  
   return false;
}

function validateEmail( strValue) {
/************************************************
DESCRIPTION: Validates that a string contains a valid email pattern. 
PARAMETERS: strValue - String to be tested for validity
RETURNS: True if valid, otherwise false.
REMARKS: Accounts for email with country appended
  does not validate that email contains valid URL
  type (.com, .gov, etc.) or valid country suffix.
*************************************************/
//var objRegExp  = /^(\w+\.)*\w+\@(\w+\.)+\w{2,3}$/
//var objRegExp  = /^.+@.+\..{2,3}$/
var objRegExp = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*\.(\w{2}|(com|net|org|edu|int|mil|gov|arpa|biz|aero|name|coop|info|pro|museum))$/
phoneRe = /^((\+\d{1,3}(-| )?\(?\d\)?(-| )?\d{1,3})|(\(?\d{2,3}\)?))(-| )?(\d{3,4})(-| )?(\d{4})(( x| ext)\d{1,5}){0,1}$/

  //check for valid email
  return objRegExp.test(strValue);
}


function validateUSDate( strValue ) {
	return checkDateENG(strValue);
}

function validateITADate( strValue ) {
	return checkDateITA(strValue);
}


function validateHHMM(strValue)
{
	
	p = strValue.replace('.',':').indexOf(':');

	/* Se non è presente o è in prima posizione */
	if (p == -1 || p == 0) return false;

    var hh = strValue.substring(0,p);

    var mm = strValue.substring(p + 1, p + 3);
    if (mm.length != 2) return false;
    
    if (validateInteger(hh) && validateInteger(mm)) {
        var h = parseInt(hh);
        var m = parseInt(mm);
        
        if (h < 0 || h > 23 || m < 0 || m > 60) return false;    
    
    } else return false;
    
	return true;
}



// VARIABLE DECLARATIONS
/************************************************************************/
var defaultEmptyOK = false
/************************************************************************/

function checkNum(str)
{
	if (str == "") {
		alert("Inserire un numero valido nel campo.")
		return false
	}
	for (i = 0; i < str.length; i++) {
		ch = str.substring(i, i + 1)
		if (ch != "," && ch != '.' && (ch < "0" || ch > "9")) {
			alert("Inserire un numero valido nel campo.")
			return false
		}
	}
	return true
}


function validateNum(t)
{
	if (!checkNum(t.value)) {
		t.value = ''
		t.focus()
		t.select()
	}
}

function isDigit (c)
{
  return ((c >= "0") && (c <= "9"))
}

function isSignedInteger (s)

{   if (isEmpty(s))
       if (isSignedInteger.arguments.length == 1) return defaultEmptyOK;
       else return (isSignedInteger.arguments[1] == true);

    else {
        var startPos = 0;
        var secondArg = defaultEmptyOK;

        if (isSignedInteger.arguments.length > 1)
            secondArg = isSignedInteger.arguments[1];

        // skip leading + or -
        if ( (s.charAt(0) == "-") || (s.charAt(0) == "+") )
           startPos = 1;
        return (isInteger(s.substring(startPos, s.length), secondArg))
    }
}

function isPositiveInteger (s)
{   var secondArg = defaultEmptyOK;

    if (isPositiveInteger.arguments.length > 1)
        secondArg = isPositiveInteger.arguments[1];

    // The next line is a bit byzantine.  What it means is:
    // a) s must be a signed integer, AND
    // b) one of the following must be true:
    //    i)  s is empty and we are supposed to return true for
    //        empty strings
    //    ii) this is a positive, not negative, number

    return (isSignedInteger(s, secondArg) && ( (isEmpty(s) && secondArg)  || (parseInt (s) > 0) ) );
}

function isNonnegativeInteger (s)
{   var secondArg = defaultEmptyOK;

    if (isNonnegativeInteger.arguments.length > 1) secondArg = isNonnegativeInteger.arguments[1];

    // The next line is a bit byzantine.  What it means is:
    // a) s must be a signed integer, AND
    // b) one of the following must be true:
    //    i)  s is empty and we are supposed to return true for
    //        empty strings
    //    ii) this is a number >= 0
    return (isSignedInteger(s, secondArg) && ( (isEmpty(s) && secondArg)  || (parseInt (s) >= 0) ) );
}


function makeArray(n) {
//*** BUG: If I put this line in, I get two error messages:
//(1) Window.length can't be set by assignment
//(2) daysInMonth has no property indexed by 4
//If I leave it out, the code works fine.
//   this.length = n;
   for (var i = 1; i <= n; i++) {
      this[i] = 0
   }
   return this
}

var daysInMonth = makeArray(12);
daysInMonth[1] = 31;
daysInMonth[2] = 29;   // must programmatically check this
daysInMonth[3] = 31;
daysInMonth[4] = 30;
daysInMonth[5] = 31;
daysInMonth[6] = 30;
daysInMonth[7] = 31;
daysInMonth[8] = 31;
daysInMonth[9] = 30;
daysInMonth[10] = 31;
daysInMonth[11] = 30;
daysInMonth[12] = 31;

function isEmpty(s)
{
  return ((s == null) || (s.length == 0))
}

function isInteger (s)
{   var i;
    if (isEmpty(s))
       if (isInteger.arguments.length == 1) return defaultEmptyOK;
       else return (isInteger.arguments[1] == true);

    // Search through string's characters one by one until we find a non-numeric character.
    // When we do, return false; if we don't, return true.
    for (i = 0; i < s.length; i++)
    {
        // Check that current character is number.
        var c = s.charAt(i);
        if (!isDigit(c)) return false;
    }
    // All characters are numbers.
    return true;
}


function isYear (s)
{   if (isEmpty(s))
       if (isYear.arguments.length == 1) return defaultEmptyOK;
       else return (isYear.arguments[1] == true);
    if (!isNonnegativeInteger(s)) return false;
    return ((s.length == 2) || (s.length == 4));
}

function isIntegerInRange (s, a, b)
{   if (isEmpty(s))
       if (isIntegerInRange.arguments.length == 1) return defaultEmptyOK;
       else return (isIntegerInRange.arguments[1] == true);

    // Catch non-integer strings to avoid creating a NaN below
    if (!isInteger(s, false)) return false;

    // Explicitly change the type to integer via parseInt (work on JavaScript 1.2)
    // and JavaScript 1.1 and before (which doesn't).
    var num = parseInt (s);
    return ((num >= a) && (num <= b));
}

function isMonth (s)
{   if (isEmpty(s))
       if (isMonth.arguments.length == 1) return defaultEmptyOK;
       else return (isMonth.arguments[1] == true);
    return isIntegerInRange (s, 1, 12);
}

function isDay (s)
{   if (isEmpty(s))
       if (isDay.arguments.length == 1) return defaultEmptyOK;
       else return (isDay.arguments[1] == true);
    return isIntegerInRange (s, 1, 31);
}

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 isDateFromYMD(year, month, day)
{   // catch invalid years (not 2- or 4-digit) and invalid months and days.
    if (!isMonth(month, false)) return false;
    if (!isDay(day, false)) return false;
    if (!isYear(year, false)) return false;

    // Explicitly change type to integer to make code work in both JavaScript 1.1 and JavaScript 1.2.
    var intYear = parseInt(year);
    var intMonth = parseInt(month);
    var intDay = parseInt(day);

    // catch invalid days, except for February
    if (intDay > daysInMonth[intMonth]) return false;

    if ((intMonth == 2) && (intDay > daysInFebruary(intYear))) return false;
    return true;
}

function checkDateITA(inDate)
{
	if (inDate == "") return true;
	p = inDate.indexOf('/');

	/* Se non è presente o è in prima posizione */
	if (p == -1 || p == 0) return false;

	q = inDate.indexOf('/', p + 1);

	/* Se non è presente o è contiguo alla prima barra */
	if (q == -1 || q == p+1) return false;

    var inDay = inDate.substring(0,p);
    if (inDay.substring(0,1) == "0" && inDay.length > 1)
       inDay = inDay.substring(1,inDay.length);

    var inMonth   = inDate.substring(p + 1, q);
    if (inMonth.substring(0,1) == "0" && inMonth.length > 1)
       inMonth = inMonth.substring(1,inMonth.length);


    var inYear  = inDate.substring(q + 1, inDate.length);
	return isDateFromYMD(inYear, inMonth, inDay);
}

function checkDateENG(inDate)
{
	if (inDate == "") return true;
	p = inDate.indexOf('/');

	/* Se non è presente o è in prima posizione */
	if (p == -1 || p == 0) return false;

	q = inDate.indexOf('/', p + 1);

	/* Se non è presente o è contiguo alla prima barra */
	if (q == -1 || q == p+1) return false;

    var inMonth = inDate.substring(0,p);
    if (inMonth.substring(0,1) == "0" && inMonth.length > 1)
       inMonth = inMonth.substring(1,inMonth.length);

    var inDay   = inDate.substring(p + 1, q);
    if (inDay.substring(0,1) == "0" && inDay.length > 1)
       inDay = inDay.substring(1,inDay.length);

    var inYear  = inDate.substring(q + 1, inDate.length);
	return isDateFromYMD(inYear, inMonth, inDay);
}




function validateUSZip( strValue ) {
/************************************************
DESCRIPTION: Validates that a string a United
  States zip code in 5 digit format or zip+4
  format. 99999 or 99999-9999
PARAMETERS: strValue - String to be tested for validity
RETURNS: True if valid, otherwise false.
*************************************************/
var objRegExp  = /(^\d{5}$)|(^\d{5}-\d{4}$)/;
 
  //check for valid US Zipcode
  return objRegExp.test(strValue);
}

function validateUSPhone( strValue ) {
/************************************************
DESCRIPTION: Validates that a string contains valid US phone pattern. Ex. (999) 999-9999 or (999)999-9999
PARAMETERS: strValue - String to be tested for validity
RETURNS: True if valid, otherwise false.
*************************************************/
  var objRegExp  = /^\([1-9]\d{2}\)\s?\d{3}\-\d{4}$/;
  //check for valid us phone with or without space between area code
  return objRegExp.test(strValue); 
}

function validateValue( strValue, strMatchPattern ) {
/************************************************
DESCRIPTION: Validates that a string a matches a valid regular expression value.
PARAMETERS:
   strValue - String to be tested for validity
   strMatchPattern - String containing a valid regular expression match pattern.
RETURNS: True if valid, otherwise false.
*************************************************/
var objRegExp = new RegExp( strMatchPattern);
 
 //check if string matches pattern
 return objRegExp.test(strValue);
}

// FORMAT: 

function rightTrim( strValue ) {
/************************************************
DESCRIPTION: Trims trailing whitespace chars.
PARAMETERS: strValue - String to be trimmed.  
RETURNS: Source string with right whitespaces removed.
*************************************************/
var objRegExp = /^([\w\W]*)(\b\s*)$/;
 
      if(objRegExp.test(strValue)) {
       //remove trailing a whitespace characters
       strValue = strValue.replace(objRegExp, '$1');
    }
  return strValue;
}

function leftTrim( strValue ) {
/************************************************
DESCRIPTION: Trims leading whitespace chars.
PARAMETERS: strValue - String to be trimmed
RETURNS: Source string with left whitespaces removed.
*************************************************/
var objRegExp = /^(\s*)(\b[\w\W]*)$/;
 
      if(objRegExp.test(strValue)) {
       //remove leading a whitespace characters
       strValue = strValue.replace(objRegExp, '$2');
    }
  return strValue;
}

function trimAll( strValue ) {
/************************************************
DESCRIPTION: Removes leading and trailing spaces.
PARAMETERS: Source string from which spaces will be removed;
RETURNS: Source string with whitespaces removed.
*************************************************/ 
 var objRegExp = /^(\s*)$/;

    //check for all spaces
    if(objRegExp.test(strValue)) {
       strValue = strValue.replace(objRegExp, '');
       if( strValue.length == 0)
          return strValue;
    }
    
   //check for leading & trailing spaces
   objRegExp = /^(\s*)([\W\w]*)(\b\s*$)/;
   if(objRegExp.test(strValue)) {
       //remove leading and trailing whitespace characters
       strValue = strValue.replace(objRegExp, '$2');
    }
  return strValue;
}

function removeCurrency( strValue ) {
/************************************************
DESCRIPTION: Removes currency formatting from source string.
PARAMETERS: strValue - Source string from which currency formatting will be removed;
RETURNS: Source string with commas removed.
*************************************************/
  var objRegExp = /\(/;
  var strMinus = '';
 
  //check if negative
  if(objRegExp.test(strValue)){
    strMinus = '-';
  }
  
  objRegExp = /\)|\(|[,]/g;
  strValue = strValue.replace(objRegExp,'');
  if(strValue.indexOf('$') >= 0){
    strValue = strValue.substring(1, strValue.length);
  }
  return strMinus + strValue;
}

function addCurrency( strValue ) {
/************************************************
DESCRIPTION: Formats a number as currency.
PARAMETERS: strValue - Source string to be formatted
REMARKS: Assumes number passed is a valid 
  numeric value in the rounded to 2 decimal 
  places.  If not, returns original value.
*************************************************/
  var objRegExp = /-?[0-9]+\.[0-9]{2}$/;
   
    if( objRegExp.test(strValue)) {
      objRegExp.compile('^-');
      strValue = addCommas(strValue);
      if (objRegExp.test(strValue)){
        strValue = '(' + strValue.replace(objRegExp,'') + ')';
      }
      return '$' + strValue;
    }
    else
      return strValue;
}

function removeCommas( strValue ) {
/************************************************
DESCRIPTION: Removes commas from source string.
PARAMETERS: strValue - Source string from which commas will be removed;
RETURNS: Source string with commas removed.
*************************************************/
  var objRegExp = /,/g; //search for commas globally
 
  //replace all matches with empty strings
  return strValue.replace(objRegExp,'');
}

function addCommas( strValue ) {
/************************************************
DESCRIPTION: Inserts commas into numeric string.
PARAMETERS:  strValue - source string containing commas.
RETURNS: String modified with comma grouping if
  source was all numeric, otherwise source is returned.
REMARKS: Used with integers or numbers with 2 or less decimal places.
*************************************************/
  var objRegExp  = new RegExp('(-?[0-9]+)([0-9]{3})'); 

    //check for match to search criteria
    while(objRegExp.test(strValue)) {
       //replace original string with first group match, 
       //a comma, then second group match
       strValue = strValue.replace(objRegExp, '$1,$2');
    }
  return strValue;
}

function removeCharacters( strValue, strMatchPattern ) {
/************************************************
DESCRIPTION: Removes characters from a source string based upon matches of the supplied pattern.
PARAMETERS: strValue - source string containing number.
RETURNS: String modified with characters matching search pattern removed
USAGE:  strNoSpaces = removeCharacters( ' sfdf  dfd', '\s*')
*************************************************/
 var objRegExp =  new RegExp( strMatchPattern, 'gi' );
 
 //replace passed pattern matches with blanks
  return strValue.replace(objRegExp,'');
}



/* effettua il controllo sulla partita Iva */
function ValidateVat(pi)
{
	if( pi == '' )  return true;
	if( pi.length != 11 )			/* effettua il test sul numero di caratteri inseriti */
		return false;
	validi = "0123456789";
	for( i = 0; i < 11; i++ ){		/*  verifica che tutti i caratteri inseriti siano ammissibili */
		if( validi.indexOf( pi.charAt(i) ) == -1 )
			return false;
	}
	s = 0;							/* calcola il checksun x verificare la validità dei dati inseriti */
	for( i = 0; i <= 9; i += 2 )
		s += pi.charCodeAt(i) - '0'.charCodeAt(0);
	for( i = 1; i <= 9; i += 2 ){
		c = 2*( pi.charCodeAt(i) - '0'.charCodeAt(0) );
		if( c > 9 )  c = c - 9;
		s += c;
	}
	if( ( 10 - s%10 )%10 != pi.charCodeAt(10) - '0'.charCodeAt(0) )
		return false;
	return true;					/* tutto ok */
}

/* effettua il controllo sulla validità del codice fiscale */
function ValidateCF(cf)
{
	var validi, i, s, set1, set2, setpari, setdisp;
	if( cf == '' )  return true;
	cf = cf.toUpperCase();
	if( cf.length != 16 )
		return false;
	validi = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
	for( i = 0; i < 16; i++ ){
		if( validi.indexOf( cf.charAt(i) ) == -1 )
			return false;
	}
	set1 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	set2 = "ABCDEFGHIJABCDEFGHIJKLMNOPQRSTUVWXYZ";
	setpari = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	setdisp = "BAKPLCQDREVOSFTGUHMINJWZYX";
	s = 0;
	for( i = 1; i <= 13; i += 2 )
		s += setpari.indexOf( set2.charAt( set1.indexOf( cf.charAt(i) )));
	for( i = 0; i <= 14; i += 2 )
		s += setdisp.indexOf( set2.charAt( set1.indexOf( cf.charAt(i) )));
	if( s%26 != cf.charCodeAt(15)-'A'.charCodeAt(0) )
		return false;
	return true;
}

