import java.io.File;
import java.text.DecimalFormat;
import java.util.Scanner;
import java.util.ArrayList;

public class Problem_1_Prime_Time {

    public static void main(String[] args) {
        
        int key = -1; // six-digit prime number key
        DecimalFormat df = new DecimalFormat("0000"); // format number to always have four digits (pad 0s to the left)
        
        ArrayList<Integer> primes = new ArrayList<Integer>(); // list of six-digit primes
        
        for (int prime = 100000; prime < 500000; prime++) {
            if (isPrime(prime)) { // use method to check if this number is a prime
                primes.add(prime);
            }
        }
        
        try {
            Scanner file = new Scanner(new File("C:\\Users\\Mike\\Desktop\\problem_1_prime_time_DATA10.txt"));
            ArrayList<String> list = new ArrayList<String>(); // list where each line is a different encoded message.
            
            // read in the file to the ArrayList
            while (file.hasNextLine()) {
                list.add(file.nextLine());
            }
            
            for (String line : list) {
                
                String[] parts = line.split ("\\s+"); // split this line by whitespace (each element in the array is one of the numbers)
                
                for (int i = 1; i < parts.length; i++) { // for every number in the line (except the first one because it's not part of the message)
                    
                    int keyMultipleInt = Integer.parseInt(parts[i]); // integer representation of the number in this part of the array
                    
                    // this actually doesn't need to be checked every time because
                    // the key will be the same for every number
                    for (int prime : primes) { // every prime in the list of six-digit primes
                        if (keyMultipleInt % prime == 0) { // if the prime number is a factor of the number (multiple of the key)
                            key = prime; // found the key
                            break; // stop checking
                        }
                    }
                    
                    keyMultipleInt /= key; // divide out the key to get the original nibble
                    String keyMultiple = df.format(keyMultipleInt); // string representation of the nibble (formatted to pad 0s on the left)

                    System.out.print(nibbleToString(keyMultiple)); // use the method to convert and print the nibble to it's character representation
                }
                System.out.println(); // next line in file, skip a line in display
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /* returns the string representation of the four digit number (according to the problem's conversions) */
    public static String nibbleToString(String s) {
        
        // s1 is the leftmost two digits in the nibble, s2 is the rightmost
        String s1 = s.substring(0,2), s2 = s.substring(2, 4);
        
        // converting the two leftmost digits to their character representation (hardcoded because it's quicker)
        if (s1.equals("00")) s1 = " ";
        if (s1.equals("01")) s1 = "A";
        if (s1.equals("02")) s1 = "B";
        if (s1.equals("03")) s1 = "C";
        if (s1.equals("04")) s1 = "D";
        if (s1.equals("05")) s1 = "E";
        if (s1.equals("06")) s1 = "F";
        if (s1.equals("07")) s1 = "G";
        if (s1.equals("08")) s1 = "H";
        if (s1.equals("09")) s1 = "I";
        if (s1.equals("10")) s1 = "J";
        if (s1.equals("11")) s1 = "K";
        if (s1.equals("12")) s1 = "L";
        if (s1.equals("13")) s1 = "M";
        if (s1.equals("14")) s1 = "N";
        if (s1.equals("15")) s1 = "O";
        if (s1.equals("16")) s1 = "P";
        if (s1.equals("17")) s1 = "Q";
        if (s1.equals("18")) s1 = "R";
        if (s1.equals("19")) s1 = "S";
        if (s1.equals("20")) s1 = "T";
        if (s1.equals("21")) s1 = "U";
        if (s1.equals("22")) s1 = "V";
        if (s1.equals("23")) s1 = "W";
        if (s1.equals("24")) s1 = "X";
        if (s1.equals("25")) s1 = "Y";
        if (s1.equals("26")) s1 = "Z";
        if (s1.equals("27")) s1 = ".";
        if (s1.equals("28")) s1 = ",";
        if (s1.equals("29")) s1 = "!";
        if (s1.equals("30")) s1 = "?";
        
        // converting the two rightmost digits to their character representation (hardcoded because it's quicker)
        if (s2.equals("00")) s2 = " ";
        if (s2.equals("01")) s2 = "A";
        if (s2.equals("02")) s2 = "B";
        if (s2.equals("03")) s2 = "C";
        if (s2.equals("04")) s2 = "D";
        if (s2.equals("05")) s2 = "E";
        if (s2.equals("06")) s2 = "F";
        if (s2.equals("07")) s2 = "G";
        if (s2.equals("08")) s2 = "H";
        if (s2.equals("09")) s2 = "I";
        if (s2.equals("10")) s2 = "J";
        if (s2.equals("11")) s2 = "K";
        if (s2.equals("12")) s2 = "L";
        if (s2.equals("13")) s2 = "M";
        if (s2.equals("14")) s2 = "N";
        if (s2.equals("15")) s2 = "O";
        if (s2.equals("16")) s2 = "P";
        if (s2.equals("17")) s2 = "Q";
        if (s2.equals("18")) s2 = "R";
        if (s2.equals("19")) s2 = "S";
        if (s2.equals("20")) s2 = "T";
        if (s2.equals("21")) s2 = "U";
        if (s2.equals("22")) s2 = "V";
        if (s2.equals("23")) s2 = "W";
        if (s2.equals("24")) s2 = "X";
        if (s2.equals("25")) s2 = "Y";
        if (s2.equals("26")) s2 = "Z";
        if (s2.equals("27")) s2 = ".";
        if (s2.equals("28")) s2 = ",";
        if (s2.equals("29")) s2 = "!";
        if (s2.equals("30")) s2 = "?";
        
        // concat the strings and return them like they were as a parameter
        return s1 + s2;
    }
    
    /* returns true if the parameter integer is prime or neither prime, nor composite; false if composite */
    public static boolean isPrime(int n) {
        if (n <= 2) return true;
        for (int i = 2; i < Math.sqrt(n); i++) { // up to sqrt contains exactly half of the factors
            if (n % i == 0) {
                return false; // has a factor; so it's composite
            }
        }
        return true; // hasn't returned false, so it's NOT composite (prime or neither)
    }
}