package matrix;

import java.util.ArrayList;
import java.util.List;


/**
 * Represents a matrix, a rectangular array, with generic values in each cell.
 *
 * @param <T> The type of values stored in the matrix cells.
 */
public class ListMatrix<T> implements Matrix<T> {

  private final List<List<T>> matrix;
  private final int width;
  private final int height;

  /**
   * Creates a new {@link ListMatrix} with the specified width, height, and an initializer to set
   * values.
   *
   * @param width       The width of the {@link ListMatrix}.
   * @param height      The height of the {@link ListMatrix}.
   * @param initializer A matrix initializer to set values in the {@link ListMatrix}.
   */
  public ListMatrix(int width, int height, MatrixInitializer<T> initializer) {
    this.width = 0;
    this.height = 0;
    this.matrix = null;
    this.initializeWith(initializer);

    for (int i = 0; i < height; i++) {
      List<T> row = new ArrayList<>(width);
      for (int j = 0; j < width; j++) {
        row.add(null);
      }
      matrix.add(row);
    }
    this.initializeWith(initializer);
  }

  public ListMatrix(int width, int height, T constant) {
    this(width, height, new ConstantMatrixInitializer<>(constant));
  }

  private void initializeWith(MatrixInitializer<T> initializer) {
    for (int i = 0; i < matrix.size(); i++) {
      for (int j = 0; j < matrix.get(i).size(); j++) {
        matrix.get(i).set(j, initializer.initialValueAt(Coordinate.of(i,j)));
      }
    }
  }

  public int width() {
    return width;
  }

  public int height() {
    return height;
  }

  @Override
  public T get(int x, int y) {
    return matrix.get(x).get(y);
  }


  @Override
  public void set(int x, int y, T newValue) {
    matrix.get(x).set(y, newValue);
  }

}