import java.util.List;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;

/**
 * @author Victor
 */
public class Main {

    public static void main(String[] args) {
        // Passa o alfabeto como parâmetro. Tem 62 caracteres aqui, então são 62 símbolos.
        BaseN bn = new BaseN("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
        String x = "The quick brown fox jumps over a lazy dog";
        System.out.println(x);
        String a = bn.encode(x);
        System.out.println(a); // Escreve "1u9WLfG65OMtVkQWPtWDcC6o8IjI5td5l9DzpilIK4Nyx81tKLRrStPj"
        String b = bn.decode(a);
        System.out.println(b); // Escreve "The quick brown fox jumps over a lazy dog"
    }
}

class BaseN {
    private static final BigInteger BI_256 = BigInteger.valueOf(256);

    private final String base;
    private final BigInteger radix;

    public BaseN(String base) {
        this.base = base;
        this.radix = BigInteger.valueOf(base.length());
    }

    public String encode(String text) {
        byte[] bytes = text.getBytes();
        BigInteger big = BigInteger.ONE;
        for (byte b : bytes) {
            big = big.multiply(BI_256).add(BigInteger.valueOf(b));
        }
        StringBuilder sb = new StringBuilder(bytes.length * 4 / 3 + 2);
        while (!BigInteger.ZERO.equals(big)) {
            BigInteger[] parts = big.divideAndRemainder(radix);
            int small = parts[1].intValue();
            big = parts[0];
            sb.append(base.charAt(small));
        }

        return sb.reverse().toString();
    }

    public String decode(String text) {
        BigInteger big = BigInteger.ZERO;
        for (char c : text.toCharArray()) {
            int i = base.indexOf(c);
            if (i == -1) throw new IllegalArgumentException();
            big = big.multiply(radix).add(BigInteger.valueOf(i));
        }

        List<Byte> byteList = new ArrayList<>(text.length());
        while (!BigInteger.ZERO.equals(big)) {
            BigInteger[] parts = big.divideAndRemainder(BI_256);
            int small = parts[1].intValue();
            big = parts[0];
            byteList.add((byte) small);
        }
        Collections.reverse(byteList);

        byte[] r = new byte[byteList.size() - 1];
        int i = 0;
        for (Byte b : byteList) {
            if (i > 0) r[i - 1] = b;
            i++;
        }
        return new String(r);
    }
}