package br.com.concretesolutions.canarinho.validator;
import android.text.Editable;
import android.text.SpannableStringBuilder;
import java.util.regex.Pattern;
import br.com.concretesolutions.canarinho.DigitoPara;
import br.com.concretesolutions.canarinho.formatador.Formatador;
/**
* Implementação de @{link Validador} para boleto
*
* @see Validador
*/
public final class ValidadorBoleto implements Validador {
/**
* Instância de módulo 10 para cálculo de digito verificador de boleto
*/
public static final DigitoPara MOD_10 = new DigitoPara.Builder()
.mod(10)
.comMultiplicadores(2, 1)
.somandoIndividualmente()
.trocandoPorSeEncontrar("0", 10)
.complementarAoModulo()
.build();
/**
* Instância de módulo 11 para cálculo de digito verificador de boleto
*/
public static final DigitoPara MOD_11 = new DigitoPara.Builder()
.trocandoPorSeEncontrar("0", 10, 11)
.complementarAoModulo()
.build();
private static final Pattern PADRAO_PARA_LIMPAR = Pattern.compile("[\\s.]");
private static final Pattern PADRAO_APENAS_NUMEROS = Pattern.compile("[\\d]*");
// No instance creation
private ValidadorBoleto() {
}
public static ValidadorBoleto getInstance() {
return SingletonHolder.INSTANCE;
}
@Override
public boolean ehValido(String valor) {
if (valor == null) {
throw new IllegalArgumentException("Campos não podem ser nulos");
}
String valorSemFormatacao = Formatador.Padroes.PADRAO_SOMENTE_NUMEROS.matcher(valor).replaceAll("");
return ehValido(new SpannableStringBuilder(valorSemFormatacao), new ResultadoParcial()).isValido();
}
@Override
public ResultadoParcial ehValido(Editable valor, ResultadoParcial resultadoParcial) {
if (resultadoParcial == null || valor == null) {
throw new IllegalArgumentException("Campos não podem ser nulos");
}
final String valorDesformatado = PADRAO_PARA_LIMPAR.matcher(valor).replaceAll("");
if (!PADRAO_APENAS_NUMEROS.matcher(valorDesformatado).matches()) {
throw new IllegalArgumentException("Apenas números, '.' e espaços são válidos");
}
resultadoParcial.totalmenteValido(false);
if (valorDesformatado.length() == 0) {
return resultadoParcial
.parcialmenteValido(true)
.mensagem("");
}
return ehTributo(valorDesformatado)
? validaTributo(valorDesformatado, resultadoParcial)
: validaNormal(valorDesformatado, resultadoParcial);
}
private ResultadoParcial validaNormal(String valor, ResultadoParcial rParcial) {
if (!validaBloco(valor, rParcial, MOD_10, 10, 0, "Primeiro")) {
return rParcial;
}
if (!validaBloco(valor, rParcial, MOD_10, 21, 10, "Segundo")) {
return rParcial;
}
if (!validaBloco(valor, rParcial, MOD_10, 32, 21, "Terceiro")) {
return rParcial;
}
if (valor.length() < 47) {
return rParcial;
}
return rParcial.parcialmenteValido(true).totalmenteValido(true);
}
private ResultadoParcial validaTributo(String valor, ResultadoParcial rParcial) {
if (valor.length() < 3) {
return rParcial.parcialmenteValido(true);
}
// A validação precisa levar em conta o terceiro dígito
final boolean ehMod10 = valor.charAt(2) == '6' || valor.charAt(2) == '7';
final DigitoPara digitoPara = ehMod10 ? MOD_10 : MOD_11;
if (!validaBloco(valor, rParcial, digitoPara, 12, 0, "Primeiro")) {
return rParcial;
}
if (!validaBloco(valor, rParcial, digitoPara, 24, 12, "Segundo")) {
return rParcial;
}
if (!validaBloco(valor, rParcial, digitoPara, 36, 24, "Terceiro")) {
return rParcial;
}
if (!validaBloco(valor, rParcial, digitoPara, 48, 36, "Quarto")) {
return rParcial;
}
// Retorna bloco válido
return rParcial.parcialmenteValido(true).totalmenteValido(true);
}
private boolean ehTributo(CharSequence valor) {
return valor.charAt(0) == '8';
}
private boolean validaBloco(String valor, ResultadoParcial resultadoParcial, DigitoPara mod,
int tamanhoMinimo, int st, String mensagem) {
if (valor.length() < tamanhoMinimo) {
resultadoParcial.parcialmenteValido(true);
return false;
}
final int end = tamanhoMinimo - 1;
// Valida primeiro bloco
final char digito = mod.calcula(valor.subSequence(st, end).toString()).charAt(0);
if (digito != valor.charAt(end)) {
return resultadoParcial
.mensagem(mensagem + " bloco inválido")
.parcialmenteValido(false)
.isParcialmenteValido();
}
return true;
}
private static class SingletonHolder {
private static final ValidadorBoleto INSTANCE = new ValidadorBoleto();
}
}