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

/* A fox ages, moves, eats rabbits, and dies.
 * 
 * @author David J. Barnes and Michael Kolling
 * @version 2006.03.30
 */


import java.util.*;


public class Fox
{
  // Characteristics shared by all foxes (static fields).
  private static final int BREEDING_AGE = 10;
  private static final int MAX_AGE = 150;
  private static final double BREEDING_PROBABILITY = 0.09;
  private static final int MAX_LITTER_SIZE = 3;    // max no. of births
  private static final int RABBIT_FOOD_VALUE = 4;
       // The no. of steps a fox can go before it has to eat again.

  // A shared random number generator to control breeding
  private static final Random rand = new Random();
    

  // fox characteristics
  private int age;
  private boolean isAlive;
  private Location location;
  private int foodLevel; // increased by eating rabbits


  public Fox(boolean randomAge)
  /* A fox can be created with zero age
     and not hungry, or with a random age. */
  {
    age = 0;
    isAlive = true;
    if (randomAge) {
      age = rand.nextInt(MAX_AGE);
      foodLevel = rand.nextInt(RABBIT_FOOD_VALUE);
    }
    else  // leave age at 0
      foodLevel = RABBIT_FOOD_VALUE;
  }  // end of Fox()
    

  public void hunt(Field currentField, Field updatedField, List<Fox> newFoxes)
  /* A fox breeds, moves about looking for food, 
     or dies of old age, hunger, or overcrowding.
  */
  {
    incrementAge();      // may die
    incrementHunger();   // may die
    if (isAlive) {
      int numBirths = breed();   // have fox breed
      for (int b = 0; b < numBirths; b++) {
        Fox newFox = new Fox(false);     // create new fox
        newFoxes.add(newFox);
        Location loc = updatedField.randomAdjLoc(location);
        newFox.setLocation(loc);         // place new fox in field
        updatedField.place(newFox, loc);
      }

      // try to move this fox
      Location newLoc = findFood(currentField, location);
      if (newLoc == null) // if no food found then move randomly
        newLoc = updatedField.freeAdjLoc(location);

      if (newLoc != null) {  // if new location is free
        setLocation(newLoc);
        updatedField.place(this, newLoc);
      }
      else  // can't move - so die due to overcrowding
        isAlive = false;
    }
  }  // end of hunt()

    
  private void incrementAge()
  // this could cause the fox's death
  { age++;
    if (age > MAX_AGE)
      isAlive = false;
  }
    

  private void incrementHunger()
  // this could cause the fox's death
  { foodLevel--;
    if (foodLevel <= 0)
      isAlive = false;
  }
    

  private Location findFood(Field field, Location loc)
  /* Make the fox look for rabbits adjacent to its current location.
     Only the first live rabbit is eaten. */
  {
    Iterator<Location> adjLocs = field.getAdjLocs(loc);
    while (adjLocs.hasNext()) {
      Location where = adjLocs.next();
      Object animal = field.getObjectAt(where);
      if (animal instanceof Rabbit) {
        Rabbit rabbit = (Rabbit) animal;
        if (rabbit.isAlive()) { 
          rabbit.setEaten();
          foodLevel = RABBIT_FOOD_VALUE;
          return where;
        }
      }
    }
    return null;
  }  // end of findFood()

        
  private int breed()
  /* Generate a number representing the number of births,
     if the fox can breed. */
  {
    int numBirths = 0;
    if (canBreed() && (rand.nextDouble() <= BREEDING_PROBABILITY))
      numBirths = rand.nextInt(MAX_LITTER_SIZE) + 1;
    return numBirths;
  }  // end of breed()


  private boolean canBreed()
  // a fox can breed if it has reached the breeding age
  { return (age >= BREEDING_AGE); }
    
  public boolean isAlive()
  { return isAlive;  }

  public void setLocation(int row, int col)
  { location = new Location(row, col);  }

  public void setLocation(Location loc)
  { location = loc; }

}  // end of Fox class
