/********************************************************************
 * Copyright © 2005 VHA. All rights reserved
 ********************************************************************/
package gov.va.med.esr.ui.common.util;

// Java Classes
import java.text.DateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.servlet.http.HttpServletRequest;



// Library Classes
import org.apache.commons.validator.EmailValidator;
import org.apache.commons.validator.Field;
import org.apache.commons.validator.ValidatorAction;
import org.apache.commons.validator.util.ValidatorUtils;
import org.apache.struts.action.ActionMessages;
import org.apache.struts.validator.FieldChecks;
import org.apache.struts.validator.Resources;



// Framework Classes
import gov.va.med.fw.util.StringUtils;
import gov.va.med.esr.common.model.person.id.VPIDEntityKeyImpl;


/**
 * Custom validation rules methods.
 *
 * @author DNS   CHENB
 * @author Muddaiah Ranga (Added validatePassword method).
 * @author Priya (Added validatePastDate method).
 * @author Andrew Pach
 */
public class EdbStrutsValidator extends FieldChecks
{
    private static final long serialVersionUID = -5044031726509231080L;

    public static final String DEFAULT_CURRENT_YEAR_VAR = "defaultCurrentYear";
    public static final String PASSWORD_REG_EXP =
        "^(?=.*\\d)(?=.*[a-z])(?=.*[!@#$%^&*()_+=-])(?=.*[A-Z]).{8,32}$";
    public static final String PASSWORD_REG_EXP_LCNS =
        "^(?=.*\\d)(?=.*[a-z])(?=.*[!@#$%^&*()_+=-]).{8,32}$";
    public static final String PASSWORD_REG_EXP_LCUCS =
        "^(?=.*[a-z])(?=.*[!@#$%^&*()_+=-])(?=.*[A-Z]).{8,32}$";
    public static final String PASSWORD_REG_EXP_LCUCN =
        "^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,32}$";
    public static final String PASSWORD_REG_EXP_UCNS =
        "^(?=.*\\d)(?=.*[!@#$%^&*()_+=-])(?=.*[A-Z]).{8,32}$";

    public static final String PATTERN_SSN = "([0-9]{9})"; // #########
    public static final String PATTERN_FORMATTED_SSN = "([0-9]{3})-([0-9]{2})-([0-9]{4})"; // ###-##-####

    public static final String PATTERN_NAME = "^[a-zA-Z-\\s]{1,25}$"; // #########
    public static final String PATTERN_REGEX = "[\\s\\w.]*"; // #########

    public static final String PATTERN_ALPHANUMERIC = "[a-zA-Z0-9]*"; // #########
    public static final String PATTERN_REPORT_PARA = "[a-zA-Z0-9////:\\s,]*"; // #########
    public static final String PATTERN_CITY = "[a-zA-Z'\\s]*"; // #########
    public static final String PATTERN_Alpha = "[a-zA-Z]*"; // #########
    public static final String PATTERN_INVOCATIONARGS = "[a-zA-Z0-9\\s|,=-]*"; // #########
    public static final String PATTERN_EMAILDIST = "[a-zA-Z0-9,@.\\-\\_]*"; // #########
    public static final String PATTERN_EMAIL = "^[_a-zA-Z0-9-]@.]*"; // #########
    public static final String PATTERN_PHONE = "\\([\\d][\\d][\\d]\\)[\\d][\\d][\\d]-[\\d][\\d][\\d][\\d]"; // #########




    public EdbStrutsValidator()
    {
        super();
    }

    /**
     * Validate SSN
     * @return
     */
    public static boolean validateSSN(Object bean, ValidatorAction va,
            Field field, ActionMessages errors,
            HttpServletRequest request) {

        String ssn = ValidatorUtils.getValueAsString(bean, field.getProperty());

        if (StringUtils.isEmpty(ssn)) return true;
        //check for the existence of at least one combination
        if (ssn.matches(PATTERN_SSN) ||   //unformatted ssn
                ssn.matches(PATTERN_FORMATTED_SSN)){ //formatted ssn

        	//validate for valid number pattern
            String ssnStr = ssn.replaceAll("-", "");
            String[] startWiths = new String[] {"000", "00000"};
            if (ssnStr.length() != 9
                    || !StringUtils.isNumeric(ssnStr)
                    || StringUtils.isSameCharString(ssnStr)
                    || StringUtils.startsWith(ssnStr, startWiths)
                    || ssnStr.startsWith("00", 3)
                    || ssnStr.endsWith("0000")
                    || "123456789".equals(ssnStr)) {
                errors.add(field.getKey(),Resources.getActionMessage(request, va, field));
                return false;
            }
            return true;
        }
        else {
            errors.add(field.getKey(),Resources.getActionMessage(request, va, field));
            return false;
        }
    }

    public static boolean validateComments(Object bean, ValidatorAction va,
	            Field field, ActionMessages errors,
	            HttpServletRequest request)
	    {
	    	 // Get the field value
	        String commentStr = ValidatorUtils.getValueAsString(bean, field.getProperty());

	        // If no value was specified, assume that the field is valid
	        if (StringUtils.isEmpty(commentStr))
	        {
	            return true;
	        }
	        if(commentStr.length()>200)
	        {
	        	 errors.add(field.getKey(),Resources.getActionMessage(request, va, field));
	             return false;
	        }
	        return true;
	    }

    //CCR13875 changes
    public static boolean validateCommentsOther(Object bean, ValidatorAction va,
            Field field, ActionMessages errors,
            HttpServletRequest request)
    {
         // Get the field value
        String clVerifiedMethod = field.getVarValue("chosenVerification");
        String isVerifiedOther = ValidatorUtils.getValueAsString(bean, clVerifiedMethod);
        String commentStr = ValidatorUtils.getValueAsString(bean, field.getProperty());

        if((isVerifiedOther == "true") && (StringUtils.isEmpty(commentStr))){
            errors.add(field.getKey(),Resources.getActionMessage(request, va, field));
            return false;
        }

        return true;
    }

    /**
     * Validate VPID
     * @return
     */
    public static boolean validateVPID(Object bean, ValidatorAction va,
            Field field, ActionMessages errors,
            HttpServletRequest request) {

        String vpid = ValidatorUtils.getValueAsString(bean, field.getProperty());

        if (StringUtils.isEmpty(vpid)) return true;

        try {
            VPIDEntityKeyImpl.getLongVPID(vpid);
            return true;
        }catch (Exception e){
            errors.add(field.getKey(),Resources.getActionMessage(request, va, field));
            return false;
        }
    }
	public static boolean validateDateAfter(Object bean, ValidatorAction va,
			Field field, ActionMessages errors,
			HttpServletRequest request) {
		String value =
			ValidatorUtils.getValueAsString(bean, field.getProperty());
		String sProperty2 = field.getVarValue("secondDate");
		String value2 = ValidatorUtils.getValueAsString(bean, sProperty2);

		Date date1 = null;
		Date date2 = null;
		DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
		try
		{
			date1 = df.parse(value);
			date2 = df.parse(value2);
		}
		catch (Exception e)
		{
			//No need to compare, validate format
		}
		if (date1 != null && date2 != null) {
			try {
				//TODO compare to dates

				if (date1.compareTo(date2) <= 0) {
					errors.add(field.getKey(),
							Resources.getActionMessage(request, va, field));

					return false;
				}
			} catch (Exception e) {
				errors.add(field.getKey(),
						Resources.getActionMessage(request, va, field));

				return false;
			}
		}

		return true;
	}

    public static boolean validateDateAfterEqual(Object bean, ValidatorAction va,
			Field field, ActionMessages errors,
			HttpServletRequest request) {
		String value =
			ValidatorUtils.getValueAsString(bean, field.getProperty());
		String sProperty2 = field.getVarValue("secondDate");
		String value2 = ValidatorUtils.getValueAsString(bean, sProperty2);

		Date date1 = null;
		Date date2 = null;
		DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
		try
		{
			date1 = df.parse(value);
			date2 = df.parse(value2);
		}
		catch (Exception e)
		{
			//No need to compare, validate format
		}
		if (date1 != null && date2 != null) {
			try {
				//TODO compare to dates

				if (date1.compareTo(date2) < 0) {
					errors.add(field.getKey(),
							Resources.getActionMessage(request, va, field));

					return false;
				}
			} catch (Exception e) {
				errors.add(field.getKey(),
						Resources.getActionMessage(request, va, field));

				return false;
			}
		}

		return true;
	}
    public static boolean validateDateBefore(Object bean, ValidatorAction va,
            Field field, ActionMessages errors,
            HttpServletRequest request) {
        String value =
            ValidatorUtils.getValueAsString(bean, field.getProperty());
        String sProperty2 = field.getVarValue("secondDate");
        String value2 = ValidatorUtils.getValueAsString(bean, sProperty2);

        Date date1 = null;
        Date date2 = null;
        DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
        try
        {
            date1 = df.parse(value);
            date2 = df.parse(value2);
        }
        catch (Exception e)
        {
            //No need to compare, validate format
        }
        if (date1 != null && date2 != null) {
            try {
                //TODO compare to dates

                if (date2.compareTo(date1) <= 0) {
                    errors.add(field.getKey(),
                            Resources.getActionMessage(request, va, field));

                    return false;
                }
            } catch (Exception e) {
                errors.add(field.getKey(),
                        Resources.getActionMessage(request, va, field));

                return false;
            }
        }

        return true;
    }

	// Validate date to be either today's date or a date in the past
	public static boolean validatePastDate(Object bean, ValidatorAction va,
			Field field, ActionMessages errors,
			HttpServletRequest request) {
		String dateStr =
			ValidatorUtils.getValueAsString(bean, field.getProperty());

        if (StringUtils.isEmpty(dateStr)) {
            return true;
        }

		try
		{
            Date date = DateUtils.getDate(dateStr, true);
            //Need time also to compare.
            Date current = DateUtils.getCurrentDateTime();
            if (date.compareTo(current) <= 0) {
                return true;
            }
		}
		catch (Exception e)
		{
			//exception shouldn't be thrown as it should be a valid date here
		}

        //parsing error or future date
        errors.add(field.getKey(),Resources.getActionMessage(request, va, field));
		return false;
	}

	/**
	 * Validates the password.
	 */
	 public static boolean validatePassword(Object bean,
	 										ValidatorAction va, Field field,
											ActionMessages errors,
											HttpServletRequest request)
	{
		String password = ValidatorUtils.getValueAsString(bean, field.getProperty());
		if (validatePassword(password)) {
            return true;
        }
        else
        {
            errors.add(field.getKey(),Resources.getActionMessage(request, va, field));
            return false;
        }
	}

	/**
	 * Validates the Imprecise date without time
	 */
	 public static Object validateImpreciseDate(Object bean, ValidatorAction va, Field field,
        ActionMessages errors, HttpServletRequest request)
	{
        return validateImpreciseDateImpl(bean, va, field, errors, request, false);
	}

    /**
     * Validates the Imprecise date with time
     */
     public static Object validateImpreciseDateWithTime(Object bean, ValidatorAction va, Field field,
        ActionMessages errors, HttpServletRequest request)
    {
        return validateImpreciseDateImpl(bean, va, field, errors, request, true);
    }

    /**
     * Validates the Imprecise date with or without time
     */
     private static Object validateImpreciseDateImpl(Object bean, ValidatorAction va, Field field,
         ActionMessages errors, HttpServletRequest request, boolean timeSupported)
    {
        // Get the field value
        String dateStr = ValidatorUtils.getValueAsString(bean, field.getProperty());

        // If no value was specified, assume that the field is valid
        if (StringUtils.isEmpty(dateStr))
        {
            return Boolean.TRUE;
        }

        boolean fieldValid = true;
        try
        {
            //	Get the user defined options
            boolean useDefaultYear = Boolean.valueOf(field.getVarValue(DEFAULT_CURRENT_YEAR_VAR)).booleanValue();

            // Validate the imprecise date
            DateUtils.getImpreciseDate(dateStr, timeSupported, useDefaultYear);
        }
        catch (Exception e)
        {
            // Field parsing exception so it isn't valid
            fieldValid = false;
        }

        // Add the error message if invalid
        if (!fieldValid)
        {
            errors.add(field.getKey(),Resources.getActionMessage(request, va, field));
        }

        // Return whether the field is valid or not
        return Boolean.valueOf(fieldValid);
    }

    /**
     * Validates a precise date without time
     */
     public static Object validatePreciseDate(Object bean, ValidatorAction va, Field field,
        ActionMessages errors, HttpServletRequest request)
    {
        return validatePreciseDateImpl(bean, va, field, errors, request, false);
    }

    /**
     * Validates a precise date with time
     */
     public static Object validatePreciseDateWithTime(Object bean, ValidatorAction va, Field field,
        ActionMessages errors, HttpServletRequest request)
    {
        return validatePreciseDateImpl(bean, va, field, errors, request, true);
    }
    /**
     * Validate password with regular expression syntax
     * password must contain lowecase, uppercase, digits and special characters
     * @param clearTextPassword
     * @return
     */
    public static boolean validatePassword(String clearTextPassword) {
        if (StringUtils.isEmpty(clearTextPassword)) return true;
        //check for the existence of at least one combination
        return (clearTextPassword.matches(PASSWORD_REG_EXP) ||  // 4 types
            clearTextPassword.matches(PASSWORD_REG_EXP_LCNS) || // lc, n, sc
            clearTextPassword.matches(PASSWORD_REG_EXP_LCUCS) ||    //lc, uc, sc
            clearTextPassword.matches(PASSWORD_REG_EXP_LCUCN) ||    //lc, uc, n
            clearTextPassword.matches(PASSWORD_REG_EXP_UCNS));      // uc, n, sc
    }
    /**
     * Validates a precise date with or without time
     */
     private static Object validatePreciseDateImpl(Object bean, ValidatorAction va, Field field,
         ActionMessages errors, HttpServletRequest request, boolean timeSupported)
    {
        // Get the field value
        String dateStr = ValidatorUtils.getValueAsString(bean, field.getProperty());

        // If no value was specified, assume that the field is valid
        if (StringUtils.isEmpty(dateStr))
        {
            return Boolean.TRUE;
        }

        boolean fieldValid = true;
        try
        {
            // Validate the precise date
            DateUtils.getDate(dateStr, timeSupported);
        }
        catch (Exception e)
        {
            // Field parsing exception so it isn't valid
            fieldValid = false;
        }

        // Add the error message if invalid
        if (!fieldValid)
        {
            errors.add(field.getKey(),Resources.getActionMessage(request, va, field));
        }

        // Return whether the field is valid or not
        return Boolean.valueOf(fieldValid);
    }

     /**
      * Validate searchSSN
      * @return
      */
     public static boolean validateSearchSSN(Object bean, ValidatorAction va,
             Field field, ActionMessages errors,
             HttpServletRequest request) {

         String ssn = ValidatorUtils.getValueAsString(bean, field.getProperty());

         if (StringUtils.isEmpty(ssn)) return true;
         //check for the existence of at least one combination
         if (ssn.matches(PATTERN_SSN) ||   //unformatted ssn
                 ssn.matches(PATTERN_FORMATTED_SSN)){ //formatted ssn
             return true;
         }
         else {
             errors.add(field.getKey(),Resources.getActionMessage(request, va, field));
             return false;
         }
     }

 	public static boolean validateName(Object bean, ValidatorAction va,
              Field field, ActionMessages errors,
              HttpServletRequest request) {

          String name = ValidatorUtils.getValueAsString(bean, field.getProperty());

          if (StringUtils.isEmpty(name)){
         	 return true;
          }

          if(StringUtils.validateEntry(name, PATTERN_NAME)){
         	 if(StringUtils.contains(name, "--")){
         		 errors.add(field.getKey(),Resources.getActionMessage(request, va, field));
        	  		 return false;
         	 }
         	 return true;
          }
          else{

         	 errors.add(field.getKey(),Resources.getActionMessage(request, va, field));
    	  		 return false;
          }

      }

      public static boolean validateFilter(Object bean, ValidatorAction va,
              Field field, ActionMessages errors,
              HttpServletRequest request) {

          String filterEntry = ValidatorUtils.getValueAsString(bean, field.getProperty());

          if (StringUtils.isEmpty(filterEntry)){
         	 return true;
          }

          if(StringUtils.validateEntry(filterEntry, PATTERN_REGEX)){
         	 if(StringUtils.contains(filterEntry, "--")){
         		 errors.add(field.getKey(),Resources.getActionMessage(request, va, field));
        	  		 return false;
         	 }
         	 return true;
          }
          else{
         	 errors.add(field.getKey(),Resources.getActionMessage(request, va, field));
    	  		 return false;
          }

      }

      public static boolean validateAlphaNumeric(Object bean, ValidatorAction va,
              Field field, ActionMessages errors,
              HttpServletRequest request) {

          String filterEntry = ValidatorUtils.getValueAsString(bean, field.getProperty());

          if (StringUtils.isEmpty(filterEntry)){
         	 return true;
          }

          if(StringUtils.validateEntry(filterEntry, PATTERN_ALPHANUMERIC)){
         	 return true;
          }
          else{
         	 errors.add(field.getKey(),Resources.getActionMessage(request, va, field));
    	  		 return false;
          }

      }

      public static boolean validateReportPara(Object bean, ValidatorAction va,
              Field field, ActionMessages errors,
              HttpServletRequest request) {
          String filterEntry = ValidatorUtils.getValueAsString(bean, field.getProperty());

          if (StringUtils.isEmpty(filterEntry)){
         	 return true;
          }

          if(StringUtils.validateEntry(filterEntry, PATTERN_REPORT_PARA)){
         	 return true;
          }
          else{
         	 errors.add(field.getKey(),Resources.getActionMessage(request, va, field));
    	  		 return false;
          }

      }

      public static boolean validateCity(Object bean, ValidatorAction va,
              Field field, ActionMessages errors,
              HttpServletRequest request) {
          String filterEntry = ValidatorUtils.getValueAsString(bean, field.getProperty());

          if (StringUtils.isEmpty(filterEntry)){
         	 return true;
          }

          if(StringUtils.validateEntry(filterEntry, PATTERN_CITY)){
         	 return true;
          }
          else{
         	 errors.add(field.getKey(),Resources.getActionMessage(request, va, field));
    	  		 return false;
          }

      }

      public static boolean validateAlpha(Object bean, ValidatorAction va,
              Field field, ActionMessages errors,
              HttpServletRequest request) {
          String filterEntry = ValidatorUtils.getValueAsString(bean, field.getProperty());

          if (StringUtils.isEmpty(filterEntry)){
         	 return true;
          }

          if(StringUtils.validateEntry(filterEntry, PATTERN_Alpha)){
         	 return true;
          }
          else{
         	 errors.add(field.getKey(),Resources.getActionMessage(request, va, field));
    	  		 return false;
          }

      }

      public static boolean validateInvoArgs(Object bean, ValidatorAction va,
              Field field, ActionMessages errors,
              HttpServletRequest request) {
          String filterEntry = ValidatorUtils.getValueAsString(bean, field.getProperty());

          if (StringUtils.isEmpty(filterEntry)){
         	 return true;
          }

          if(StringUtils.validateEntry(filterEntry, PATTERN_INVOCATIONARGS)){
         	 return true;
          }
          else{
          	 //errors.add(field.getKey(),Resources.getActionMessage(request, va, field));
     	  		// return false;
         	  return true;
           }
      }

      public static boolean validateDistEmail(Object bean, ValidatorAction va,
	                Field field, ActionMessages errors,
	                HttpServletRequest request) {
	            String filterEntry = ValidatorUtils.getValueAsString(bean, field.getProperty());

	            if (StringUtils.isEmpty(filterEntry)){
	           	 return true;
	            }
	   /*Work Item 203373-Allow multiple emails and email address contains hyphen or underscore*/
	            String[] oneEmail = filterEntry.split(",");
	            for (int i = 0; i < oneEmail.length; i++) {
	                    if ( !(EmailValidator.getInstance().isValid(oneEmail[i]))  ){

	                    	 errors.add(field.getKey(),Resources.getActionMessage(request, va, field));
	               	  		 return false;
	                     }
	            }
	            return true;
      }

      public static boolean validatePhone(Object bean, ValidatorAction va,
              Field field, ActionMessages errors,
              HttpServletRequest request) {
          String filterEntry = ValidatorUtils.getValueAsString(bean, field.getProperty());

          if (StringUtils.isEmpty(filterEntry)){
         	 return true;
          }

          if(StringUtils.validateEntry(filterEntry, PATTERN_PHONE)){
         	 return true;
          }
          else{
         	 errors.add(field.getKey(),Resources.getActionMessage(request, va, field));
         	 return false;
          }

      }

      public static boolean validateEmail(Object bean, ValidatorAction va,
          Field field, ActionMessages errors,
          HttpServletRequest request) {
      String filterEntry = ValidatorUtils.getValueAsString(bean, field.getProperty());

      if (StringUtils.isEmpty(filterEntry)){
     	 return true;
      }

     	if (EmailValidator.getInstance().isValid(filterEntry)) {
     		return true;
      }
      else{
     	 errors.add(field.getKey(),Resources.getActionMessage(request, va, field));
	  		 return false;
      }

  }



































}
