package br.com.caelum.stella.validation.ie; import java.text.ParseException; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.regex.Pattern; import javax.swing.text.MaskFormatter; import br.com.caelum.stella.DigitoGenerator; import br.com.caelum.stella.DigitoPara; import br.com.caelum.stella.MessageProducer; import br.com.caelum.stella.SimpleMessageProducer; import br.com.caelum.stella.ValidationMessage; import br.com.caelum.stella.validation.BaseValidator; import br.com.caelum.stella.validation.InvalidValue; import br.com.caelum.stella.validation.Validator; import br.com.caelum.stella.validation.error.IEError; public class IERioGrandeDoSulValidator implements Validator<String> { private final boolean isFormatted; public static final Pattern FORMATED = Pattern.compile("[0-4]\\d{2}\\/\\d{7}"); public static final Pattern UNFORMATED = Pattern.compile("([0-4]\\d{2})\\d{7}"); /** * Este considera, por padrão, que as cadeias estão formatadas e utiliza um * {@linkplain SimpleMessageProducer} para geração de mensagens. */ public IERioGrandeDoSulValidator() { this(true); } /** * O validador utiliza um {@linkplain SimpleMessageProducer} para geração de * mensagens. * * @param isFormatted * considerar cadeia formatada quando <code>true</code> */ public IERioGrandeDoSulValidator(boolean isFormatted) { this.baseValidator = new BaseValidator(); this.isFormatted = isFormatted; } public IERioGrandeDoSulValidator(MessageProducer messageProducer, boolean isFormatted) { this.baseValidator = new BaseValidator(messageProducer); this.isFormatted = isFormatted; } private List<InvalidValue> getInvalidValues(String IE) { List<InvalidValue> errors = new ArrayList<InvalidValue>(); errors.clear(); if (IE != null) { String unformatedIE = checkForCorrectFormat(IE, errors); if (errors.isEmpty()) { if (!hasValidCheckDigits(unformatedIE)) { errors.add(IEError.INVALID_CHECK_DIGITS); } } } return errors; } private String checkForCorrectFormat(String ie, List<InvalidValue> errors) { String unformatedIE = null; if (isFormatted) { if (!(FORMATED.matcher(ie).matches())) { errors.add(IEError.INVALID_FORMAT); } unformatedIE = ie.replaceAll("\\D", ""); } else { if (!UNFORMATED.matcher(ie).matches()) { errors.add(IEError.INVALID_DIGITS); } unformatedIE = ie; } return unformatedIE; } protected boolean hasValidCheckDigits(String unformattedIE) { String iESemDigito = unformattedIE.substring(0, unformattedIE.length() - 1); String digito = unformattedIE.substring(unformattedIE.length() - 1); String digitoCalculado = calculaDigito(iESemDigito); return digito.equals(digitoCalculado); } private String calculaDigito(String iESemDigito) { DigitoPara digitoPara = new DigitoPara(iESemDigito); digitoPara.complementarAoModulo().trocandoPorSeEncontrar("0", 10, 11); return digitoPara.calcula(); } public boolean isEligible(String value) { boolean result; if (isFormatted) { result = FORMATED.matcher(value).matches(); } else { result = UNFORMATED.matcher(value).matches(); } return result; } private final BaseValidator baseValidator; public void assertValid(String cpf) { baseValidator.assertValid(getInvalidValues(cpf)); } public List<ValidationMessage> invalidMessagesFor(String cpf) { return baseValidator.generateValidationMessages(getInvalidValues(cpf)); } private String formata(String valor) { try { final MaskFormatter formatador = new MaskFormatter("###/#######"); formatador.setValidCharacters("1234567890"); formatador.setValueContainsLiteralCharacters(false); return formatador.valueToString(valor); } catch (ParseException e) { throw new RuntimeException("Valor gerado não bate com o padrão: " + valor, e); } } @Override public String generateRandomValid() { final String primeiroDigito = String.valueOf(new Random().nextInt(5)); final String ieSemDigito = primeiroDigito + new DigitoGenerator().generate(8); final String ieComDigito = ieSemDigito + calculaDigito(ieSemDigito); if (isFormatted) { return formata(ieComDigito); } return ieComDigito; } }