var currentCheckElement;
var currentForm;
var formValidationParams;

function InitFormValidation()
{
  currentCheckElement = null;
  formValidationParams = new Array();
}

function CheckForm(form)
{
  var i;
  currentForm = form;
  for (i=0;i<form.elements.length;i++) {
    if ( formValidationParams[form.elements[i].name] ) {
      var success = CheckElement( form.elements[i] );
      if ( !success ) {
        currentForm = null;
        return false;
      }
    }
  }
  currentForm = null;
  return true;
}

function CheckValueMandatory(value,elementParams)
{
  reqParams = elementParams[4].split("^");
   //reqParams[1] - contains the name of the element which this element's requirement is
   //               dependent on
   //reqParams[2] - list of values (seperated by # ) that if the dependent is set to mean that
   //               this element is required
  switch (reqParams[0].toUpperCase()) {
    case "TRUE":
      if (!value ) {
        alert("The field '" + elementParams[5] + "' is required");
        return false;
      }
      break;
    case "DEPENDENT":
      if (!value ) {
        depElement = currentForm.elements[reqParams[1]];
        depValues = reqParams[2].split("#");
        switch (depElement.type.toUpperCase()) {
          case "SELECT-ONE":
          case "TEXT":
            for (i in depValues) {
              if (depElement.value == depValues[i]) {
                alert("The field '" + elementParams[5] + "' is required");
                return false;
              }
            }
            break;
          case "CHECKBOX":
            if ( (depValues[0].toUpperCase() == "CHECKED" && depElement.checked) ||
                 (depValues[0].toUpperCase() == "UNCHECKED" && !(depElement.checked) ) ) {
              alert("The field '" + elementParams[5] + "' is required");
              return false;
            }
            break;
        }
      }
      break;
  }
  return true;
}

function CheckValueLength(value,elementParams)
{
  if (elementParams[1] && (value.length < parseInt(elementParams[1],10))) {
    alert("The value in field '" + elementParams[5] + "' is too short. You have "+value.length+" characters and the minimum is "+parseInt(elementParams[1],10)+" characters");
    return false;
  }
  else if (elementParams[2] && (value.length > parseInt(elementParams[2],10))) {
    alert("The value in field '" + elementParams[5] + "' is too long. You have "+value.length+" characters and the limit is "+parseInt(elementParams[2],10)+" characters");
    return false;
  }
  return true;
}

function CheckIntValueRange(value,elementParams)
{
  intval = parseInt(value,10);
  if (elementParams[1] && (intval < parseInt(elementParams[1],10))) {
    alert("The value in field '" + elementParams[5] + "' is too small. You have entered "+intval+" and the minimum is "+parseInt(elementParams[1],10));
    return false;
  }
  else if (elementParams[2] && (intval > parseInt(elementParams[2],10))) {
    alert("The value in field '" + elementParams[5] + "' is too large. You have entered "+intval+" and the maximum is "+parseInt(elementParams[2],10));
    return false;
  }
  return true;
}

function CheckFloatValueRange(value,elementParams)
{
  floatval = parseFloat(value);
  if (elementParams[1] && (floatval < parseFloat(elementParams[1]))) {
    alert("The value in field '" + elementParams[5] + "' is too small. You have entered "+floatval+" and the minimum is "+parseFloat(elementParams[1]));
    return false;
  }
  else if (elementParams[2] && (floatval > parseFloat(elementParams[2]))) {
    alert("The value in field '" + elementParams[5] + "' is too large. You have entered "+floatval+" and the maximum is "+parseFloat(elementParams[2]));
    return false;
  }
  return true;
}

function CheckDateValueRange(value,elementParams)
{
  dateval = GetDate(value);
  if (IsDate(elementParams[1]) && (dateval < GetDate(elementParams[1]))) {
    alert("The value in field '" + elementParams[5] + "' is too small. You have entered "+value+" and the minimum is "+elementParams[1]);
    return false;
  }
  else if (IsDate(elementParams[2]) && (dateval > GetDate(elementParams[2]))) {
    alert("The value in field '" + elementParams[5] + "' is too large. You have entered "+value+" and the maximum is "+elementParams[2]);
    return false;
  }
  return true;
}

function CheckElement(element) {
  if (currentCheckElement && currentCheckElement != element.name) return;
  currentCheckElement = element.name;
  var elementParams;
  var value;

  value = element.value;

  if (value != null) {
    value = Trim(value);
    elementParams = formValidationParams[element.name].split("|");

    switch (elementParams[0].toUpperCase()) {
      case "STR":
        if (!CheckValueMandatory(value,elementParams)) {
          element.focus();
          currentCheckElement = null;
          return false;
        }

        if (value) {
          if (!CheckValueLength(value,elementParams)) {
            element.focus();
            currentCheckElement = null;
            return false;
          }
           //check to make sure all characters in the string meet the optional character class
          switch (elementParams[3].toUpperCase()) {
            case 'NUMERIC':
              for (var i=0;i<value.length;i++) {
                if (value.charAt(i) < "0" || value.charAt(i) > "9") {
                  alert("The value in field '" + elementParams[5] + "' must contain only digits(0-9)");
                  element.focus();
                  currentCheckElement = null;
                  return false;
                }
              }
              break;

            case 'ALPHANUMERIC':
              value = value.toUpperCase();
              for (var i=0;i<value.length;i++) {
                if (value.charAt(i) < "0" ||
                    value.charAt(i) > "Z" ||
                    (value.charAt(i) > "9" && value.charAt(i) < "A")) {
                  alert("The value in field '" + elementParams[5] + "' must contain only digits (0-9) and letters(a-z,A-Z)");
                  element.focus();
                  currentCheckElement = null;
                  return false;
                }
              }
              break;

            case 'ALPHA':
              value = value.toUpperCase();
              for (var i=0;i<value.length;i++) {
                if (value.charAt(i) > "Z" || value.charAt(i) < "A") {
                  alert("The value in field '" + elementParams[5] + "' must contain only letters(a-z,A-Z)");
                  element.focus();
                  currentCheckElement = null;
                  return false;
                }
              }
              break;
          }
        }
        break;

      case "INT":
        if (!CheckValueMandatory(value,elementParams)) {
          element.focus();
          currentCheckElement = null;
          return false;
        }

        if (value) {
           //make sure value is an integer
          if (!(IsInt(value))) {
            alert("The value in field '" + elementParams[5] + "' must be a integer number");
            element.focus();
            currentCheckElement = null;
            return false;
          }

          if (!CheckIntValueRange(value,elementParams)) {
            element.focus();
            currentCheckElement = null;
            return false;
          }
        }
        break;

      case "FLOAT":
        if (!CheckValueMandatory(value,elementParams)) {
          element.focus();
          currentCheckElement = null;
          return false;
        }

        if (value) {
           //make sure the value looks like a floating point number
          if (!(IsFloat(value))) {
            alert("The value in field '" + elementParams[5] + "' must be a decimal number");
            element.focus();
            currentCheckElement = null;
            return false;
          }

          if (!CheckFloatValueRange(value,elementParams)) {
            element.focus();
            currentCheckElement = null;
            return false;
          }
        }
        break;

      case "DATE":
        if (!CheckValueMandatory(value,elementParams)) {
          element.focus();
          currentCheckElement = null;
          return false;
        }

        if (value) {
          if (!(FormatDate(element))) {
            alert("The value in field '" + elementParams[5] + "' is not a valid date (MM/DD/YYYY)");
            element.focus();
            currentCheckElement = null;
            return false;
          }

          if (!CheckDateValueRange(value,elementParams)) {
            element.focus();
            currentCheckElement = null;
            return false;
          }
        }
        break;

      case "TIME":
        if ( ! CheckValueMandatory( value, elementParams ) ) {
          element.focus();
          currentCheckElement = null;
          return false;
        }

        if ( element.value )  {
          if ( ! FormatTime( element ) )  {
            alert( "The value in field '" + elementParams[5] + "' is not a valid time (HH:MM AM/PM)" );
            element.focus();
            currentCheckElement = null;
            return false;
          }
          if ( ! CheckTimeRange( element.value, elementParams ) )  {
            element.focus();
            currentCheckElement = null;
            return false;
          }
        }
        break;
    }
  }
  currentCheckElement = null;
  return true;
}

function Trim(str)
{
  if (!str.length) return;

  //trim leading spaces
  var i = 0;
  while (str.charAt(i) == ' ')
    i++;
  if ( i )
    str = str.substr( i );

  //trim trailing spaces
  i = str.length - 1;
  while ( str.charAt( i ) == ' '  &&  i >= 0 )
    i--;
  if ( i >= 0  &&  i != str.length - 1 )
    str = str.substr( 0, i );

  return(str);
}

function IsInt(str) //returns true if str contains only digits and commas
{
  var i;
  var isNegative = false;
  for (i=0;i<str.length;i++) {
    if (!( (str.charAt(i) <= '9' && str.charAt(i) >= '0') ||
           (str.charAt(i) == '-' && i == 0) ) )
      return(false);
    else if (str.charAt(i) == '-')
      isNegative = true;
  }
  if (isNegative && str.length < 2)
    return false;
  return(true);
}

function IsFloat(str) //returns true if str contains only digits, decimal period, and commas
{
  var hasDecimalDot = false;
  var isNegative = false;
  for (var i=0;i<str.length;i++) {
    if (!( (str.charAt(i) <= '9' && str.charAt(i) >= '0') ||
           (str.charAt(i) == '-' && i == 0)  ||
           (str.charAt(i) == '.' && !hasDecimalDot) ) )
      return(false);
    else if (str.charAt(i) == '-')
      isNegative = true;
    else if (str.charAt(i) == '.')
      hasDecimalDot = true;
  }
  if (isNegative && str.length < 2)
    return false;
  return(true);
}

function IsLeapYear(year)
{
  year = parseInt(year,10);
  if ( (year%4) != 0 )           //  or:    if ( year%4 )
    return false;                //  means: if year is not divisible by 4
  else if ( (year%400) == 0 )    //  or:    if ( !(year%400) )
    return true;                 //  means: if year is divisible by 400
  else if ( (year%100) == 0 )    //  or:    if ( !(year%100) )
    return false;                //  means: if year is divisible by 100
  else                           //  (but not by 400, since that case
    return true;                 //  considered already)
}


function FormatDate(element) {
  dateParts = element.value.split("/");

  if (dateParts.length == 1)
    dateParts = element.value.split("-");

  if (dateParts.length == 2) {
    currDate = new Date();
    dateParts[2] = currDate.getFullYear();
  }

  if (dateParts.length != 3)
    return(false);

  if (dateParts[2].length == 2) {
    dateParts[2] = "20" + dateParts[2];
  }

  dateParts[0] = parseInt(dateParts[0],10);
  dateParts[1] = parseInt(dateParts[1],10);
  dateParts[2] = parseInt(dateParts[2],10);

  if (IsValidDate(dateParts[0],dateParts[1],dateParts[2])) {
    element.value = '' + dateParts[0] + '/' + dateParts[1] + '/'  + dateParts[2];
    return true;
  }
  else
    return false;
}

function IsDate(str)
{
  var dateParts;

  dateParts = str.split("/");

  if (dateParts.length != 3)
    return(false);

  dateParts[0] = parseInt(dateParts[0],10);
  dateParts[1] = parseInt(dateParts[1],10);
  dateParts[2] = parseInt(dateParts[2],10);

  return IsValidDate(dateParts[0],dateParts[1],dateParts[2]);
}

function IsValidDate(month,day,year)
{
  if (month < 1 || month > 12)
    return false;

  if (year < 1000 || year > 9999)
    return false;

  switch (month) {
    case 1:
    case 3:
    case 5:
    case 7:
    case 8:
    case 10:
    case 12:
      if (day < 1 || day > 31)
        return false;
      break;
    case 4:
    case 6:
    case 9:
    case 11:
      if (day < 1 || day > 30)
        return false;
      break;
    case 2:
      if (day < 1 || day > (IsLeapYear(year) ? 29 : 28))
        return false;
      break;
  }
  return true;
}

function GetDate(str)
{
  var dateParts;
  dateParts = str.split("/");
  return new Date(parseInt(dateParts[2],10),parseInt(dateParts[0],10)-1,parseInt(dateParts[1],10));
}


function FormatTime( element )  {
  var t = Trim( element.value.toUpperCase() );
  var i, hour, minute, meridiem;

  if ( ( i = t.indexOf( 'AM' ) ) != -1 ) {
    meridiem = 'AM';
    t = Trim( t.substring( 0, i-1 ) );
  }
  else if ( ( i = t.indexOf( 'PM' ) ) != -1 ) {
    meridiem = 'PM';
    t = Trim( t.substring( 0, i-1 ) );
  }

  timeParts = element.value.split( ':' );
  if ( timeParts.length > 2 )
    return false;
  hour = parseInt( timeParts[0], 10 );
  if ( ! ( hour >= 0  &&  hour <= 23 ) )
    return false;

  if ( timeParts.length == 2  &&  timeParts[1].length > 0 ) {
    minute = parseInt( timeParts[1], 10 );
    if ( ! ( minute >= 0  &&  minute <= 59 ) )
      return false;
  }
  else
    minute = 0;

  if ( hour > 12 )  {
    hour     -= 12;
    meridiem  = 'PM';
  }
  else if ( ! meridiem )  {
    meridiem = 'AM';
  }

  if ( hour == 0 )
    hour = 12;

  if ( minute < 10 )
    minute = '0' + minute;

  element.value = '' + hour + ':' + minute + meridiem;
  return true;
}

function hmToTimeString( h, m )  {
  var s;
  if ( m < 10 ) m = '' + '0' + m;
  if ( h >= 12 )  {
    s = '' + ( h - 12 ) + ':' + m + 'PM';
  }
  else  {
    if ( h == 0 )
      s = '12';
    else
      s = '' + h;
    s = '' + s + ':' + m + 'AM';
  }
  return s;
}

function CheckTimeRange( value, elementParams ) {
  var hour, minute, h, m, i;
  i = value.indexOf( ':' );
  hour     = parseInt( value.substring( 0, i ), 10 );
  minute   = parseInt( value.substring( i+1, i+3 ), 10 );
  if ( value.substring( i+3 ) == 'AM' ) {
    if ( hour == 12 ) hour = 0;
  }
  else  {
    if ( hour < 12 ) hour += 12;
  }

  if ( elementParams[1] ) {
    h = parseInt( elementParams[1].substring( 0, 2 ), 10 );
    m = parseInt( elementParams[1].substring( 3, 5 ), 10 );
    if ( hour < h  ||  ( hour == h  &&  minute < m ) ) {
      alert(   "The time in field '" + elementParams[5]
             + "' is earlier than the earliest time allowed, "
             + hmToTimeString( h, m )
           );
      return false;
    }
  }

  if ( elementParams[2] ) {
    h = parseInt( elementParams[2].substring( 0, 2 ), 10 );
    m = parseInt( elementParams[2].substring( 3, 5 ), 10 );
    if ( hour > h  ||  ( hour == h  &&  minute > m ) ) {
      alert(   "The time in field '" + elementParams[5]
             + "' is later than the latest time allowed, "
             + hmToTimeString( h, m )
           );
      return false;
    }
  }

  return true;
}


function ClearFormElements()  {
  for ( var f=0; f<document.forms.length; f++ ) {
    var e = document.forms[f].elements;
    for ( var i=0; i<e.length; i++ ) {
      if ( e[i].type == "text"  ||  e[i].type == "textarea"  ||  e[i].type == "password" ) {
        e[i].value = "";
      }
      else if ( e[i].type == "select-one" ) {
        e[i].selectedIndex = 0;
      }
      else if ( e[i].type == "checkbox" )  {
        e[i].checked = false;
      }
    }
  }
}
