package grid;

import java.util.ArrayList;
import position.Position;

/**
 * A grid csomagon belül hozzuk létre a nyilvános DenseGrid osztályt, mely
 * kiterjeszti az előbbi AbstractGrid osztályt ugyanazzal a paraméterrel.
 * @param <T> típussal paraméterezett
 */
public class DenseGrid<T> extends AbstractGrid<T> {

	/**
	 * Vegyünk fel egy rejtett adattagot, melynek típusa ArrayList, mely
	 * ArrayList-eket tárol, mely típusparaméternek megfelelő objektumokat
	 * tartalmaz. Tehát az adattag a kétdimenziós tömb ArrayList megfelelője.
	 * Legyen az adattag neve grid.
	 * @note 3ICE: I made it final as well, because why not.
	 */
	private final ArrayList<ArrayList<T>> grid;

	/**
	 * Egy konstruktort, mely inicializálja az egyetlen adattagot. Töltsük fel
	 * összesen annyi null-lal, ahány elemet el tudunk tárolni (sorok száma	 * oszlopok száma). Ehhez célszerű felölteni egy ArrayList-et annyi
	 * null-lal, ahány oszlop van. Ezt az ArrayList-et adjuk hozzá a grid
	 * adattaghoz. Ismételjük meg a lépést annyiszor, ahány sor van.
	 * @param rows paraméterül várja a sorok és oszlopok számát
	 * @param cols ezekkel meghívja a szülőosztály konstruktorát
	 */
	public DenseGrid(int rows, int cols) {
		super(rows, cols);
		grid = new ArrayList<>(rows);
		//for (ArrayList<T> g : grid)
		for (int i = 0; i < rows; i++) {
			grid.add(new ArrayList<T>(cols));
			for (int j = 0; j < cols; j++) {
				grid.get(i).add(null);
			}
		}
	}

	/**
	 * A get metódus. Két eset lehetséges:<ul>
	 * <li>Ha a pozíció a táblán van (isValid), akkor adjuk vissza a Position
	 * által jelölt soron belül (függőleges koordináta) található oszlopban
	 * (vízszintes koordináta) tárolt elemet. Az elem elérésekor használt első
	 * index a sorszám, a második az oszlopszám.</li>
	 * <li>Ha a pozíció nincs a táblán, úgy dobjunk IndexOutOfBoundsException-t
	 * a következő paraméterrel: "Invalid position: " melyet a paraméter
	 * követ.</li></ul>
	 * @param p Position-t vár
	 * @return típusparaméternek megfelelő objektumot ad vissza
	 */
	@Override
	public T get(Position p) {
		//System.out.println(p);
		if (isValid(p)) {
			return grid.get(p.v).get(p.h);
		} else {
			//System.out.println("Throwing...");
			throw new IndexOutOfBoundsException("Invalid position: " + p);
		}
	}

	/**
	 * A set metódus. Szintén két eset lehetséges:
	 * <ul>
	 * <li>Ha a pozíció a táblán van (isValid), akkor tároljuk el a Position
	 * által jelölt sorban és oszlopban a második paramétert.</li>
	 * <li>Ha a pozíció nincs a táblán, akkor dobjunk
	 * IndexOutOfBoundsException-t a következő paraméterrel: "Invalid position:
	 * " melyet a pozíció követ.</li></ul>
	 * @param p egy Position-t
	 * @param t és egy, a típusparaméternek megfelelő objektumot vár paraméterül
	 * @noreturn nincs visszatérési értéke
	 */
	@Override
	public void set(Position p, T t) {
		if (isValid(p)) {
			grid.get(p.v).set(p.h, t);
		} else {
			throw new IndexOutOfBoundsException("Invalid position: " + p);
		}
	}

}
