package alive;

/**
 * <ALIVE Project>
 * Agent Template class
 * Food is an animated agent, just grow and splits
 * anyway, uses the Agent class to implement procedures
 */

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

public class XP_Template_Agent extends Agent {
  // *** Change Class name to match your filename

  // Local Agent variables
  double gain = 0;
  double life = 10000;

// ----------------------------- Constructors ------------------------------
  public XP_Template_Agent(Environment env) {
  // *** Change Constructor name to match your class name
  // ** Enviroment call to constructor
    super.configureToEnvironment(env); // *** Update references, don't remove
    setParameters(); // User shared method
    // position.set(custom.position.x,y,z); // Default = random position
    // message("T"); // "Agent Created" char code
    super.makeAlive(); // *** Final agent computations, required
  }

  public XP_Template_Agent(XP_Template_Agent parent) {
  // *** Change names to match your class name
  // ** Agent (reproduction) call to constructor
    super.configureToEnvironment(parent.env); // Don't remove
    setParameters(); // User shared method
    for (int i = 0; i < param.length; i++) {
      // Mutational and variational operators
      if (probability(.95)) set(i, parent.paramName[i], parent.param[i]);
      // 5% change of max 20% mutation
      if (probability(.05)) param[i] = param[i] * rnd(.8, 1.2);
    }
    position.set(parent.position); speed.set(parent.speed); speed.negate();
    set("energy", parent.get("energy"));
    set("lifetime", life);
    // message("t"); // "Agent Created" char code
    super.makeAlive(); // *** Final agent computations, required
  }

// ----------------------------- User methods ------------------------------
  public synchronized void reproduce() {
    set("energy", get("energy")/2); // half-half reproduction
    if (env.nAgents<env.config.POP_LIMIT) // Not required, but saves some computation
      env.addAgent(new XP_Template_Agent(this));
  }
  void setParameters() {
    // Init vectors & parameters
    param = new double[7];
    paramName = new String[7];
    set(0, "energy", 6);
    set(1, "temperature", env.get("temperature"));
    set(2, "r", rnd(-1,1));
    set(3, "g", rnd(-1,1));
    set(4, "b", rnd(-1,1));
    set(5, "lifetime", life);
    set(6, "reproduction", 20);
    speed = generateRandomVector();
    speed.scale(rnd(0,1));
  }

// --------------------------- Overrided methods ----------------------------
  public void behavior() { //  ***  Main Cycle
  // *** Replace with your agent run-time computations
    adjust("lifetime",-1);
    gain = ( -.001 // Round activity energy loss
             - test(get("lifetime")<0) * Math.abs(get("lifetime"))/1000 // metabolism function
             - Math.abs( get("temperature") - env.get("temperature") )/40
             + env.get("r")*get("r") + env.get("g")*get("g") + env.get("b")*get("b")
             )/100; // Converted radiation
    adjust("energy",gain);
    if (probability(.05)) speed.set(speed.x+rnd(-1,1),speed.y+rnd(-1,1),speed.z+rnd(-1,1));
    if ((gain<0||get("energy")>get("reproduction"))&&probability(.01)) reproduce();
    if (get("energy")<.1)  die();
  }
  public synchronized void die() {
    // message("x");
    super.die(); // Destroy created objects and actors
  }
  public String getInfo() {
  /* *** Add information to default agent info
   *
   * String must start with Agent number followed by space
   * Agent name and variables are sugested aditions to help
   * to identify agent types as well as append the default agent info
   */
    String s = id + " Template Agent\n" +
        "gain = " + round(gain,5) +
        super.getInfo();
    return s;
  }

  // ------------------------ Actor manipulation ----------------------------
  public Actor createActor() {
  //*** Replace by your actor preferences
    this.actor = new Actor_Sphere();
    //actor.setTransparency(0.3f);
    //actor.setTexture(env.config.codeBase + "textures/shock-bw.gif");
    return actor;
  }

  public void updateActor() {
  // *** Replace by your own run-time actor updates
    size = .5 * Math.pow(3*get("energy")/12.57, 1/3.0);
    color.set( (1+(float)get("r"))/4,
               (1+(float)get("g"))/4,
               (1+(float)get("b"))/4);
    // If you use any of above variables for computations,
    // put them on the behavior() method,
    // this method doesn't run if the renderer is disabled

    actor.set(position,direction,size);
    // Can use any of actor's access methods
  }
}
