package io.codearte.jfairy.producer.person.locale.pl; import com.google.common.annotations.VisibleForTesting; import io.codearte.jfairy.producer.BaseProducer; import io.codearte.jfairy.producer.DateProducer; import io.codearte.jfairy.producer.person.NationalIdentityCardNumberProvider; import io.codearte.jfairy.producer.util.AlphaNumberSystem; import org.joda.time.DateTime; import javax.inject.Inject; import static com.google.common.base.Preconditions.checkArgument; import static java.lang.String.copyValueOf; import static java.lang.String.valueOf; import static java.lang.System.arraycopy; import static org.apache.commons.lang3.StringUtils.leftPad; /** * Polish Identity Card Number * * http://en.wikipedia.org/wiki/Polish_identity_card */ public class PlNationalIdentityCardNumberProvider implements NationalIdentityCardNumberProvider { @VisibleForTesting static final int ISSUING_BEGIN = 2000; private static final int[] WEIGHTS = new int[]{7, 3, 1, 0, 7, 3, 1, 7, 3}; private static final int CHECKSUM_INDEX = 3; private static final int DIGITS_PART_SIZE = 5; @VisibleForTesting static final int MAX_DIGITS_PART_VALUE = 99999; @VisibleForTesting static final int LETTER_WEIGHT = 45; private static final int LETTERS_PART_SIZE = 3; private static final int LETTER_VALUE_MODIFIER = 10; private static final int ALPHABET_SIZE = 26; private static final int BASE_TEN = 10; private final DateProducer dateProducer; private final BaseProducer baseProducer; @Inject public PlNationalIdentityCardNumberProvider(DateProducer dateProducer, BaseProducer baseProducer) { this.dateProducer = dateProducer; this.baseProducer = baseProducer; } @Override public String get() { DateTime dateTime = dateProducer.randomDateBetweenYearAndNow(ISSUING_BEGIN); return get(dateTime); } public String get(DateTime date) { checkArgument(date.getYear() >= ISSUING_BEGIN, "Polish ID was introduced in 2000"); char[] id = new char[WEIGHTS.length]; fillLettersPart(date.getYear(), id); fillDigitsPart(id); char checksum = calculateChecksum(id); id[CHECKSUM_INDEX] = checksum; return copyValueOf(id); } public boolean isValid(String id) { int checksum = calculateChecksum(id.toCharArray()); return id.charAt(CHECKSUM_INDEX) == checksum; } private char calculateChecksum(char[] id) { int index = 0; int checksum = 0; for (int weight : WEIGHTS) { int value = 0; if (index < CHECKSUM_INDEX) { value = id[index] - 'A' + LETTER_VALUE_MODIFIER; } else if (index > CHECKSUM_INDEX) { value = id[index] - '0'; } index++; checksum += weight * value; } return valueOf(checksum % BASE_TEN).charAt(0); } private void fillDigitsPart(char[] id) { String num = valueOf(baseProducer.randomInt(MAX_DIGITS_PART_VALUE)); char[] digits = leftPad(num, DIGITS_PART_SIZE, '0').toCharArray(); arraycopy(digits, 0, id, CHECKSUM_INDEX + 1, digits.length); } private void fillLettersPart(int year, char[] id) { int maxPrefix = (year - ISSUING_BEGIN) * LETTER_WEIGHT; int range = baseProducer.randomBetween(maxPrefix, maxPrefix + LETTER_WEIGHT); String prefix = AlphaNumberSystem.convertToString(range, ALPHABET_SIZE); char[] charArray = leftPad(prefix, LETTERS_PART_SIZE, 'A').toCharArray(); arraycopy(charArray, 0, id, 0, charArray.length); } }