package javakurs.musterloesung.uebung01.aufgabe2;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.List;

/**
 * {@link EncodingBytesPrinter} provides a method to print the byte
 * representation of each line of an input document for several encodings.
 *
 * @author Ulrich Schaefer, DFKI
 * @author Joerg Steffen, DFKI
 * @version $Id: EncodingBytesPrinter.java,v 1.2 2010/11/11 10:38:09 steffen Exp $
 */
public final class EncodingBytesPrinter {

  /**
   * This would create a new instance of {@link EncodingBytesPrinter}. Not to be
   * used.
   */
  private EncodingBytesPrinter() {

    // private constructor to enforce noninstantiability
  }


  /**
   * This prints the byte representation for the given string in the given
   * encoding.
   *
   * @param s
   *          the string
   * @param encoding
   *          the encoding name
   * @throws UnsupportedEncodingException
   *           if encoding is not supported
   */
  public static void printByteRepresentation(String s, String encoding)
      throws UnsupportedEncodingException {

    // init string builders that will contain the output lines
    StringBuilder outputLine1 = new StringBuilder();
    StringBuilder outputLine2 = new StringBuilder();
    for (int i = 0; i < s.length(); i++) {

      // convert Unicode code to character
      char currChar = s.charAt(i);

      // convert character to string and get its bytes for the given encoding
      byte[] bytes = Character.toString(currChar).getBytes(encoding);

      // create output for first line
      if (Character.isISOControl(currChar)) {
        // replace control characters with 'X'
        currChar = 'X';
      }
      // calculate space requirements to align first with second line;
      // a bytes requires two position in hexadecimal presentation and
      // bytes are separated by a single whitespace
      int spaceReq = bytes.length * 2 + bytes.length - 1;
      outputLine1.append(
        String.format("%" + spaceReq + "s", currChar));
      outputLine1.append("|");

      // create output for second line
      for (int j = 0; j < bytes.length; j++) {
        outputLine2.append(String.format("%02X", bytes[j]));
        if (j < bytes.length - 1) {
          outputLine2.append(" ");
        }
      }
      outputLine2.append("|");
    }
    // append encoding at the end of the first line
    outputLine1.append(" (").append(encoding).append(")");

    // print result
    System.out.println(outputLine1.toString());
    System.out.println(outputLine2.toString());
    System.out.println();
  }


  /**
   * This is the main method. It requires as arguments the encoding and the name
   * of an input file.
   *
   * @param args
   *          the arguments
   */
  public static void main(String[] args) {

    if (args.length != 2) {
      System.err.println(
        "This requires the encoding and name of an input file.");
      System.exit(1);
    }

    // define encodings for which to print the byte representation
    List<String> encodings = Arrays.asList(
      "ISO-8859-15",
      "windows-1252",
      "IBM500",
      "UTF-8",
      "UTF-16BE",
      "UTF-16LE",
      "UTF-32");

    BufferedReader in = null;
    try {
      in = new BufferedReader(
        new InputStreamReader(
          new FileInputStream(args[1]), args[0]));
      String str;
      while ((str = in.readLine()) != null) {
        for (String oneEncoding : encodings) {
          printByteRepresentation(str, oneEncoding);
        }
      }
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      if (null != in) {
        try {
          in.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
  }
}
