import java.io.IOException;
import java.lang.ArrayIndexOutOfBoundsException;
import java.lang.NumberFormatException;
import java.util.Vector;
import rebelsky.io.SimpleReader;
import rebelsky.io.SimpleOutput;
import rebelsky.util.BoundsException;
import rebelsky.util.Matrix;
import rebelsky.util.NumberRangeException;

/**
 * Allow interactive testing of the <code>java.util.Matrix</code>.
 * Used to extend understanding of what that class does in various
 * situations.
 * <p>
 * Copyright (c) 1998 Samuel A. Rebelsky.  All rights reserved.
 * 
 * @author Samuel A. Rebelsky
 * @version 1.0 of February 1998
 */
public class MatrixTester 
{
  // +------------+---------------------------------------------------------
  // | Attributes |
  // +------------+

  /**
   * The object used for output.
   */
  protected SimpleOutput out;
  
  /**
   * The object used for input.
   */
  protected SimpleReader in;

  /**
   * The matrix we're testing.
   */
  protected Matrix stuff;


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

  /**
   * Build a new tester.  
   */
  public MatrixTester()
  {
    in = new SimpleReader();
    out = new SimpleOutput();
    stuff = new Matrix(0,0);
  } // MatrixTester()


  // +---------+------------------------------------------------------------
  // | Methods |
  // +---------+
 
  /*
   * Look up a value.
   */
  public void lookup(int row, int col)
  {
    try {
      out.println("(" + row + "," + col + "): " + stuff.get(row,col));
    }
    catch (Exception e) {
      out.println("(" + row + "," + col + ") is an invalid position");
    }
  } // lookup(int)

  /**
   * Give instructions for using this program.
   */
  public void giveHelp()
  {
    out.println("c val len where - insert a column");
    out.println("f val row col delta-row delta-col end-row end-col - fill");
    out.println("e - erase (clear) the matrix");
    out.println("h - this help message");
    out.println("g row col - get the value at position (row,col)");
    out.println("n val rows cols - create a new matrix with the given " +
                "default value and the " +
                "specified number of rows and columns");
    out.println("p - print the current matrix");
    out.println("c val len where - insert a column");
    out.println("s val row col - set the value at position (row,col)");
    out.println("q      quit");
    out.println("x row - delete a row");
    out.println("y col - delete a column");
  } // giveHelp()

  /**
   * Print the current matrix.
   */
  public void print()
  {
    out.println(stuff.draw());
  } // print()

  /**
   * Build a vector of the specified size and contents.
   */
  public Vector vector(Object val, int size) 
  {
    Vector vec = new Vector(size);
    for (int i = 0; i < size; ++i) {
      vec.addElement(val);
    }
    return vec;
  } // vector(String,int)


  // +------------+---------------------------------------------------------
  // | Attributes |
  // +------------+

  /**
   * Repeatedly prompt for what to do and then do it.
   */
  public static void main(String[] args)
    throws Exception
  {
    // The object used to drive the testing
    MatrixTester tester = new MatrixTester();
    // The base part of the user's response
    String resp;
    // The value the user wants to add or retrieve
    String val;
    // The row in the matrix (or number of rows)
    int row;
    // The column in the matrix (or number of columns)
    int col;
    // The length of a vector
    int len;
    // An object to add
    String obj;
     
    // Provide some basic instructions
    tester.giveHelp();

    // Keep going until we hit the end of file or the user quits.
    // One exit is done using "break", and the other is done using
    // a catch of the end-of-file exception, so it looks as if our
    // loop continues indefinitely.
    try {
      LOOP:
      while (true)
      {
        // Print a prompt
        tester.out.println();
        tester.out.print("> ");
        // Get the first response
        resp = tester.in.readString();
        // Make sure the response is non-empty
        if (resp.length() == 0) {
          tester.out.println("You must give a non-empty response.");
          tester.giveHelp();
          continue;
        }
        // Determine what to do based on the first character
        switch (resp.charAt(0)) {

          case 'c':				// insert column
            // Get the value, width, and place
            obj = tester.in.readString();
            len = tester.in.readInt();
            col = tester.in.readInt();
            try {
              tester.stuff.insertColumn(tester.vector(obj,len), col);
            }
            catch (Exception e) {
              tester.out.println("Failed to insert column because " +
                                 e.toString());
            }
            break;

          case 'e':				// erase
            tester.stuff.clear();
            break;


          case 'f':				// fill line
            try {
              obj = tester.in.readString();
              row = tester.in.readInt();
              col = tester.in.readInt();
              int delta_row = tester.in.readInt();
              int delta_col = tester.in.readInt();
              int end_row = tester.in.readInt();
              int end_col = tester.in.readInt();
              tester.stuff.fillLine(obj, row, col, delta_row, delta_col,
                                    end_row, end_col);
            }
            catch (NumberFormatException e) {
              tester.out.println("Invalid number");
              continue LOOP;
            }
            catch (BoundsException e) {
              tester.out.println("Failed because: " + e.toString());
            }
            break;

          case 'g':				// get
            // Get the position and look up
            try {
              row = tester.in.readInt();
              col = tester.in.readInt();
              tester.lookup(row,col);
            }
            catch (NumberFormatException e) {
              tester.out.println("Invalid position");
            }
            catch (NumberRangeException e) {
              tester.out.println("Invalid position");
            }
            break;

          case 'h':				// help
            tester.giveHelp();
            break;

          case 'n':
            try {
              obj = tester.in.readString();
              row = tester.in.readInt();
              col = tester.in.readInt();
            }
            catch (NumberFormatException e) {
              tester.out.println("Invalid position");
              continue LOOP;
            }
            tester.stuff = new Matrix(obj,row,col);
            break;

          case 'p':				// print
            tester.print();
            break;

          case 'r':				// insert row
            // Get the value, width, and place
            obj = tester.in.readString();
            len = tester.in.readInt();
            row = tester.in.readInt();
            try {
              tester.stuff.insertRow(tester.vector(obj,len), row);
            }
            catch (Exception e) {
              tester.out.println("Failed to insert row because: " +
                                 e.toString());
            }
            break;

          case 'q':				// quit
            break LOOP;

          case 's':				// set
            try {
              obj = tester.in.readString();
              row = tester.in.readInt();
              col = tester.in.readInt();
            }
            catch (NumberFormatException e) {
              tester.out.println("Invalid number");
              continue LOOP;
            }
            try {
              tester.stuff.set(obj, row, col);
            }
            catch (BoundsException e) {
              tester.out.println("Invalid position");
              continue LOOP;
            }
            break;

          case 'x':				// delete row
            try {
              tester.stuff.deleteRow(tester.in.readInt());
            }
            catch (NumberFormatException e) {
              tester.out.println("That's not a number");
            }
            catch (BoundsException e) {
              tester.out.println("Invalid row");
            }
            break;

          case 'y':				// delete column
            try {
              tester.stuff.deleteColumn(tester.in.readInt());
            }
            catch (NumberFormatException e) {
              tester.out.println("That's not a number");
            }
            catch (BoundsException e) {
              tester.out.println("Invalid column");
            }
            break;

          default:
            tester.out.println("Illegal command.");
            tester.giveHelp();
            break;
        } // switch
        // Skip anything else on the line
        tester.in.readLine();
      } //while
    } // try doing the input
    catch (IOException e) {
      // We're done
    } // catch(IOException)

  } // main
  
} // MatrixTester

