// Template for COT 5937 Programming Assignment #1
// Provided: An utility function to read in a normal text file into a
// hex message string, as well as a function that takes the hex version of
// a plaintext message and properly writes to a specified file the actual
// plaintext.

import java.io.*;

public class AES {

  // Constants to identify the current status of the message.
  final static boolean PLAIN = false;
  final static boolean CIPHER = true;

  private String message; // Stores the message in HEX.
  private String inputfile; // Stores the name of the input file.
  private String outputfile; // Stores the name of the output file.
  private String key; // Stores the key.
  private boolean msgstatus; // Stores whether message is currently the
                             // plain text or cipher text.

  public static void main(String[] args) throws IOException {

    // A very small test of the given methods. It allows the user to
    // Read in a file, write out its HEX equivalent, and then write the
    // file back to a separate input file. No encryption is being done
    // here.
    BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
    System.out.println("Enter the input file.");
    String input = stdin.readLine();
    String output = "cipher.txt";
    AES test = new AES(input, output);
    test.readMessage();
    test.dumpMessage();
    test.writePlainFile("inputtest.txt");
  }

  // Creates a new AES object.
  public AES(String inp, String out) {
    message = new String();
    inputfile = inp;
    outputfile = out;
  }

  // Reads in a the input file into message, storing the input file in
  // hexadecimal characters.
  public void readMessage() throws IOException {

    BufferedReader fin = new BufferedReader(new FileReader(inputfile));
    while (fin.ready()) {
      int c = fin.read();
      message = message + convert(c);
    }
  }

  // Pads the message with spaces so that the message size is divisible by
  // 128, the block size for AES for this assignment.
  public void padMessage() {
    while (message.length() %128 != 0)
      message = message + new String("20");
  }

  // Converts a normal text character into a String that stores a two
  // character HEX equivalent.
  public static String convert(int c) {
    char[] temp = new char[2];
    int d1 = c/16; // Most significant hex digit.
    int d2 = c%16; // Least significant hex digit.
    temp[0] = convToHex(d1);
    temp[1] = convToHex(d2);
    return new String(temp);
  }

  // Converts an integer(0-15) to the appropriate HEX character.
  public static char convToHex(int d) {
    if (d < 10)
      return (char)(d+'0');
    else
      return (char)(d-10+'A');
  }

  // Returns the integer value of a given HEX character.
  public static int hexVal(char c) {
    if (c >= '0' && c <= '9')
      return (int)(c-'0');
    else
      return (int)(c-'A'+10);
  }

  // Prints out message, for error checking purposes.
  public void dumpMessage() {
    System.out.println(message);
  }

  // Should only be called if the message is in CIPHER status. This
  // method writes out the ciphertext to the output file, writing 64
  // hex characters per line. This corresponds to 4 blocks of ciphertext
  // per line.
  public void writeOutput() throws IOException {

    BufferedWriter fout = new BufferedWriter(new FileWriter(outputfile));
    for (int i=0; i<message.length(); i++) {
      fout.write(message.charAt(i));
      if (i>0 && i%64 == 0)
        fout.write('\n');
    }
    fout.close();
  }

  // This method should only be called in PLAIN mode. It writes out the
  // plaintext in NORMAL text mode instead in HEX to the file passed into
  // the method.
  public void writePlainFile(String plain) throws IOException {

    BufferedWriter fout = new BufferedWriter(new FileWriter(plain));    
    for (int i=0; i<message.length(); i+=2) {
      int c = invert(message.charAt(i), message.charAt(i+1));
      fout.write(c); 
    }
    fout.close();
  }

  // Returns the ascii value of a single character represented by the HEX
  // characters a and b together.
  public static int invert(char a, char b) {
    return 16*hexVal(a)+hexVal(b);
  }

  // Runs AES encryption on the message, assuming that the mode is PLAIN.
  // After completion, the mode is changed to CIPHER.
  public void encrypt() {

  }

  // Runs AES decryption on the message, assuming that the mode is CIPHER.
  // After completion, the mode is changed to PLAIN.
  public void decrypt() {

  }
}
