package model;

import datastruct.Coordinate;
import datastruct.Matrix;
import datastruct.MatrixInitializer;

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

public class NextGenerationInitializer<S extends State<S>> implements MatrixInitializer<S> {

    private final CellularAutomatonSimulation<S> simulation;

    public NextGenerationInitializer(CellularAutomatonSimulation<S> simulation) {
        this.simulation = simulation;
    }

    @Override
    public S initialValueAt(Coordinate coordinate) {
        List<State<S>> neighbours = new ArrayList<>();
        for (Coordinate neighbourCoord : coordinate.orthodiagonalNeighbours()) {
            Coordinate wrapped = wrap(neighbourCoord);
            neighbours.add(this.simulation.at(wrapped).get());
        }
        S state = this.simulation.at(coordinate).get();
        return state.update(neighbours);
    }

    private Coordinate wrap(Coordinate coordinate) {
        return new Coordinate(
                modulo(coordinate.x(),this.simulation.numberOfColumns()),
                modulo(coordinate.y(),this.simulation.numberOfRows())
        );
    }

    /** The non-negative remainder of n divided by d.
     *
     * @param n an arbitrary integer.
     * @param d a non-zero integer.
     * @return the remainder of {@code n/d}, between {@code 0} and {@code n-1}.
     */
    private static int modulo(int n, int d) {
        int result = n % d;
        return n < 0 ? result + d : result;
    }
}