import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.EOFException;
import java.io.IOException;

/**
 * A simple input system for beginning programmers.  Permits reading
 * of basic data types without delving into the workings of the
 * various Java libraries.  Does not throw exceptions.
 * 
 * Only permits reading of one value per line.  A more advanced class
 * would permit reading of multiple values per line (or, more precisely,
 * one value from each part of the line).  Such an implementation should
 * probably be based on the various classes in java.text.
 *
 * If something goes wrong with one of the read methods, an error
 * value is returned.  You can also use hadError to determine whether 
 * a value you received is intended to mark an error.
 *
 * Requires Java 1.1 or later.
 *
 * @author Samuel A. Rebelsky
 * @version 1.4 of January 1999
 */
public class SimpleInput {

  // +--------+------------------------------------------------------------
  // | Fields |
  // +--------+

  /**
   * The base input.  We use BufferedReaders because they are
   * a convenient form of input.
   */
  protected BufferedReader base;

  /** Are we at the end of the file? */
  protected boolean atEOF;
  
  /**
   * The error generated by the last operation.  If there was no
   * error, this should be null.
   */
  protected String error;
  
  /** Does something need closing? */
  protected boolean needsClosing;
  

  // +--------------+------------------------------------------------------
  // | Constructors |
  // +--------------+

  /**
   * Create a new object to read from standard input.
   */
  public SimpleInput() {
    // We need to convert standard input (System.in) to a Reader and
    // then buffer that reader.
    base = new BufferedReader(new InputStreamReader(System.in));
    // At times, we'll need to close input (e.g., if we're reading from
    // a file and what to start reading from another file).
    needsClosing = false;
    // We're not yet at the end of the file.
    atEOF = false;
    // And we don't yet have any errors.
    error = null;
  } // SimpleInput


  // +------------------+--------------------------------------------------
  // | Exported Methods |
  // +------------------+
  
  /**
   * Are we at the end of the file?
   */
  public boolean eof() {
    return atEOF;
  } // eof()

  /**
   * Determine if the last I/O exception had an error.
   */
  public boolean hadError() {
    return error != null;
  } // hadError()
  
  /**
   * Get the last error.
   */
  public String getError() {
    return error;
  } // getError()
  
  /**
   * Read one line of input (without the carriage return).  
   * Returns null at end of file or upon other errors.
   */
  public String readString() {
    return safeReadLine();
  } // readString()
  
  /**
   * Read a double from one line of input.  Returns false upon
   * encountering an error.
   */
  public boolean readBoolean() {
    String line = safeReadLine();
    boolean val = false;
    if (line == null) {
      return val;
    }
    try {
      val = Boolean.valueOf(line).booleanValue();
    }
    catch (Exception e) {
      this.error = e.toString();
    }
    return val;
  } // readBoolean()
  
  /**
   * Read a double from one line of input.  Returns Double.NaN upon
   * encountering an error.
   */
  public double readDouble() {
    String line = safeReadLine();
    double val = Double.NaN;
    if (line == null) {
      return val;
    }
    try {
      val = Double.valueOf(line).doubleValue();
    }
    catch (Exception e) {
      this.error = e.toString();
    }
    return val;
  } // readDouble()
  
  /**
   * Read a float from one line of input.  Returns 
   * Float.NaN upon error.
   */
  public float readFloat() {
    String line = safeReadLine();
    float val = Float.NaN;
    if (line == null) {
      return val;
    }
    try {
      val = Float.valueOf(line).floatValue();
    }
    catch (Exception e) {
      error = e.toString();
    }
    return val;
  } // readFloat()
  
  /**
   * Read an integer from one line of input.  Returns 
   * Integer.MIN_VALUE upon error.
   */
  public int readInt() {
    String line = safeReadLine();
    int val = Integer.MIN_VALUE;
    if (line == null) {
      return val;
    }
    try {
      val = Integer.valueOf(line).intValue();
    }
    catch (Exception e) {
      error = e.toString();
    }
    return val;
  } // readInt()
  
  /**
   * Read a long value from one line of input.  Returns 
   * Long.MIN_VALUE upon error.
   */
  public long readLong() {
    String line = safeReadLine();
    long val = Long.MIN_VALUE;
    if (line == null) {
      return val;
    }
    try {
      val = Long.valueOf(line).longValue();
    }
    catch (Exception e) {
      error = e.toString();
    }
    return val;
  } // readLong()
  
    
  // +---------------+-----------------------------------------------------
  // | Local Methods |
  // +---------------+

  /**
   * ``Safely'' read one line of input, catching exceptions when it is
   * appropriate to do so.
   *  Update errors appropriately.
   * Returns null at end of fie or upon other errors.
   */
  private String safeReadLine() {
    String line = null;	// Nothing read yet.
    error = null;	// No errors.
    // Are we at the end of file?  If so, we're done.
    if (atEOF) {
      error = "End of file";
      return null;
    }
    // Ask the base input object to read the line.
    try {
      line = base.readLine();
    }
    // Were we at the end of file?
    catch (EOFException eofe) {
      error = "End of file";
      atEOF = true;
      return null;
    }
    // Did we encounter some other horrendous error?
    catch (IOException ioe) {
      error = ioe.toString();
      return null;
    }
    // Some classes return null for end of file.
    if (line == null) {
      error = "End of file";
      atEOF = true;
    }
    // If we got this far, we're okay.
    return line;
  } // safeReadLine()

} // class SimpleInput

