/*
 * 2004 Utah High School Programming Contest, University of Utah
 * Take-Home Problem
 *
 * Decrypt.java
 *
 * This file contains the implementation of the Decrypt class.
 */

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

/**
 * This is the "main class" of the program: it contains the top-level objects
 * and methods.  Its `main' method implements the overall program logic, but
 * all the real work is performed by helper methods and other objects.
 */
public class Decrypt {
    /**
     * The "default dictionary" for solving cryptograms.  This is initialized
     * from the "raw word array" in the Words class.  This dictionary is used
     * by the `decrypt' method in this class in order to make Puzzle objects.
     */
    private static final Dictionary DICT = new Dictionary(Words.ALL_WORDS);
    
    /**
     * This method implements the overall program logic.  It processes the
     * command line arguments, reads the input cryptogram file, deciphers the
     * cryptogram, and outputs the decoded result.  This method calls helper
     * methods to do the actual file reading and decryption.
     *
     * @param args    the array of command line arguments (Strings)
     */
    public static void main(String[] args) {
        if (args.length != 1) {
            // The user provided the wrong number of command line arguments.
            System.err.print("Usage: java ");
            System.err.print(Decrypt.class.getName());
            System.err.print(" <filename>");
            System.err.println();
            return;
        }
        
        StringBuffer cryptogram = new StringBuffer();
        
        if (!readFile(args[0], cryptogram)) {
            // We were unable to read the cryptogram file.
            return;
        }
        decrypt(cryptogram);
        System.out.print(cryptogram);
    }
    
    /**
     * This method reads the contents of a file into a given StringBuffer.  If
     * the file is read successfully, this method returns `true'.  Otherwise,
     * this method prints an error message (to `System.err') and returns
     * `false'.
     *
     * @param filename    the name of the file to be read
     * @param contents    the StringBuffer that the file contents will be read
     *                    into
     * @return            true if the file was read successfully, false if not
     */
    public static boolean readFile(String filename, StringBuffer contents) {
        contents.setLength(0);
        
        FileReader reader;
        try {
            reader = new FileReader(filename);
        } catch (FileNotFoundException e) {
            System.err.print("Cannot open file `");
            System.err.print(filename);
            System.err.print("'");
            System.err.println();
            System.err.println(e.getMessage());
            return false;
        }
        try {
            char readBuf[] = new char[1024];
            for (int readCount = reader.read(readBuf);
                 readCount != -1;
                 readCount = reader.read(readBuf)) {
                contents.append(readBuf, 0, readCount);
            }
        } catch (IOException e) {
            // Nothing to do (?).
        } finally {
            try {
                reader.close();
            } catch (IOException e) { }
        }
        return true;
    }
    
    /**
     * This method runs the steps required to decipher a given cryptogram.
     * First, it creates a Puzzle object to represent the current puzzle as a
     * whole and collect the data that is relevant to the problem (currently,
     * the cryptogram and the default dictionary).  Next, this method creates a
     * Search object and invokes it to perform the actual search for the
     * decryption cipher.  Finally, the Cipher returned by the search is
     * applied to the cryptogram: in other words, the StringBuffer parameter
     * given to this method is modified and decrypted.
     *
     * @param cryptogram    the StringBuffer containing the encrypted message.
     *                      This StringBuffer is modified to contain the
     *                      decrypted message.
     */
    public static void decrypt(StringBuffer cryptogram) {
        Puzzle puzzle = new Puzzle(cryptogram.toString(), DICT);
        Search search = new Search(puzzle);
        Cipher answerCipher = search.findCipher();
        
        // `findCipher' should *always* return a Cipher, but we check anyway.
        if (answerCipher != null) {
            answerCipher.decipher(cryptogram);
        }
    }
}

// End of file.

