package com.ejie.y42b.validation;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class Y42bCifValidator implements ConstraintValidator<Y42bCif, String> {

	private static Pattern mask = Pattern
			.compile("[[A-H][J-N][P-S]UVW][0-9]{7}[0-9A-J]");
	private static final int longitudCero = 0;
	private static final String CONTROL_SOLO_NUMEROS = "ABEH"; // Sólo admiten
																// números como
																// caracter de
																// control
	private static final String CONTROL_SOLO_LETRAS = "KPQS"; // Sólo admiten
																// letras como
																// caracter de
																// control
	private static final String CONTROL_NUMERO_A_LETRA = "JABCDEFGHI"; // Conversión
																		// de
																		// dígito
																		// a
																		// letra
																		// de
																		// control.

	@Override
	public void initialize(Y42bCif constraintAnnotation) {
	}

	@Override
	public boolean isValid(String value, ConstraintValidatorContext context) {

		if (value == null || value.length() == Y42bCifValidator.longitudCero) {
			return true;
		} else {
			boolean resultado = Y42bCifValidator.validarCifPuro(value);

			return resultado;
		}
	}

	/**
	 * validarCifPuro
	 * 
	 * @param strCIF
	 *            String
	 * @return boolean
	 */

	public static boolean validarCifPuro(String cif) {
		try {
			Matcher matcher = mask.matcher(cif);

			if (!matcher.matches()) {
				// No cumple el patrón
				return false;
			}

			int parA = 0;
			for (int i = 2; i < 8; i += 2) {
				final int digito = Character.digit(cif.charAt(i), 10);
				if (digito < 0) {
					return false;
				}
				parA += digito;
			}

			int nonB = 0;
			for (int i = 1; i < 9; i += 2) {
				final int digito = Character.digit(cif.charAt(i), 10);
				if (digito < 0) {
					return false;
				}
				int nn = 2 * digito;
				if (nn > 9) {
					nn = 1 + (nn - 10);
				}
				nonB += nn;
			}

			final int parcialC = parA + nonB;
			final int digitoE = parcialC % 10;
			final int digitoD = (digitoE > 0) ? (10 - digitoE) : 0;
			final char letraIni = cif.charAt(0);
			final char caracterFin = cif.charAt(8);

			final boolean esControlValido =
			// ¿el caracter de control es válido como letra?
			(CONTROL_SOLO_NUMEROS.indexOf(letraIni) < 0 && CONTROL_NUMERO_A_LETRA
					.charAt(digitoD) == caracterFin) ||
			// ¿el caracter de control es válido como dígito?
					(CONTROL_SOLO_LETRAS.indexOf(letraIni) < 0 && digitoD == Character
							.digit(caracterFin, 10));
			return esControlValido;

		} catch (Exception e) {
			return false;
		}

	}
}