001/*
002 * Licensed under the Apache License, Version 2.0 (the "License");
003 * you may not use this file except in compliance with the License.
004 * You may obtain a copy of the License at
005 *
006 *     http://www.apache.org/licenses/LICENSE-2.0
007 *
008 * Unless required by applicable law or agreed to in writing, software
009 * distributed under the License is distributed on an "AS IS" BASIS,
010 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011 * See the License for the specific language governing permissions and
012 * limitations under the License.
013 */
014package org.gbif.api.util.validators.identifierschemes;
015
016import java.util.regex.Pattern;
017
018/**
019 * Util class that generates a validates Mod11,2 checksums.
020 */
021public abstract class Mod112 {
022
023  private static final Pattern NORMALIZE_PATTERN = Pattern.compile("-|\\s+");
024
025  /**
026   * Private constructor.
027   */
028  private Mod112() {
029    //do nothing
030  }
031
032  /**
033   * Validates that value contains an valid checksum digit according to ISO 7064 11,2.
034   */
035  static boolean hasValidChecksumDigit(String value) {
036    String normalized = NORMALIZE_PATTERN.matcher(value).replaceAll("");
037    return normalized.charAt(normalized.length() - 1) ==
038           generateChecksumDigit(normalized.substring(0, normalized.length() - 1));
039  }
040
041  /**
042   * Generates check digit as per ISO 7064 11,2.
043   *
044   */
045  static char generateChecksumDigit(String baseDigits) {
046    int total = 0;
047    for (int i = 0; i < baseDigits.length(); i++) {
048      int digit = Character.getNumericValue(baseDigits.charAt(i));
049      total = (total + digit) << 1;
050    }
051    int remainder = total % 11;
052    int result = (12 - remainder) % 11;
053    return result == 10 ? 'X' : Character.forDigit(result, 10);
054  }
055
056  public abstract boolean isValid(String value);
057
058  public String normalize(String value) {
059    return NORMALIZE_PATTERN.matcher(value).replaceAll("");
060  }
061
062}