// PredatorBehavior.java
// Andrew Davison, April 2005, ad@fivedots.coe.psu.ac.th
// Sirinart Sakarin, March 2003, s4210315@calvin.coe.psu.ac.th

/* Třída PredatorBehavior spravuje seznam typu BoidsList instancí podtříd
   třídy Boid a odkaz na seznam obětí typu BoidsList, který získá přes odkaz
   na objekt typu PreyBehavior.

   Tato třída svůj seznam a uzel typu BranchGroup sestávající s dalších uzlů
   téhož typu nejdříve inicializuje.

   Dále spravuje jedno rychlostní pravidlo navíc: findClosePrey()
   - pokud je predátor hladový, začne hledat nejbližší kořist.
   Tuto metodu volá každý objekt typu PredatorBoid.

   Třídá dále obsahuje metodu eatClosePrey(), kterou volá objekt typu
   PredatorBoid, když má skutečně sežrat objekt typu PreyBoid, je-li tento
   dostatečně blízko.
*/

import java.util.*;
import javax.media.j3d.*;
import javax.vecmath.*;


public class PredatorBehavior extends FlockBehavior
{
  // škálovací faktor pro rychlost vypočítanou v pravidle findClosePrey()
  private final static float FIND_WEIGHT = 0.2f;
  
  private BoidsList preyList;
  private PreyBehavior preyBeh;

  // pro opakované výpočty
  private Vector3f preyPos = new Vector3f();
  private Vector3f distFrom = new Vector3f();
  

  public PredatorBehavior(int numBoids, Obstacles obs)
  {
    super(numBoids);
    System.out.println("Num. Predators: " + numBoids);
    createBoids(numBoids, obs);
  }


  private void createBoids(int numBoids, Obstacles obs)
  /* Inicializuje seznam typu BoidsList objektů typu PredatorBoid a 
     přidá uzly typu TransformGroup pro tyto agenty k uzlu boidsBG.
     Třída Boid je odvozena od třídy TransformGroup, takže může být přidána
     k uzlu boidsBG přímo.
  */
  { PredatorBoid pb; 
	for(int i=0; i < numBoids; i++){
      pb = new PredatorBoid(obs, this);
	  boidsBG.addChild(pb);    // přidej k uzlu typu BranchGroup
	  boidsList.add(pb);       // přidej do seznamu typu BoidsList
    }
    boidsBG.addChild(this);    // ulož chování predátora přes jeho uzel typu BG
  } // konec metody: createBoids()


  public void setPreyBeh(PreyBehavior pb)
  // ulož chování kořisti
  { preyBeh = pb; }


  public int eatClosePrey(Vector3f boidmos)
  /* Najde nejbližší objekt typu PreyBoid (nebo i více) a sežere jej.
     To způsobí odpoutání objektu od grafu scény a odebrání ze seznamu.
     Vrátí počet sežraných kořistí (obvykle 1 nebo 0).
     Tuto metodu volá metoda animateBoid() třídy PredatorBoid.
  */
  { preyList = preyBeh.getBoidsList();
    int numPrey = preyList.size();
    int numEaten = 0;
    PreyBoid b;

    int i = 0;
	while((b = (PreyBoid)preyList.getBoid(i)) != null) {
      distFrom.set(boidmos);
      distFrom.sub( b.getBoidmos() );
	  if(distFrom.length() < PROXIMITY/3.0) {   // je agent blízko kořisti?
		preyBeh.eatBoid(i);   // kořist nalezena, sněz ji
        numPrey--;
        numEaten++;
	    System.out.println("numPrey: " + numPrey);
      }
      else 
        i++;
	}
    return numEaten;
  } // konec metody: eatClosePrey()



  public Vector3f findClosePrey(Vector3f boidmos)
  /* Najde všechny nejbližší kořisti, načež vytvoří vektor směřující
     k jejich průměrné pozici a vezme z něj stanovený poměr.

     Toto rychlostní pravidlo navíc používá třída PredatorBoid.
     Volá se z její metody doVelocityRules().
  */
  { preyList = preyBeh.getBoidsList();  // získej seznam kořistí
    int numClosePrey = 0;
    preyPos.set(0,0,0);
    Vector3f pos;
    PreyBoid b;

    int i = 0;
	while((b = (PreyBoid)preyList.getBoid(i)) != null) {
      pos = b.getBoidmos();
      distFrom.set(pos);
      distFrom.sub(boidmos);
	  if(distFrom.length() < PROXIMITY*1.5f) {  // vidí dále
        preyPos.add( distFrom );	 // přidej vzdálenost do počítadla
        numClosePrey++;
      }
      i++;
    }
	if (numClosePrey > 0) {
	  preyPos.scale(1.0f/numClosePrey);  // vypočítej průměrnou pozici
      // vynásob pro snížení prudkosti při změně směru a rychlosti
      preyPos.scale(FIND_WEIGHT);
    }
    return preyPos;
  } // konec metody: findClosePrey()


} // konec třídy: PredatorBehavior
