package rebelsky.io;

import java.io.PrintWriter;
import java.io.FileWriter;

/**
 * A simple output system for beginning programmers.  Permits 
 * writing of basic data types without delving into the workings 
 * of the various Java libraries.  Using this library makes it
 * easier to change programs to do output to a file (hopefully).
 * <p>
 * While it would be preferable to have this class extend 
 * PrintWriter, this makes it difficult to make it work with files
 * (at least in my experience).
 * <p>
 * Copyright (c) 1998 Samuel A. Rebelsky.  All rights reserved.
 * 
 * @author Samuel A. Rebelsky
 * @version 1.1 of February 1998
 */
public class SimpleOutput {
  // +--------+------------------------------------------------------------
  // | Fields |
  // +--------+

  /**
   * The base Writer used for doing the actual output.
   */
  protected PrintWriter base;

  /**
   * Are we writing to something that needs closing?
   */
  protected boolean needs_closing;


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

  /**
   * Build an object that can write to standard output.
   * <br>pre: Standard output has not been modified.
   * <br>post: The returned object writes to standard output.
   */
  public SimpleOutput() {
    // Use System.out, converting it as appropriate
    base = new PrintWriter(System.out, true);
    needs_closing = false;
  } // SimpleOutput

  /**
   * Build an object that can write to a file.  Make sure to
   * call <code>close()</code> when you're done writing to that
   * file.  If the file can't be created, exits the program.
   * <br>pre: The file can be created.
   * <br>post: The object writes to that file.
   */
  public SimpleOutput(String filename) {
    // Since nothing is open, nothing needs closing.
    needs_closing = false;
    // Set the output to the given file.
    setOutput(filename);
  } // SimpleOutput

 
  // +------------+--------------------------------------------------------
  // | Finalizers |
  // +------------+

 
  // +------------------+--------------------------------------------------
  // | Exported Methods |
  // +------------------+

  /**
   * Print a boolean (truth) value.
   * <br>pre: (none)
   * <br>post: The value is printed to the appropriate destination.
   */
  public void print(boolean b)
  {
    base.print(b);
  } // print(boolean)

  /**
   * Print a character value.
   * <br>pre: (none)
   * <br>post: The value is printed to the appropriate destination.
   */
  public void print(char c)
  {
    base.print(c);
  } // print(char)

  /**
   * Print a double value.
   * <br>pre: (none)
   * <br>post: The value is printed to the appropriate destination.
   */
  public void print(double d)
  {
    base.print(d);
  } // print(double)

  /**
   * Print an array of doubles.
   * <br>pre: (none)
   * <br>post: The array is printed to the appropriate destination.
   */
  public void print(double[] doubles)
  {
    // Special case: 0-length array
    if (doubles.length == 0) {
      print("[]");
    }
    // Normal case: 1 or more elements
    else {
      // Print the opening bracket
      print("[");
      // Print the first value
      print(doubles[0]);
      // Print all but the first value, with a comma before each value 
      for(int i = 1; i < doubles.length; ++i) {
        print(", ");
        print(doubles[i]);
      } // for
      // Print the closing bracket
      print("]");
    } // 1 or more elements
  } // print(double[])

  /**
   * Print an integer value.
   * <br>pre: (none)
   * <br>post: The value is printed to the appropriate destination.
   */
  public void print(int i)
  {
    base.print(i);
  } // print(int)

  /**
   * Print an array of integer values.
   * <br>pre: (none)
   * <br>post: The array is printed to the appropriate destination in
   *           a simplified format.
   */
  public void print(int[] iarr)
  {
    // Special case: 0-length array
    if (iarr.length == 0) {
      print("[]");
    }
    // Normal case: 1 or more elements
    else {
      // Print the opening bracket
      print("[");
      // Print the first value
      print(iarr[0]);
      // Print all but the first value, with a comma before each value 
      for(int i = 1; i < iarr.length; ++i) {
        print(", ");
        print(iarr[i]);
      } // for
      // Print the closing bracket
      print("]");
    } // 1 or more elements
  } //print(int[])

  /**
   * Print a long value.
   * <br>pre: (none)
   * <br>post: The value is printed to the appropriate destination.
   */
  public void print(long l)
  {
    base.print(l);
  } // print(long)

  /**
   * Print a float value.
   * <br>pre: (none)
   * <br>post: The value is printed to the appropriate destination.
   */
  public void print(float f)
  {
    base.print(f);
  } // print(float)

  /**
   * Print a string value.
   * <br>pre: (none)
   * <br>post: The value is printed to the appropriate destination.
   */
  public void print(String s)
  {
    base.print(s);
    base.flush();
  } // print(String)

  /**
   * Print a carriage return.
   * <br>pre: (none)
   * <br>post: A carriage return is printed to the appropriate destination.
   */
  public void println()
  {
    base.println();
  } //println

  /**
   * Print a boolean (truth) value followed by a carriage return
   * <br>pre: (none)
   * <br>post: The value is printlned to the appropriate destination.
   */
  public void println(boolean b)
  {
    base.println(b);
  } // println(boolean)

  /**
   * Print a character value followed by a carriage return.
   * <br>pre: (none)
   * <br>post: The value is printlned to the appropriate destination.
   */
  public void println(char c)
  {
    base.println(c);
  } // println(char)

  /**
   * Print a double value followed by a carriage return.
   * <br>pre: (none)
   * <br>post: The value and a carriage return are printed to 
   *    the appropriate destination.
   */
  public void println(double d)
  {
    base.println(d);
  } // println(double)

  /**
   * Print an array of double values followed by a carriage return.
   * <br>pre: (none)
   * <br>post: The value and a carriage return are printed to
   *    the appropriate destination.
   */
  public void println(double[] doubles)
  {
    print(doubles);
    println();
  } // println(double[])

  /**
   * Print an integer value followed by a carriage return.
   * <br>pre: (none)
   * <br>post: The value is printlned to the appropriate destination.
   */
  public void println(int i)
  {
    base.println(i);
  } // println(int)

  /**
   * Print an array of integers followed by a carriage return.
   * <br>pre: (none)
   * <br>post: The values and a carriage return are printed to the
   *     appropriate destination.
   */
  public void println(int[] iarr)
  {
    print(iarr);
    println();
  } // println(int[])

  /**
   * Print a long value followed by a carriage return.
   * <br>pre: (none)
   * <br>post: The value is printlned to the appropriate destination.
   */
  public void println(long l)
  {
    base.println(l);
  } // println(long)

  /**
   * Print a float value followed by a carriage return.
   * <br>pre: (none)
   * <br>post: The value is printlned to the appropriate destination.
   */
  public void println(float f)
  {
    base.println(f);
  } // println(float)

  /**
   * Print a string value followed by a carriage return.
   * <br>pre: (none)
   * <br>post: The value is printlned to the appropriate destination.
   */
  public void println(String s)
  {
    base.println(s);
  } // println(String)

  /**
   * Reset the output to standard output.  Not yet implemented.
   * <br>pre: (none)
   * <br>post: The output now goes to standard output.
   */
  public void reset() 
  {
  } // reset()

  /**
   * Set the output to a file.  Make sure to call close() when
   * you're done.  If the file can't be created, exits the program.
   */
  public void setOutput(String filename) {
    // If the previous output needs closing, close it
    if (needs_closing) {
      base.flush();
      base.close();
    }
    // Try to create an appropriate output stream.  If we fail,
    // crash the program.
    try {
      base = new PrintWriter(new FileWriter(filename));
    }
    catch (Exception e) {
      throw new Error(e.toString());
    }
    // Note that this needs closing
    needs_closing = true;
  } // setOutput
} // SimpleOutput

