//
// Contains validation routines for numbers.
//
  // Validates if the field contains a valid decimal number of the correct precision and allowed sign.
  // This function can deal with numbers of the following format: -...999999.9999... where ... means
  // that the number can go on in either direction as long as required. If it is a null value or empty
  // string, it is considered valid.
  //
  // @param value the value to be considered as a decimal.
  // @param allowNeg if set to true, it allows negative numbers, else it does not.
  // @param intLen number of digits allowed on the left hand side of the decimal point. Set this
  //   to a negative number for no limit.
  // @param decLen number of digits allowed to the right hand side of the decimal point. Set this
  //   to a negative number for no limit.
  //
  // @return null if it is a decimal of the correct precision and allowed sign, otherwise an error message.
  function isDecNegPrec(value, allowNeg, intLen, decLen)
  {
    var result = null;
    var numbers = "0123456789";
    value = trim(value);
    if (value != null && value != "" && value.length > 0)
    {
       // Check to see if the number is negative and if that is allowed.
       var hasNegSign = (value.charAt(0) == '-');
       if (allowNeg || !hasNegSign)
       {
         var intStart = 0;
         if (hasNegSign)
         {
           intStart = 1;
         }
         var decPos = value.indexOf(".");
         // If there is no decimal, set the position one after the last number.
         if (decPos < 0)
         {
           decPos = value.length;
         }
         var intValid = false;
         if (decPos > intStart)
         {
           // Now, count the number of integers.
           var intCnt = 0;
           for (var i=intStart; i < decPos; i++)
           {
             // Initialize this to false. If it gets through everything okay, it will go to true.
             intValid = false; 
             // Try to see if the character is a number...
             var numMatch = (numbers.indexOf(value.charAt(i)) > -1);

             // If it is not a number, this is invalid.
             if (!numMatch)
             {
               result = "Integer part of the number contains a character that is not a number.";
               break;
             }
             
             // If this is a number, increase the number of integers found.
             if (numMatch)
             {
               intCnt++;

               // If there are more integers than allowed...
               if (intLen >= 0 && intCnt > intLen)
               {
                  result = "The number of digits in the integer exceed the max allowed: " + intLen;
                  break;
               }
             }
             // The number is in a valid state.
             intValid = true; 
             result = null;
           }
         }
         // This allows the user to enter numbers like .5 instead of having to type 0.5.
         else
         {
           intValid = true;
         }

         // Initialize the decimal valid, by testing if the number just ends with a decimal point. 
         var decValid = (value.charAt(value.length-1) != '.'); 
         // Do not bother processing further if the integer is not valid.
         if (result == null && intValid && decValid && decPos < value.length)
         {
           var decCnt = 0;
           for (var j=decPos+1; j < value.length; j++)
           {
             decValid = false;
             // Try to see if the character is a number...
             if (numbers.indexOf(value.charAt(j)) > -1)
             {
               decCnt++;
               if (decLen >= 0 && decCnt > decLen)
               {
                 result = "The number of digits in the decimal part of the number exceeds the max allowed: " + decLen; 
                 break;
               }
               decValid = true;
             }
             else
             {
               result = "The decimal part of the number contains non-numeric characters.";
               break;
             }
           }
         }
       }
       else
       {
         result = "Negative numbers are not allowed.";
       }
    }
    return result;
  }

  // AMS 10/23/2001 Moved this to its own function - basically had to disable allowing commas as the
  //   server code did not correctly take care of reformatting data with commas in it.
  // 
  // Validates if the field contains a valid decimal number of the correct precision and allowed sign.
  // This function can deal with numbers of the following format: -...999,999.9999... where ... means
  // that the number can go on in either direction as long as required. If it is a null value or empty
  // string, it is considered valid.
  //
  // @param value the value to be considered as a decimal.
  // @param allowNeg if set to true, it allows negative numbers, else it does not.
  // @param intLen number of digits allowed on the left hand side of the decimal point. Set this
  //   to a negative number for no limit.
  // @param decLen number of digits allowed to the right hand side of the decimal point. Set this
  //   to a negative number for no limit.
  //
  // @return null if it is a decimal of the correct precision and allowed sign, otherwise an error message.
  function isCommaDecNegPrec(value, allowNeg, intLen, decLen)
  {
    var result = null;
    var numbers = "0123456789";
    value = trim(value);
    if (value != null && value != "" && value.length > 0)
    {
       // Check to see if the number is negative and if that is allowed.
       var hasNegSign = (value.charAt(0) == '-');
       if (allowNeg || !hasNegSign)
       {
         var intStart = 0;
         if (hasNegSign)
         {
           intStart = 1;
         }
         var decPos = value.indexOf(".");
         // If there is no decimal, set the position one after the last number.
         if (decPos < 0)
         {
           decPos = value.length;
         }
         var intValid = false;
         if (decPos > intStart)
         {
           // Now, count the number of integers and make sure that the # of digits before
           // any commas is correct.
           var commaDigits = 0;
           var intCnt = 0;
           var commasExist = (value.indexOf(",") > -1);
           var commaGroups = 0;
           for (var i=intStart; i < decPos; i++)
           {
             // Initialize this to false. If it gets through everything okay, it will go to true.
             intValid = false; 
             // Try to see if the character is a number...
             var numMatch = (numbers.indexOf(value.charAt(i)) > -1);
             // If not, try to see if it is a comma.
             var commaMatch = (value.charAt(i) == ','); 

             // If it is not a comma or number, this is invalid.
             if (!numMatch && !commaMatch)
             {
               result = "Integer part of the number contains a character that is not a number or a comma.";
               break;
             }
             
             // If the first character is a comma, this is invalid.
             if (commasExist && i == intStart && commaMatch)
             {
               result = "Numbers can not start with commas.";
               break;
             }

             // If this is a number, increase the number of integers found and the number
             // of digits found between commas.
             if (numMatch)
             {
               intCnt++;
               commaDigits++;

               // If there are more integers than allowed...
               if (intLen >= 0 && intCnt > intLen)
               {
                  result = "The number of digits in the integer exceed the max allowed: " + intLen;
                  break;
               }

               // If there are commas and we have more than three digits in a row
               if (commasExist && (commaDigits > 3))
               {
                  result = "More than three digits appear between commas.";
                  break;
               }             
             }
             if (commaMatch)
             {
               // If we are after the first comma, each group of numbers must be 3 between commas.
               if (commaGroups > 0 && commaDigits != 3)
               {
                  result = "There are less than three digits between two commas.";
                  break;
               }             
               commaGroups++;
               commaDigits = 0;
             }

             // If there is at least on comma and either it has not been hit yet or it is after
             // the first comma and there are less than three digits so far, it is in an invalid
             // state (so if there are no more digits, it will come back as false). But since it
             // may become valid, we do not break at this point.
             if (commasExist && ((commaGroups < 1) || (commaGroups > 0 && commaDigits < 3)))
             {
               intValid = false; 
               result = "There are not three digits after the last comma.";
             }
             // Otherwise, the number is in a valid state.
             else
             {
               intValid = true; 
               result = null;
             }
           }
         }
         // This allows the user to enter numbers like .5 instead of having to type 0.5.
         else
         {
           intValid = true;
         }

         // Initialize the decimal valid, by testing if the number just ends with a decimal point. 
         var decValid = (value.charAt(value.length-1) != '.'); 
         // Do not bother processing further if the integer is not valid.
         if (result == null && intValid && decValid && decPos < value.length)
         {
           var decCnt = 0;
           for (var j=decPos+1; j < value.length; j++)
           {
             decValid = false;
             // Try to see if the character is a number...
             if (numbers.indexOf(value.charAt(j)) > -1)
             {
               decCnt++;
               if (decLen >= 0 && decCnt > decLen)
               {
                 result = "The number of digits in the decimal part of the number exceeds the max allowed: " + decLen; 
                 break;
               }
               decValid = true;
             }
             else
             {
               result = "The decimal part of the number contains non-numeric characters.";
               break;
             }
           }
         }
       }
       else
       {
         result = "Negative numbers are not allowed.";
       }
    }
    return result;
  }

  // Validates if the field contains a valid decimal number of the correct precision.
  //
  // @param value the value to be considered as a decimal.
  // @param intLen number of digits allowed on the left hand side of the decimal point. Set this
  //   to a negative number for no limit.
  // @param decLen number of digits allowed to the right hand side of the decimal point. Set this
  //   to a negative number for no limit.
  //
  // @return null if it is a decimal of the correct precision, otherwise an error message.
  function isDecPrec(value, intLen, decLen)
  {
    return isDecNegPrec(value, true, intLen, decLen);
  }

  // Validates if the field contains a valid decimal number of an allowed sign.
  //
  // @param value the value to be considered as a decimal.
  // @param allowNeg if set to true, it allows negative numbers, else it does not.
  //
  // @return null if it is a decimal of the allowed sign, otherwise an error message.
  function isDecNeg(value, allowNeg)
  {
    return isDecNegPrec(value, allowNeg, -1, -1);
  }

  // Validates if the field contains a valid decimal number.
  //
  // @param value the value to be considered as a decimal.
  //
  // @return null if it is a decimal, otherwise an error message.
  function isDec(value)
  {
    return isDecNegPrec(value, true, -1, -1);
  }

  // Validates if the field contains a valid integer (no decimal, but negative allowed if specified and
  //  precision can be specified).
  //
  // @param value the value to be considered as an integer.
  // @param allowNeg if set to true, it allows negative numbers, else it does not.
  // @param intLen number of digits allowed on the left hand side of the decimal point. Set this
  //   to a negative number for no limit.
  //
  // @return null if it is an integer of the correct sign and length, otherwise an error message.
  function isIntNeg(value, allowNeg, intLen)
  {
    return isDecNegPrec(value, allowNeg, intLen, 0);
  }

  // Validates if the field contains a valid integer (no decimal, but negative allowed if specified).
  //
  // @param value the value to be considered as an integer.
  // @param allowNeg if set to true, it allows negative numbers, else it does not.
  //
  // @return null if it is an integer of the correct sign, otherwise an error message.
  function isIntNeg(value, allowNeg)
  {
    return isDecNegPrec(value, allowNeg, -1, 0);
  }

  // Validates if the field contains a valid integer (no decimal, but negative allowed).
  //
  // @param value the value to be considered as an integer.
  //
  // @return null if it is an integer, otherwise an error message.
  function isInt(value)
  {
    return isDecNegPrec(value, true, -1, 0);
  }


  // Formats a number into currency (#.##) format.
  function formatNumber(s) {
    s = Math.round(s*100)/100;
    var intPart = Math.floor(s);
    s = s.toString();
    var fracPart;

    var div = s.indexOf('.');
    if (div == -1) {
      fracPart = ".00";
    } else {
      fracPart = (Math.round(parseFloat(s.substr(div))*100)/100).toString();
      if (fracPart.charAt(0)=="0") fracPart = fracPart.substr(1);
      if (fracPart.length==2) fracPart += '0';
    }

    return intPart.toString()+fracPart;
  }
