package com.papajo.examples.util;

import org.apache.regexp.*;

public final class StringValidator
{
/*
  Future features that would probably be useful:

  public boolean isValidPostalCode(String zip)
  public boolean checkPostalCode(String zip, boolean emptyOK)

  public boolean isValidStateCode(String abbrev)
  public boolean checkStateCode(String stateAbbrev, boolean emptyOK)

  public boolean isValidUSPhone(String phone)
  public boolean checkUSPhone(String phone, boolean emptyOK)

  public boolean isValidI18LPhone(String phone)
  public boolean checkI18LPhone(String phone, boolean emptyOK)
*/

  /**
   *  Check that String email is a valid email address.
   *  emptyOK=true indicates that an empty String is valid
   *  for this test.
   */
  public boolean checkEmail(String email, boolean emptyOK)
  {
    if ((emptyOK == true) && (isEmpty(email))) return true;
    else if(isValidEmail(email)) return true;
    else return false;
  }

  /**
   *  Check that String date is a valid date.
   *  emptyOK=true indicates that an empty String is valid
   *  for this test.
   */
  public boolean checkDate(String date, boolean emptyOK)
  {
    if ((emptyOK == true) && (isEmpty(date))) return true;
    else if(isValidDate(date)) return true;
    else return false;
  }

  /**
   *  Check that String date is a valid date.
   *  emptyOK=true indicates that an empty String is valid
   *  for this test.
   */
  public boolean checkInteger(String s, boolean emptyOK)
  {
    if ((emptyOK == true) && (isEmpty(s))) return true;
    else if(isValidInteger(s)) return true;
    else return false;
  }

  /**
   * 1. Checks for the following date formats:
   *    'MM/dd/yyyy', 'MM.dd.yyyy' and 'MM-dd-yyyy'
   *
   * 2. Checks that the date is a valid date.
   *    (ie. accounts for number of days in a month,
   *     leap years, etc..)
   */
  public boolean isValidDate(String s)
  {
    boolean valid = true;
    if (s == null)
      valid = false;
    else
    {
      int day   = 0;
      int month = 0;
      int year  = 0;

      String dtMask = "^(\\d{1,2})(\\/|-|\\.)(\\d{1,2})\\2(\\d{4})$";
                      //|   1    ||    2    ||   3    |---|  4   |
      int monthIndex = 1;  // NOTE: xxx_indx variables
      int dayIndex   = 3;  // denote the posistion of tagged
      int yearIndex  = 4;  // expression preserved by their
      RE reDate = null;
      // ignoring exceptions on purpose
      try { reDate = new RE(dtMask); } catch (RESyntaxException e){;}
      if ( ! reDate.match(s) )
        valid = false;

      try { month = Integer.parseInt(reDate.getParen(monthIndex)); } catch (Exception e) {;}
      try { day   = Integer.parseInt(reDate.getParen(dayIndex  )); } catch (Exception e) {;}
      try { year  = Integer.parseInt(reDate.getParen(yearIndex )); } catch (Exception e) {;}

      valid = isMonthInRange(month) && isDayInRange(day, month, year);
    }
    return valid;
  }


  /**
   * Checks to see if a String is null or all spaces.
   */
  public boolean isEmpty(String s)
  {
    return ((s == null) || (s.trim().length() == 0));
  }

  /**
   * Checks to see if a String is a valid email address.
   */
  public boolean isValidEmail(String email)
  {
    if(email == null) return false;
    try
    {
      RE reEmail = new RE("^.+\\@.+\\..+$");
      if (reEmail.match(email) )
        return true;
      else
        return false;
    }
    catch(RESyntaxException e)
    {
      System.out.println(e);
      return false;
    }
  }

  /**
   * Checks to see if a String can be safely converted to a
   * primitive byte.
   */
  public boolean isValidByte(String s)
  {
    if(s == null)
      return false;
    try
    {
      Byte.parseByte(s);
      return true;
    }
    catch (NumberFormatException e)
    {
      return false;
    }
  }

  /**
   * Checks to see if a String can be safely converted to a
   * primitive short.
   */
  public boolean isValidShort(String s)
  {
    if(s == null)
      return false;
    try
    {
      Short.parseShort(s);
      return true;
    }
    catch (NumberFormatException e)
    {
      return false;
    }
  }


  /**
   * Checks to see if a String can be safely converted to a
   * primitive int.
   */
  public boolean isValidInteger(String s)
  {
    if(s == null)
      return false;
    try
    {
      Integer.parseInt(s);
      return true;
    }
    catch (NumberFormatException e)
    {
      return false;
    }
  }

  /**
   * Checks to see if a String can be safely converted to a
   * primitive long.
   */
  public boolean isValidLong(String s)
  {
    if(s == null)
      return false;
    try
    {
      Long.parseLong(s);
      return true;
    }
    catch (NumberFormatException e)
    {
      return false;
    }
  }

  /**
   * Checks to see if a String can be safely converted to a
   * primitive float.
   */
  public boolean isValidFloat(String s)
  {
    if(s == null)
      return false;
    try
    {
      Float.parseFloat(s);
      return true;
    }
    catch (NumberFormatException e)
    {
      return false;
    }
  }

  /**
   * Checks to see if a String can be safely converted to a
   * primitive double.
   */
  public boolean isValidDouble(String s)
  {
    if(s == null)
      return false;
    try
    {
      Double.parseDouble(s);
      return true;
    }
    catch (NumberFormatException e)
    {
      return false;
    }
  }



  /**
   * Checks to see if an int is in range for
   * representing a month. (1-12)
   */
  private boolean isMonthInRange(int month)
  {
    if ((month < 1) ||  (month > 12))
      return false;
    else
      return true;
  }

  /**
   * Checks to see if an date can actually exist.
   */
  private boolean isDayInRange(int day, int month, int year)
  {
    if  ( (day < 1) || (day > getDaysInMonth(month, year)) )
      return false;
    else
      return true;
  }

  /**
   * Determines how many days are in a month for a given year.
   */
  private int getDaysInMonth(int month, int year)
  {
    int daysInMonth = 0;
    switch (month)
    {
      case 1 :
      case 3 :
      case 5 :
      case 7 :
      case 8 :
      case 10 :
      case 12 :
      daysInMonth = 31;
      break;
      case 4 :
      case 6 :
      case 9 :
      case 11 :
      daysInMonth = 30;
      break;
      case 2 :
      // Test for leap year
      if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
        daysInMonth = 29;
      else
        daysInMonth = 28;
      break;
    }
    return daysInMonth;
  }
}