package pigeons;
import java.awt.Color;

/**
 * Classe permettant de gérer un oiseau
 * 
 * Implemente l'interface Runnable, ce qui permet d'executer les actions d'un
 * oiseau dans un thread.
 * 
 * @author Valentin THEDON
 * @author Nathan AMSELLEM
 * 
 * @version %I%, %G%
 * @since 1.0
 */

public class Bird implements Runnable {

  /**
   * Positiion de l'oiseau
   */
  private Position position;

  /**
   * Parc de rattachement de l'oiseau
   */
  private Park park;
  private boolean isAlive = true;

  /**
   * Couleur d'un oiseau
   */
  public static Color COLOR = Color.BLACK;
  /**
   * Temps de raffraichissement d'un oiseau (en ms)
   */
  public static int REFRESH_TIME = 20;
  /**
   * Vitesse d'un oiseau
   */
  public static int VELOCITY = 10;

  /**
   * Constructeur de l'objet oiseau
   * 
   * @param position position de l'oiseau
   * @param park parc de rattachement de l'oiseau
   */
  public Bird(Position position, Park park) {
    this.position = position;
    this.park = park;
    this.park.addBird(this);
  }

  /**
   * Constructeur de l'objet oiseau
   * 
   * @param x position sur l'axe des abscisses de l'oiseau
   * @param y position sur l'axe des ordonnées de l'oiseau
   * @param park parc de rattachement de l'oiseau
   */
  public Bird(int x, int y, Park park) {
    this(new Position(x, y), park);
  }

  /**
   * Detecte la nourriture la plus proche de l'oiseau
   * 
   * @return Food L'objet representant la nourriture la plus proche
   */
  public Food findNearestFood() {
    Food nearestFood = null;
    int minDistance = Integer.MAX_VALUE;
    int i = 0;
    while(i < park.getFoods().size()){
      Food f = park.getFoods().get(i);
      if (this.position.distance(f.getPosition()) < minDistance && f.isFresh()) {
        nearestFood = f;
        minDistance = this.position.distance(f.getPosition());
      }
      i++;
    }
    return nearestFood;
  }

  @Override
  public void run() {
    while (isAlive) {
      Food nearestFood = findNearestFood();
      if (nearestFood != null) {
        this.moveTo(nearestFood);
        Food onFood = this.getOnFood();
        if (onFood != null && onFood.isFresh()) {
          this.park.removeFood(onFood);
        }
      }
      try {
        Thread.sleep(REFRESH_TIME);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }

  /**
   * Deplace un oiseau vers une position
   * 
   * @param toMove La position vers laquelle nous devous nous deplacer
   */
  public void moveTo(Position toMove) {
    if (this.position.distance(toMove) <= ((VELOCITY * REFRESH_TIME * 0.01))) {
      this.position.moveTo(toMove.getX(), toMove.getY());
    } else {
      float x = this.position.getX()
          + ((VELOCITY * REFRESH_TIME * 0.01f)
              * ((toMove.getX() - this.position.getX()) / (float) this.position.distance(toMove)));
      float y = this.position.getY()
          + (((VELOCITY * REFRESH_TIME * 0.01f))
              * ((toMove.getY() - this.position.getY()) / (float) this.position.distance(toMove)));
      this.position.moveTo(Math.round(x), Math.round(y));
    }
  }

  /**
   * Deplacer l'oiseau vers une nourriture
   * 
   * @param food La nourriture vers laquelle l'oiseau doit se diriger
   */
  public void moveTo(Food food) {
    this.moveTo(food.getPosition());
  }

  /**
   * Effraie l'oiseau, a pour but de le déplacer à une position aléatoire
   */
  public void frighten() {
    this.position.moveTo(Math.round((float) Math.random() * park.getWidth()),
        Math.round((float) Math.random() * park.getHeight()));
    ;
  }

  /**
   * @return Food Renvoie la nourriture sur laquelle nous nous situons, ou null si nous sommes sur aucune nourriture
   */
  public Food getOnFood() {
    for (Food f : park.getFoods()) {
      if (this.position.distance(f.getPosition()) == 0)
        return f;
    }
    return null;
  }

  /**
   * Obtenir le parc dans lequel l'oiseau evolue
   * 
   * @return  Le parc dans lequel l'oiseau évolue
   */
  public Park getPark() {
    return park;
  }

  /**
   * Définir un parc dans lequel l'oiseau evoluera
   * 
   * @param park Le parc dans lequel l'oiseu évoluera
   */
  public void setPark(Park park) {
    this.park = park;
  }

  /**
   * 
   * @return boolean vrai si l'oiseau est en vie, faux sinon.
   */
  public boolean isAlive() {
    return this.isAlive;
  }

  /**
   * Obtenir la position de l'oiseau
   * 
   * @return Position la position actuelle de l'oiseau
   */
  public Position getPosition() {
    return this.position;
  }
}
