/* SimText.java */

/* DO NOT CHANGE THIS FILE (except as noted). */
/* YOUR SUBMISSION MUST WORK CORRECTLY WITH _OUR_ COPY OF THIS FILE. */

/* (You may wish to make temporary changes or insert println() statements    */
/* while testing your code.  When you're finished testing and debugging,     */
/* though, make sure your code works with the original version of this file. */

import java.util.*;

/**
 *  The SimText class is a program that runs and animates a simulation of
 *  Sharks and Fish.
 *
 *  The SimText program takes up to four parameters.  The first two specify
 *  the width and height of the ocean.  The third parameter specifies the value
 *  of starveTime.  If there is a fourth parameter (it doesn't matter what the
 *  parameter is), then SimText uses the SparseOcean class; otherwise, by
 *  default, it uses the DenseOcean class.  For example, if you run
 *
 *         java SimText 25 25 1 s
 *
 *  then SimText will animate a 25x25 ocean (implemented by SparseOcean)
 *  with a starveTime of 1.  If you run "java SimText" with no parameters,
 *  by default SimText will animate a 50x25 ocean (implemented by
 *  DenseOcean) with a starveTime of 3.  With some choices of parameters, the
 *  ocean quickly dies out; with others, it teems forever.
 *
 *  @author Jonathan Shewchuk
 */

public class SimText {

  /**
   *  Default parameters.  (You may change these if you wish.)
   */

  private static int i = 50;                             // Default ocean width
  private static int j = 25;                            // Default ocean height
  private static int starveTime = 3;           // Default shark starvation time
  private static boolean sparse = false;           // Use DenseOcean by default

  /**
   *  paint() prints an Ocean.
   */

  public static void paint(Ocean sea) {
    if (sea != null) {
      int w = sea.width();
      int h = sea.height();

      /* Create an ocean view whose contents are all spaces. */
      char oceanView[][] = new char[w][h];
      for (int i = 0; i < w; i++) {
        for (int j = 0; j < h; j++) {
          oceanView[i][j] = ' ';
        }
      }

      sea.restartCritters();            // Prepare to enumerate all the animals
      Critter critter = sea.nextCritter();               // First fish or shark
      while (critter != null) {
        if (critter.species == Critter.SHARK) {
          oceanView[critter.x][critter.y] = 'S';
        } else if (critter.species == Critter.FISH) {
          oceanView[critter.x][critter.y] = '~';
        }
        critter = sea.nextCritter();                      // Next fish or shark
      }

      /* Draw the ocean. */
      for (int i = 0; i < w + 2; i++) {
        System.out.print("-");
      }
      System.out.println();
      for (int j = 0; j < h; j++) {
        System.out.print("|");
        for (int i = 0; i < w; i++) {
          System.out.print(oceanView[i][j]);
        }
        System.out.println("|");
      }
      for (int i = 0; i < w + 2; i++) {
        System.out.print("-");
      }
      System.out.println();
    }
  }

  /**
   *  main() reads the parameters and performs the simulation and animation.
   */

  public static void main(String[] argv) throws InterruptedException {
    Ocean sea;

    /**
     *  Read the input parameters.
     */

    if (argv.length > 0) {
      try {
        i = Integer.parseInt(argv[0]);
      }
      catch (NumberFormatException e) {
        System.out.println("First argument to SimText is not an number.");
      }
    }

    if (argv.length > 1) {
      try {
        j = Integer.parseInt(argv[1]);
      }
      catch (NumberFormatException e) {
        System.out.println("Second argument to SimText is not an number.");
      }
    }

    if (argv.length > 2) {
      try {
        starveTime = Integer.parseInt(argv[2]);
      }
      catch (NumberFormatException e) {
        System.out.println("Third argument to SimText is not an number.");
      }
    }

    /**
     *  Note that the presence of a fourth parameter causes SparseOcean to
     *  be used instead of DenseOcean, regardless of what the parameter is.
     */

    if (argv.length > 3) {
      sparse = true;
    }

    /**
     *  Create the initial ocean.
     */

    if (sparse) {
      sea = new SparseOcean(i, j);
    } else {
      sea = new DenseOcean(i, j);
    }

    /**
     *  Visit each cell (in a roundabout order); randomly place a fish, shark,
     *  or nothing in each.
     */

    Random random = new Random(0);      // Create a "Random" object with seed 0
    int x = 0;
    int y = 0;
    for (int xx = 0; xx < i; xx++) {
      x = (x + 78887) % i;           // This will visit every x-coordinate once
      if ((x < 25) || (x >= i - 25)) {
        for (int yy = 0; yy < j; yy++) {
          y = (y + 78887) % j;       // This will visit every y-coordinate once
          if ((y < 25) || (y >= j - 25)) {
            int r = random.nextInt();     // Between -2147483648 and 2147483647
            if (r < 0) {                        // 50% of cells start with fish
              sea.addFish(x, y);
            } else if (r > 1500000000) {     // ~15% of cells start with sharks
              sea.addShark(x, y);
            }
            //  While you are debugging you SparseOcean class, consider adding
            //  a call to "sea.check()" here.  Be sure to remove it once you
            //  have addFish() and addShark() debugged, as it will slow down
            //  this loop a lot.
          }
        }
      }
    }
    sea.check();                   // Check the validity of your data structure

    /**
     *  Perform timesteps forever.
     */

    while (true) {                                              // Loop forever
      paint(sea);
      //  For fun, you might wish to change the delay in the next line.
      Thread.sleep(1000);                // Wait one second (1000 milliseconds)
      sea = sea.timeStep(starveTime);                    // Simulate a timestep
      sea.check();                 // Check the validity of your data structure
    }
  }

}