br.com.caelum.stella.DigitoPara Maven / Gradle / Ivy
package br.com.caelum.stella;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* Uma fluent interface para o cálculo de dígitos, que é usado em diversos boletos e
* documentos.
*
* Para exemplificar, o dígito do trecho 0000039104766 para os multiplicadores indo de
* 2 a 7 e usando módulo 11 é a seguinte:
*
*
* 0 0 0 0 0 3 9 1 0 4 7 6 6 (trecho numérico)
* 2 7 6 5 4 3 2 7 6 5 4 3 2 (multiplicadores, da direita para a esquerda e ciclando)
* ----------------------------------------- multiplicações algarismo a algarismo
* 0 0 0 0 0 9 18 7 0 20 28 18 12 -- soma = 112
*
*
* Tira-se o módulo dessa soma e, então, calcula-se o complementar do módulo e, se o número
* for 0, 10 ou 11, o dígito passa a ser 1.
*
*
* soma = 112
* soma % 11 = 2
* 11 - (soma % 11) = 9
*
*
* @author ceci
*/
public class DigitoPara {
private LinkedList numero;
private List multiplicadores = new ArrayList();
private boolean complementar;
private int modulo;
private boolean somarIndividual;
private Map substituicoes;
/**
* Cria o objeto a ser preenchido com interface fluente e armazena o trecho numérico
* em uma lista de algarismos. Isso é necessário porque a linha digitada pode ser
* muito maior do que um int suporta.
*
* @param trecho Refere-se à linha numérica sobre a qual o dígito deve ser calculado
*/
public DigitoPara(String trecho) {
comMultiplicadoresDeAte(2, 9);
mod(11);
substituicoes = new HashMap();
this.numero = new LinkedList();
char[] digitos = trecho.toCharArray();
for (char digito : digitos) {
this.numero.add(Character.getNumericValue(digito));
}
Collections.reverse(numero);
}
/**
* Para multiplicadores (ou pesos) sequenciais e em ordem crescente, esse método permite
* criar a lista de multiplicadores que será usada ciclicamente, caso o número base seja
* maior do que a sequência de multiplicadores. Por padrão os multiplicadores são iniciados
* de 2 a 9. No momento em que você inserir outro valor este default será sobrescrito.
*
* @param inicio Primeiro número do intervalo sequencial de multiplicadores
* @param fim Último número do intervalo sequencial de multiplicadores
* @return this
*/
public DigitoPara comMultiplicadoresDeAte(int inicio, int fim) {
this.multiplicadores.clear();
for (int i = inicio; i <= fim; i++) {
multiplicadores.add(i);
}
return this;
}
/**
* Há documentos em que os multiplicadores não usam todos os números de um intervalo
* ou alteram sua ordem. Nesses casos, a lista de multiplicadores pode ser passada
* através de varargs.
*
* @param multiplicadoresEmOrdem Sequência de inteiros com os multiplicadores em ordem
* @return this
*/
public DigitoPara comMultiplicadores(Integer... multiplicadoresEmOrdem) {
this.multiplicadores = Arrays.asList(multiplicadoresEmOrdem);
return this;
}
/**
* É comum que os geradores de dígito precisem do complementar do módulo em vez
* do módulo em sí. Então, a chamada desse método habilita a flag que é usada
* no método mod para decidir se o resultado devolvido é o módulo puro ou seu
* complementar.
*
* @return this
*/
public DigitoPara complementarAoModulo() {
this.complementar = true;
return this;
}
public DigitoPara trocandoPorSeEncontrar(String substituto, Integer... i) {
for (Integer integer : i) {
substituicoes.put(integer, substituto);
}
return this;
}
/**
* @param modulo Inteiro pelo qual o resto será tirado e também seu complementar.
* O valor padrão é 11.
*
* @return this
*/
public DigitoPara mod(int modulo) {
this.modulo = modulo;
return this;
}
/**
* Indica se ao calcular o módulo, se a soma dos resultados da multiplicação deve ser
* considerado digito a dígito.
*
* Ex: 2 X 9 = 18, irá somar 9 (1 + 8) invés de 18 ao total.
*
* @return this
*/
public DigitoPara somandoIndividualmente(){
this.somarIndividual = true;
return this;
}
/**
* Faz a soma geral das multiplicações dos algarismos pelos multiplicadores, tira o
* módulo e devolve seu complementar.
*
* @return String o dígito vindo do módulo com o número passado e configurações extra.
*/
public String calcula() {
int soma = 0;
int multiplicadorDaVez = 0;
for (int algarismo : numero) {
int multiplicador = multiplicadores.get(multiplicadorDaVez);
int total = algarismo * multiplicador;
soma += somarIndividual ? somaDigitos(total) : total;
multiplicadorDaVez = proximoMultiplicador(multiplicadorDaVez);
}
int resultado = soma % modulo;
if (complementar)
resultado = modulo - resultado;
if (substituicoes.containsKey(resultado)) {
return substituicoes.get(resultado);
}
return String.valueOf(resultado);
}
/**
* soma os dígitos do número (até 2)
*
* Ex: 18 => 9 (1+8), 12 => 3 (1+2)
*
* @param total
* @return
*/
private int somaDigitos(int total) {
return (total / 10) + (total % 10);
}
/**
* Devolve o próximo multiplicador a ser usado, isto é, a próxima posição da lista de
* multiplicadores ou, se chegar ao fim da lista, a primeira posição, novamente.
*
* @param multiplicadorDaVez Essa é a posição do último multiplicador usado.
* @return próximo multiplicador
*/
private int proximoMultiplicador(int multiplicadorDaVez) {
multiplicadorDaVez++;
if (multiplicadorDaVez == multiplicadores.size())
multiplicadorDaVez = 0;
return multiplicadorDaVez;
}
/**
* Adiciona um dígito no final do trecho numérico.
*
* @param digito É o dígito a ser adicionado.
* @return this
*/
public DigitoPara addDigito(String digito) {
this.numero.addFirst(Integer.valueOf(digito));
return this;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy