
// SimulatorView.java
// Andrew Davison, Nov 2018, ad@fivedots.coe.psu.ac.th

/* A graphical view of the simulation grid.
 * The view displays a colored rectangle for each location 
 * representing its contents. It uses a default background color.
 * Colors for each type of species can be defined using the
 * setColor method.
 * 
 * @author David J. Barnes and Michael Kolling
 * @version 2006.03.30
 */


import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.HashMap;


public class SimulatorView extends JFrame
{
  private static final Color EMPTY_COLOR = Color.white; // for empty locations
  private static final Color UNKNOWN_COLOR = Color.gray; // for objects with no colour

  private final String STEP_PREFIX = "Step: ";
  private final String POPULATION_PREFIX = "Population: ";


  private JLabel stepLabel, population;
  private FieldView fieldView;
    
  // A map for storing colors for participants in the simulation
  private HashMap<Class, Color> colors;

  // A statistics object computing and storing simulation information
  private FieldStats stats;



  public SimulatorView(int height, int width)
  {
    stats = new FieldStats();
    colors = new HashMap<Class, Color>();

    setTitle("Fox and Rabbit Simulation V.2");
    stepLabel = new JLabel(STEP_PREFIX, JLabel.CENTER);
    population = new JLabel(POPULATION_PREFIX, JLabel.CENTER);
    fieldView = new FieldView(height, width);

    Container contents = getContentPane();
    contents.add(stepLabel, BorderLayout.NORTH);
    contents.add(fieldView, BorderLayout.CENTER);
    contents.add(population, BorderLayout.SOUTH);

    setLocation(100, 50);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    pack();
    setResizable(false);
    setVisible(true);
  }  // end of SimulatorView()
    

  public void setColor(Class animalClass, Color color)
  {  colors.put(animalClass, color); }


  private Color getColor(Class animalClass)
  {
    Color col = colors.get(animalClass);
    if (col == null)  // no color defined for this class
      return UNKNOWN_COLOR;
    else
      return col;
  }  // end of getColor()


  public void showStatus(int step, Field field)
  {
    if (!isVisible())
      setVisible(true);
            
    stepLabel.setText(STEP_PREFIX + step);
    stats.reset();
    
    fieldView.preparePaint();
    for (int row = 0; row < field.getDepth(); row++) {
      for (int col = 0; col < field.getWidth(); col++) {
        Animal animal = field.getAnimalAt(row, col);  // was Object
        if (animal != null) {
          stats.incrementCount(animal.getClass());
          fieldView.drawMark(col, row, getColor(animal.getClass()));
        }
        else
          fieldView.drawMark(col, row, EMPTY_COLOR);
      }
    }
    stats.countFinished();
    population.setText(POPULATION_PREFIX + stats.getPopulationDetails(field));
    fieldView.repaint();
  }  // end of showStatus()


  public boolean isViable(Field field)
  // should simulation continue to run?
  {  return stats.isViable(field); }
    

  // ------------------------------- JPanel inner class ------------------------

  /* Provide a graphical view of a rectangular field. This is 
   * a nested class (a class defined inside a class) which
   * defines a custom component for the user interface. This
   * component displays the field.
   * This is rather advanced GUI stuff - you can ignore this 
   * for your project if you like. */

  private class FieldView extends JPanel
  {
    private final int GRID_VIEW_SCALING_FACTOR = 6;

    private int gridWidth, gridHeight;
    private int xScale, yScale;
    private Dimension size;
    private Graphics g;
    private Image fieldImage;


    public FieldView(int height, int width)
    {
      gridHeight = height;
      gridWidth = width;
      size = new Dimension(0, 0);
    }  // end of FieldView()


    public Dimension getPreferredSize()
    // tell the GUI manager how big we would like the JPanel to be
    { return new Dimension(gridWidth * GRID_VIEW_SCALING_FACTOR,
                           gridHeight * GRID_VIEW_SCALING_FACTOR);
    }


    public void preparePaint()
    {
      if (!size.equals(getSize())) { // if the size has changed...
        size = getSize();
        fieldImage = fieldView.createImage(size.width, size.height);
        g = fieldImage.getGraphics();

        xScale = size.width / gridWidth;
        if (xScale < 1)
          xScale = GRID_VIEW_SCALING_FACTOR;

        yScale = size.height / gridHeight;
        if (yScale < 1)
          yScale = GRID_VIEW_SCALING_FACTOR;
      }
    }  // end of preparePaint()

        
    public void drawMark(int x, int y, Color color)
    // paint on grid location on this field in a given color
    {
      g.setColor(color);
      g.fillRect(x * xScale, y * yScale, xScale - 1, yScale - 1);
    }


    public void paintComponent(Graphics g)
    /* The field view component needs to be redisplayed. Copy the
       internal image to screen. */
    {
      if (fieldImage != null) {
        Dimension currentSize = getSize();
        if (size.equals(currentSize))
          g.drawImage(fieldImage, 0, 0, null);
        else   // Rescale the previous image.
          g.drawImage(fieldImage, 0, 0, currentSize.width, currentSize.height, null);
      }
    }  // end of paintComponent()

  }  // end of FieldView inner class

}  // end of SimulatorView class
