package gov.va.med.esr.voa.util;

import gov.va.med.fw.util.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;

/**
 * Utility for validation.
 */
public class ServiceUtils {

	// RegEx pattern, only alphanumeric allowed.
	public static final String PATTERN_ALPHA_NUMERIC = "^\\w+$";

	// RegEx pattern, only 1-10 digits allowed.
	public static final String PATTERN_LESS_THAN_10_DIGITS = "^\\d{1,10}$";

	// RegEx pattern, only 5 digits allowed for zip code.
	public static final String PATTERN_ZIP = "^\\d{5}$";

	// RegEx pattern, only 4 digits allowed for zipPlus.
	public static final String PATTERN_ZIP_PLUS = "^\\d{4}$";

	// RegEx pattern, only 5 digits allowed for SSN.
	public static final String PATTERN_SSN = "^\\d{9}$";

	// only 10 digits allowed for phone.
	public static final String PATTERN_PHONE = "^\\d{10}$";

	// only 10 digits allowed for phone + chars of extension
	public static final String PATTERN_PHONE_WITH_EXT = "^\\d{10}[0-9a-zA-Z-]{0,5}$";

	// RegEx pattern for date format of MM/DD/YYYY
	public static final String PATTERN_MM_DD_YYYY_FORMAT = "^(0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])[- /.](19|20)\\d\\d$";

	// RegEx pattern for date format of MM/YYYY
	public static final String PATTERN_MM_YYYY_FORMAT = "^(0[1-9]|1[012])[- /.](19|20)\\d\\d$";

	// RegEx pattern for date format of YYYY
	public static final String PATTERN_YYYY_FORMAT = "^((19|20)\\d\\d)$";

	// String has 1-35 chars.
	public static final int LIMIT_LESS_THAN_35_CHARS = 35;

	// String has 1-30 chars.
	public static final int LIMIT_LESS_THAN_30_CHARS = 30;

	// String has 1-25 chars.
	public static final int LIMIT_LESS_THAN_25_CHARS = 25;

	// String has 1-10 chars.
	public static final int LIMIT_LESS_THAN_10_CHARS = 10;

	/**
	 * Check if input is alphaNumberic character
	 *
	 * @param input
	 * @return: true/false
	 */
	public static boolean isAlphaNumeric(String input) {
		boolean isValid = false;

		if (StringUtils.isNotBlank(input)) {
			isValid = StringUtils.validateEntry(input, PATTERN_ALPHA_NUMERIC);
		}

		return isValid;
	}

	/**
	 * Validate a phone number which will have only 10 digits.
	 *
	 * @param phoneNumber
	 * @return: true/false
	 */
	public static boolean validatePhone(String phoneNumber) {
		boolean isValid = false;

		if (StringUtils.isNotBlank(phoneNumber)) {
			isValid = StringUtils.validateEntry(phoneNumber, PATTERN_PHONE);
		}

		return isValid;
	}

	/**
	 * Validate a phone number with extension. phone is 10 digits + 5 chars for extension.
	 * @param phoneNumber
	 * @return: true/false
	 */
	public static boolean validatePhoneWithExtension(String phoneNumber) {
		boolean isValid = false;

		if (StringUtils.isNotBlank(phoneNumber)) {
			isValid = StringUtils.validateEntry(phoneNumber, PATTERN_PHONE_WITH_EXT);
		}

		return isValid;
	}

	/**
	 * Validate an input which will have only 10 digits.
	 *
	 * @param input
	 *            string
	 * @return: true/false
	 */
	public static boolean hasLessThan10Digits(String input) {
		boolean isValid = false;

		if (StringUtils.isNotBlank(input)) {
			isValid = StringUtils.validateEntry(input,
					PATTERN_LESS_THAN_10_DIGITS);
		}

		return isValid;
	}

	/**
	 * Validate a zipCode which will have only 9 digits
	 *
	 * @param zipCode
	 * @return: true/false
	 */
	public static boolean validateSsn(String ssn) {
		boolean isValid = false;

		if (StringUtils.isNotBlank(ssn)) {
			isValid = StringUtils.validateEntry(ssn, PATTERN_SSN);
		}

		return isValid;
	}

	/**
	 * Validate a zipCode which will have only 5 digits
	 *
	 * @param zipCode
	 * @return: true/false
	 */
	public static boolean validateZip(String zipCode) {
		boolean isValid = false;

		if (StringUtils.isNotBlank(zipCode)) {
			isValid = StringUtils.validateEntry(zipCode, PATTERN_ZIP);
		}

		return isValid;
	}

	/**
	 * Validate a zipPlus which will have only 4 digits
	 *
	 * @param zipPlus
	 * @return: true/false
	 */
	public static boolean validateZipPlus(String zipPlus) {
		boolean isValid = false;

		if (StringUtils.isNotBlank(zipPlus)) {
			isValid = StringUtils.validateEntry(zipPlus, PATTERN_ZIP_PLUS);
		}

		return isValid;
	}

	/**
	 * Validate a date string to have mm/dd/yyyy format
	 *
	 * @param dateStr
	 * @return: true/false
	 */
	public static boolean validateDate(String dateStr) {
		boolean isValid = false;

		if (StringUtils.isNotBlank(dateStr)) {
			isValid = StringUtils.validateEntry(dateStr,
					PATTERN_MM_DD_YYYY_FORMAT);
		}

		return isValid;
	}

	/**
	 * Valid year in mm/yyyy format.
	 *
	 * @param dateStr
	 * @return: true/false.
	 */
	public static boolean isValidMonthYear(String dateStr) {
		boolean isValid = false;

		if (StringUtils.isNotBlank(dateStr)) {
			isValid = StringUtils
					.validateEntry(dateStr, PATTERN_MM_YYYY_FORMAT);
		}

		return isValid;
	}

	/**
	 * Valid year in yyyy format.
	 *
	 * @param dateStr
	 * @return: true/false.
	 */
	public static boolean isValidYear(String dateStr) {
		boolean isValid = false;

		if (StringUtils.isNotBlank(dateStr)) {
			isValid = StringUtils.validateEntry(dateStr, PATTERN_YYYY_FORMAT);
		}

		return isValid;
	}

	/*
	 * Validate last name to have 1 - 10 characters.
	 */
	public static boolean hasLessThan10Chars(String input) {
		return (StringUtils.isNotBlank(input) && input.length() <= LIMIT_LESS_THAN_10_CHARS) ? true
				: false;
	}

	/*
	 * Validate string with 1 - 25 characters.
	 */
	public static boolean hasLessThan25Chars(String input) {
		return (StringUtils.isNotBlank(input) && input.length() <= LIMIT_LESS_THAN_25_CHARS) ? true
				: false;
	}

	/*
	 * Validate string with 1 - 30 characters.
	 */
	public static boolean hasLessThan30Chars(String input) {
		return (StringUtils.isNotBlank(input) && input.length() <= LIMIT_LESS_THAN_30_CHARS) ? true
				: false;
	}

	/*
	 * Validate string with 1 - 35 characters.
	 */
	public static boolean hasLessThan35Chars(String input) {
		return (StringUtils.isNotBlank(input) && input.length() <= LIMIT_LESS_THAN_35_CHARS) ? true
				: false;
	}

	/**
	 * test if the date string is future date.
	 *
	 * @param input
	 * @return: true/false
	 */
	public static boolean isFutureDate(String input) {
		boolean result = false;
		boolean isValid = validateDate(input);
		if (isValid) {
			try {
				Date date = new SimpleDateFormat("MM/dd/yyyy", Locale.ENGLISH)
						.parse(input);
				if (new Date().before(date)) {
					result = true;
				}
			} catch (ParseException e) {

			}
		}
		return result;
	}

	/**
	 * test if the date string is future date.
	 *
	 * @param input
	 * @return: true/false
	 */
	public static boolean isFutureMonthYear(String input) {
		boolean result = false;
		if (StringUtils.isNotBlank(input)) {
			try {
				Date date = new SimpleDateFormat("mm/yyyy", Locale.ENGLISH)
						.parse(input);
				Calendar current = new GregorianCalendar();
				int currentYear = current.get(Calendar.YEAR);
				int currentMonth = current.get(Calendar.MONTH);
				Calendar inputDate = new GregorianCalendar();
				inputDate.setTime(date);
				int inputYear = inputDate.get(Calendar.YEAR);
				int inputMonth = inputDate.get(Calendar.MONTH);
				if (currentYear < inputYear) {
					result = true;
				} else if (currentYear == inputYear) {
					if (currentMonth < inputMonth) {
						result = true;
					}
				}
			} catch (ParseException e) {

			}
		}
		return result;
	}

	/**
	 * test if the date string is future date.
	 *
	 * @param input
	 * @return: true/false
	 */
	public static boolean isFutureYear(String input) {
		boolean result = false;
		if (StringUtils.isNotBlank(input)) {
			try {
				Date date = new SimpleDateFormat("yyyy", Locale.ENGLISH)
						.parse(input);
				int currentYear = new GregorianCalendar().get(Calendar.YEAR);
				Calendar inputDate = new GregorianCalendar();
				inputDate.setTime(date);
				int inputYear = inputDate.get(Calendar.YEAR);
				if (currentYear < inputYear) {
					result = true;
				}
			} catch (ParseException e) {

			}
		}
		return result;
	}
}
