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;
}
}