import java.io.PrintStream;
import java.math.BigInteger;
import java.util.Date;
import java.util.Random;
import java.util.Scanner;
import java.util.zip.CRC32;

public class Main {

    public static final byte PRODUCT_TYPE = 1; //IntelliJ IDEA
    public static final byte PRODUCT_VERSION = 14;
    public static final String DEFUALT_NAME = "IntelliJ IDEA";

    public static final Random rnd = new Random();
    public static final char[] encodeTable = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();

    public static final BigInteger pow = new BigInteger("89126272330128007543578052027888001981", 10);
    public static final BigInteger mod = new BigInteger("86f71688cdd2612ca117d1f54bdae029", 16);

    public static final BigInteger baseChunk = BigInteger.valueOf(0x39aa400L);
    public static final int baseDigit = encodeTable.length;

    public static final Scanner in = new Scanner(System.in);
    public static final PrintStream out = System.out;

    public static byte[] writeSignature(char[] name, int salt, byte[] bkey) {
        CRC32 crc32 = new CRC32();

        for (char chr : name) {
            crc32.update(chr);
        }

        crc32.update(salt);
        crc32.update(salt >> 8);
        crc32.update(salt >> 16);
        crc32.update(salt >> 24);

        for (int i = 0; i < bkey.length - 2; i++) {
            crc32.update(bkey[i]);
        }

        short sign = (short) crc32.getValue();

        bkey[10] = (byte) (sign & 255);
        bkey[11] = (byte) ((sign >> 8) & 255);

        return bkey;
    }


    public static String keyToString(BigInteger key) {
        StringBuilder builder = new StringBuilder();

        for (int i = 0; key.compareTo(BigInteger.ZERO) != 0; i++) {
            if (i > 0) {
                builder.append("-");
            }

            int num = key.mod(baseChunk).intValue();

            for (int j = 0; j < 5; j++, num /= baseDigit) {
                builder.append(encodeTable[num % baseDigit]);
            }

            key = key.divide(baseChunk);
        }

        return builder.toString();
    }


    public static String generateKey(String name, int days) {
        int salt = rnd.nextInt(100000);
        int ld = (int) (new Date().getTime() >> 16);

        salt %= 100000;
        days &= 0xffff;

        byte[] bkey = { //size 12
                PRODUCT_TYPE,
                PRODUCT_VERSION,

                (byte) (ld & 0xff),
                (byte) ((ld >> 8) & 0xff),
                (byte) ((ld >> 16) & 0xff),
                (byte) ((ld >> 24) & 0xff),

                (byte) (days & 0xff),
                (byte) ((days >> 8) & 0xff),

                105, -59, 0, 0
        };

        bkey = writeSignature(name.toCharArray(), salt, bkey);

        BigInteger key = new BigInteger(bkey);
        key = key.modPow(pow, mod);

        return String.format(
                "%05d-%s",
                salt,
                keyToString(key)
        );
    }


    public static void main(String[] args) {
        out.printf("\nJetBrains IntelliJ IDEA Keygen\nEnter name [%s]: ", DEFUALT_NAME);
        String userName = in.nextLine().trim();

        if (userName.isEmpty()) {
            userName = DEFUALT_NAME;
        }

        out.printf("\nName: %s\nKey:  %s\n", userName, generateKey(userName, 0));

        out.println("Press Enter to exit...");
        in.hasNextLine();
    }

}