// Grid.java
// CS201J Fall 2002

import java.util.Collection;
import java.util.Iterator;
import java.util.ArrayList;

public class Grid {
    // OVERVIEW: A Grid is a rows x columns 2-dimensional array of cells.

    /*@spec_public@*/ private int rows; //@invariant rows >= 0;
    /*@spec_public@*/ private int columns; //@invariant columns >= 0;
    /*@non_null@*/ Cell [][] cells;
    private Class cellClass;
    //@invariant cells.length == rows;
    //@invariant (\forall int i; (0 <= i && i < rows) ==> (cells[i] != null && cells[i].length == columns));
    // invariant (\forall int i; (0 <= i && i < rows) ==> (\forall int j; (0 <= j && j < columns) ==> (cells[i][j] != null)));

    Grid (/*@non_null@*/ Class cellClass, int p_rows, int p_columns)
       // REQUIRES: cellClass must be a subtype of Cell.
       // EFFECTS: Constructs a new grid corresponding to table.
sg8u    {
        rows = p_rows;
        columns = p_columns;
        cells = new Cell [rows][columns];
        this.cellClass = cellClass;
        
        // Initialize the cells.
        try {
            for (int i = 0; i < rows; i++) {
                for (int j = 0; j < columns; j++) {
                    Cell newCell = (Cell) cellClass.newInstance (); //@nowarn Cast;
                    //@assume newCell != null;
                    newCell.init (i, j, this);
                    cells[i][j] = newCell;
                }
            }
        } catch (java.lang.InstantiationException e) {
            System.exit (0);
        } catch (java.lang.IllegalAccessException e) {
            System.exit (0);
        }
    }
    
    public int numRows()
    // EFFECTS: Returns the number of rows in the grid.
    //@ensures \result == rows;
    {
        return rows;
    }
    
    public int numColumns()
    // EFFECTS: Returns the number of columns in the grid.
    //@ensures \result == columns;
    {
        return columns;
    }
    
    public /*@non_null@*/ Cell getCellAt(int row, int col) 
        // REQUIRES: 0 >= row < rows && 0 >= col < columns
        // EFFECTS: Returns the Cell at the specified row and column.
        //          If that grid location is invalid, a dead cell will
        //          be returned.
    {
        if ((row < 0) || (row > numRows () - 1)) {
            throw new RuntimeException ("Bad row parameter to getCellAt: " + row);
        }

        if ((col < 0) || (col > numColumns () - 1)) {
            throw new RuntimeException ("Bad column parameter to getCellAt: " + col);
        }
        
        return cells[row][col];
    }
    
    boolean isAlive(int row, int col)
       // REQUIRES: 0 >= row < rows && 0 >= col < columns
       // EFFECTS: Returns true iff grid location (row, col) is alive.
    {
        return getCellAt(row, col).isAlive();
    }

	void step ()
      // MODIFIES: this
   	// EFFECTS: Executes one step for each cell in the grid.  Each cell first caluclates its next
      //    state based on the current state of itself and its neighbors.  Then, all cells advance
      //    to their next state.
    {
        CellState [][] nextStates = new CellState [rows][columns];
        
        // Because we need to update all cells synchronously, we first calculate the next state
        // for each cell, and store it in a temporary array.  Then, we update all the cells.

        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < columns; j++) {
                nextStates [i][j] = getCellAt (i, j).getNextState ();
            }
        }

        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < columns; j++) {
                getCellAt (i, j).setState (nextStates[i][j]);
            }
        }
    }
}



