/*
 *  Mouse in a Maze Program
 *
 *  Class: Maze
 *
 *  Author: Alyce Brady
 *
 *  License:
 *      This program is free software; you can redistribute it
 *      and/or modify it under the terms of the GNU General Public
 *      License as published by the Free Software Foundation.
 *
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 */

import java.util.ArrayList;

import edu.kzoo.grid.BoundedGrid;
import edu.kzoo.grid.Location;

/**
 *  Mouse in a Maze Program:<br>
 *  The <code>Maze</code> class models a bounded, two-dimensional
 *  grid.  In addition to the methods it inherits from
 *  BoundedGrid, it also provides methods for keeping track of the starting
 *  and ending locations in the maze, a method for finding possible move
 *  locations for a Mouse (locations that are empty or have cheese), and
 *  methods for adding and removing markers that can be used to indicate
 *  where a mouse has been.
 *
 *  @author Alyce Brady
 *  @version 5 October 2025
 **/
public class Maze extends BoundedGrid
{
  // instance variables
    private Location startLoc;
    private Location finishLoc;
    private ArrayList<Location> markerLocs;  // this list makes it easy to
                                             // remove markers when
                                             // resetting the maze

  // constructor

    /** Constructs an empty Maze object with the given dimensions.
     *  (Precondition: <code>rows > 0</code> and <code>cols > 0</code>.)
     *    @param rows        number of rows in Maze
     *    @param cols        number of columns in Maze
     **/
    public Maze(int rows, int cols)
    {
        // Construct and initialize inherited attributes.
        super(rows, cols);

        // Initialize additional instance variables.
        startLoc = null;
        finishLoc = null;
        markerLocs = new ArrayList<Location>();
    }


  // additional methods

    /** Gets the start location for this maze.
     **/
    public Location getStartLoc()
    {
        return startLoc;
    }

    /** Gets the finish location for this maze.
     **/
    public Location getFinishLoc()
    {
        return finishLoc;
    }

    /** Sets the start location in this maze.
     *    @param loc  the start location for this maze.
     **/
    public void setStartLoc(Location loc)
    {
        startLoc = loc;
    }

    /** Sets the finish location in this maze.
     *    @param loc  the finish location for this maze.
     **/
    public void setFinishLoc(Location loc)
    {
        finishLoc = loc;
    }

    /** Finds possible next locations (empty locations or
     *  locations containing cheese) that neighbor the given base
     *  location.
     *      @param     baseLoc  the base location around which to look
     *      @return    a list of next locations for the mouse
     **/
    protected ArrayList<Location> possibleNextLocations(Location baseLoc)
    {
        // Get all the neighboring locations of the base location.
        ArrayList<Location> nbrs = neighborsOf(baseLoc);
        Location cheeseLoc = getFinishLoc();

        // Figure out which neighbors are empty or contain cheese
        // and add those to a new list.
        ArrayList<Location> posNextLocs = new ArrayList<Location>();
        for ( Location loc : nbrs )
        {
            if ( isEmpty(loc) || loc.equals(cheeseLoc) )
                posNextLocs.add(loc);
        }

        return posNextLocs;
    }

    /** Add a marker to the maze at the specified location (assuming it is
     *  currently empty).
     *      @param markerLoc  the location where a marker should be added
     */
    protected void addMarker(Location markerLoc)
    {
        // If the location is empty, add a marker to the grid and keep
        // track of it in the list of markers.
        if ( isEmpty(markerLoc) )
        {
            add(new Marker(), markerLoc);
            markerLocs.add(markerLoc);
        }
    }

    /** Remove any markers in the maze.
     */
    protected void removeMarkers()
    {
        // Remove all the markers in the list.  (This is more efficient
        // than traversing the entire grid, looking at objects, determining
        // whether they are markers (or walls or mice or cheese), and
        // removing them if they are markers.)
        for ( Location loc : markerLocs )
        {
            if ( ! isEmpty(loc) )
                remove(loc);
        }
    }

}
