package org.dicadeveloper.weplantaforest.common.code;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CodeHelper {
private static class Values {
public final int small;
public final int medium;
public final int large;
public Values(final int s, final int m, final int l) {
small = s;
medium = m;
large = l;
}
public static Values create(final int s, final int m, final int l) {
return new Values(s, m, l);
}
}
private static final Pattern CODE_PATTERN = Pattern.compile("[A-Z0-9^IJO0]{4}-[A-Z0-9^IJO0]{4}-[A-Z0-9^IJO0]{4}-[A-Z0-9^IJO0]{4}");
private static final Map<Character, Values> _crypt = new HashMap<Character, Values>();
static {
_crypt.put('A', Values.create(5, 6, 14));
_crypt.put('B', Values.create(2, 9, 12));
_crypt.put('C', Values.create(4, 1, 21));
_crypt.put('D', Values.create(1, 14, 26));
_crypt.put('E', Values.create(1, 5, 4));
_crypt.put('F', Values.create(4, 2, 20));
_crypt.put('G', Values.create(0, 14, 18));
_crypt.put('H', Values.create(3, 2, 13));
_crypt.put('K', Values.create(5, 13, 28));
_crypt.put('L', Values.create(5, 15, 10));
_crypt.put('M', Values.create(3, 8, 11));
_crypt.put('N', Values.create(7, 0, 30));
_crypt.put('P', Values.create(3, 4, 1));
_crypt.put('Q', Values.create(6, 11, 23));
_crypt.put('R', Values.create(6, 3, 27));
_crypt.put('S', Values.create(1, 12, 3));
_crypt.put('T', Values.create(6, 4, 22));
_crypt.put('U', Values.create(2, 13, 9));
_crypt.put('V', Values.create(0, 9, 2));
_crypt.put('W', Values.create(7, 7, 31));
_crypt.put('X', Values.create(2, 12, 19));
_crypt.put('Y', Values.create(7, 11, 17));
_crypt.put('Z', Values.create(0, 0, 25));
_crypt.put('1', Values.create(7, 15, 29));
_crypt.put('2', Values.create(6, 10, 16));
_crypt.put('3', Values.create(4, 6, 0));
_crypt.put('4', Values.create(5, 11, 7));
_crypt.put('5', Values.create(0, 7, 5));
_crypt.put('6', Values.create(2, 8, 15));
_crypt.put('7', Values.create(3, 1, 6));
_crypt.put('8', Values.create(1, 5, 24));
_crypt.put('9', Values.create(4, 3, 8));
}
public static boolean isValid(final String code) {
final Matcher matcher = CODE_PATTERN.matcher(code);
if (matcher.matches()) {
int sum = 0;
for (int i = 0; i < 2; i++) {
final char c = code.charAt(i);
sum += _crypt.get(c).small;
}
for (int i = 2; i < 4; i++) {
final char c = code.charAt(i);
sum += _crypt.get(c).medium;
}
for (int i = 5; i < 9; i++) {
final char c = code.charAt(i);
sum += _crypt.get(c).large;
}
for (int i = 10; i < 14; i++) {
final char c = code.charAt(i);
sum += _crypt.get(c).large;
}
for (int i = 15; i < 17; i++) {
final char c = code.charAt(i);
sum += _crypt.get(c).small;
}
for (int i = 17; i < 19; i++) {
final char c = code.charAt(i);
sum += _crypt.get(c).medium;
}
if (sum % 23 == 0) {
return true;
}
}
return false;
}
public static String generateCodeString() {
final StringBuilder key = new StringBuilder();
// 1st block
final int number11 = random(8);
final int number12 = random(8);
final int number13 = random(16);
final int number14 = random(16);
key.append(small(number11));
key.append(small(number12));
key.append(medium(number13));
key.append(medium(number14));
key.append("-");
// 2nd block
int number21 = random(32);
int number22 = random(32);
int number23 = random(32);
int number24 = random(32);
key.append(large(number21));
key.append(large(number22));
key.append(large(number23));
key.append(large(number24));
key.append("-");
// 3rd block
int number31 = random(32);
int number32 = random(32);
int number33 = random(32);
int number34 = random(32);
key.append(large(number31));
key.append(large(number32));
key.append(large(number33));
key.append(large(number34));
key.append("-");
// 4th block
final int number41 = random(8);
final int number42 = random(8);
key.append(small(number41));
key.append(small(number42));
// calculate checksum [medium]
final int sum = number11 + number12 + number13 + number14 + number21 + number22 + number23 + number24 + number31 + number32 + number33 + number34 + number41 + number42;
final int missing = 23 - sum % 23;
final int checkA = random(Math.max(missing - 8, 0), Math.min(missing, 8));
final int checkB = missing - checkA;
key.append(medium(checkA));
key.append(medium(checkB));
return key.toString();
}
private static int random(final int to) {
return random(0, to);
}
private static int random(final int from, final int to) {
return (int) (from + Math.random() * (to - from));
}
private static char small(final int v) {
final List<Character> cs = new ArrayList<Character>();
for (final Character c : _crypt.keySet()) {
final Values values = _crypt.get(c);
if (values.small == v) {
cs.add(c);
}
}
final int max = cs.size() - 1;
return cs.get(random(max));
}
private static char medium(final int v) {
final List<Character> cs = new ArrayList<Character>();
for (final Character c : _crypt.keySet()) {
final Values values = _crypt.get(c);
if (values.medium == v) {
cs.add(c);
}
}
final int max = cs.size() - 1;
return cs.get(random(max));
}
private static char large(final int v) {
for (final Character c : _crypt.keySet()) {
final Values values = _crypt.get(c);
if (values.large == v) {
return c;
}
}
return '0';
}
}