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

/* A fox ages, moves, eats rabbits, and dies.
   This version extends Animal
   Instead of a hunt() method, the fox behaviour is located
   in act(). Many field changes are now carried out with 
   inherited get/set methods.
 * 
 * @author David J. Barnes and Michael Kolling
 * @version 2006.03.30
 */


import java.util.*;


public class Fox extends Animal
{
  // 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 foodLevel;
     // many fields are inherited in this version


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

  public void act(Field currentField, Field updatedField, List<Animal> newAnimals)
  /* A fox hunts for rabbits. It may also breed, die of hunger,
     or die of old age. This was previously the hunt() method. 
  */
  {
    incrementAge();
    incrementHunger();
    if (isAlive()) {  // new foxes are born into adjacent locs
      int births = breed();
      for (int b = 0; b < births; b++) {
        Fox newFox = new Fox(false);
        newAnimals.add(newFox);
        newFox.setLocation(updatedField.randomAdjLoc( getLocation() ));
        updatedField.place(newFox);
      }
      // move towards the source of food if found.
      Location newLoc = findFood(currentField, getLocation());

      if (newLoc == null) // no food found - move randomly
        newLoc = updatedField.freeAdjLoc(getLocation());
 
      if (newLoc != null) {
        setLocation(newLoc);
        updatedField.place(this); // sets location
      }
      else   // can neither move nor stay - overcrowding - all locations taken
        setDead();
    }
  }  // end of act()

    
  private void incrementAge()
  // this could cause the fox's death
  { setAge(getAge() + 1);
    if (getAge() > MAX_AGE)
      setDead();
  }  // end of incrementAge()
    

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

  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();
      Animal animal = field.getAnimalAt(where);   // was Object
      if (animal instanceof Rabbit) {
        Rabbit rabbit = (Rabbit) animal;
        if (rabbit.isAlive()) { 
          rabbit.setDead();
          foodLevel = RABBIT_FOOD_VALUE;
          return where;
        }
      }
    }
    return null;
  }  // end of findFood()

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

    
  public String toString()
  {  return "Fox, age " + getAge();  }


  private boolean canBreed()
  {  return (getAge() >= BREEDING_AGE);  }

}  // end of Fox class
