package alive;

/**
 * <ALIVE Project>
 * Experiment 1 Food agent
 * 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 xp1_Food extends Agent {
  public Actor_Sphere actor = null;
  public int generation = 1;
  public double scale = 0.2, size = 0.001,
      energy = rnd(-4,8),
      grow_rate = rnd(0.0001,0.001),
      temperature = 30,
      lifetime= 99999,
      life = 99999,
      tolerance = 20,
      metabolism = 0,
      signal = 1;
// ----------------------------- Constructors ------------------------------
  public xp1_Food(Environment env) { // Constructor
    this.configureToEnvironment(env);
    speed = generateRandomVector(); speed.scale(.02);
    super.makeAlive();
  }
  public xp1_Food(xp1_Food parental) { // Constructor
    this.configureToEnvironment(parental.env);
    Vector3d inc = generateRandomVector();
    inc.scale(rnd(0.1,1));
    position.set(parental.position);
    position.add(inc);
    if (probability(.1)) {
      speed.set(inc.x,inc.y,inc.z); parental.speed.set(-inc.x,-inc.y,-inc.z);
    }
    if (probability(.9)) { // 90% chance of being of the same kind
      energy = parental.energy;
      grow_rate = parental.grow_rate * rnd(.9, 1.1); // 10% variation
    } else energy = Math.abs(parental.energy);
    generation = parental.generation+1;
    life = parental.life;
    super.makeAlive();
  }
  public synchronized void reproduce() {
    energy = energy/2;
    if (env.nAgents<env.config.POP_LIMIT) env.addAgent(new xp1_Food(this));
  }

  // --------------------------- Overriden methods --------------------------
  public void startUp() {
    lifetime = life;
    env.adjust("food",1);
    if (signal(energy) > 0) {
      color.set(.0f, .5f, .0f);
      env.adjust("green", 1);
      message("+");
    } else {
      color.set(.5f, .0f, .0f);
      grow_rate = 0.0001;
      env.adjust("red", 1);
      signal = -1;
      message("-");
    }
  }
  public void behavior() {
    lifetime--;
    if (lifetime < 0) metabolism = 0;
    else metabolism = 1-Math.abs(temperature-env.get("temperature"))/tolerance;
    energy = energy -.001 + signal(energy)* grow_rate * env.get("radiation")*metabolism;
    size = scale*Math.pow(3*Math.abs(energy/12.57), 1/3.0);
    if (Math.abs(energy) > 10) reproduce();
    if (Math.abs(energy) < 1)  die();
  }

  public Actor createActor() {
    this.actor = new Actor_Sphere();
    return actor;
  }

  public void updateActor() {
    actor.set(position,size);
  }

  public synchronized void die() {    // Destroy created objects and actors
    if (signal > 0) env.adjust("green",-1);
    else env.adjust("red",-1);
    env.adjust("food",-1);
    message("x");
    super.die();
  }

// ----------------------- Overrided access methods -----------------------
  public double get(String s) {
    if (s.equals("energy")) return energy;
    if (s.equals("lifetime")) return lifetime;
    if (s.equals("life")) return life;
    if (s.equals("temperature")) return temperature;
    if (s.equals("tolerance")) return tolerance;
    if (s.equals("grow_rate")) return grow_rate;
    if (s.equals("metabolism")) return metabolism;
    return 0;
  }
  public synchronized boolean set(String s, double val) {
    if (s.equals("energy")) energy = val;
    if (s.equals("lifetime")) lifetime = val;
    if (s.equals("life")) life = val;
    if (s.equals("temperature")) temperature = val;
    if (s.equals("tolerance")) tolerance = val;
    if (s.equals("grow_rate")) grow_rate = val;
    if (s.equals("metabolism")) metabolism = val;
    return true;
  }
  public synchronized boolean adjust(String s, double val) {
    return set(s,get(s)+val);
  }
  public String getInfo() {
    String s = new String();
    s = id + " Food Agent\nenergy = " + round(energy,4);
    s = s + "\nlifetime = " + round(lifetime,4);
    s = s + "\nlife = " + round(life,4);
    s = s + "\ntemperature = " + round(temperature,4);
    s = s + "\ntolerance = " + round(tolerance,4);
    s = s + "\nmetabolism = " + round(metabolism,4);
    s = s + "\ngrow_rate = " + round(grow_rate,4);
    s = s + super.getInfo();
    return s;
  }
}