package alive;

/**
 * <ALIVE Project>
 * Spheric Actor
 * Default Actor for simple experiments
 * attributes can be mapped into size, color and
 * transparency
 * LSI - POLI - USP
 */

import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.image.*;

public class Actor extends BranchGroup {
  public int id = 0;
  public int latency = 0;
  public String model = "Agent";
  public String texturefile = "";
  public float transparency = 0;
  public double scale = .01;
  Vector3d pos = new Vector3d();
  Vector3d dir = new Vector3d();
  public Color3f
      emissiveColor = new Color3f(0.0f, 0.0f, 0.0f),
      ambientColor = new Color3f(0.6f, 0.6f, 0.6f),
      diffuseColor = new Color3f(0.6f, 0.6f, 0.6f),
      specularColor = new Color3f(1.0f, 1.0f, 1.0f),
      c =  null;
  public static Color3f
      black = new Color3f(0.0f, 0.0f, 0.0f),
      white = new Color3f(1.0f, 1.0f, 1.0f),
      red = new Color3f(1.0f, 0.0f, 0.0f),
      green = new Color3f(0.0f, 1.0f, 0.0f),
      blue = new Color3f(0.0f, 0.0f, 1.0f),
      yellow = new Color3f(1.0f, 1.0f, 0.0f),
      cyan = new Color3f(0.0f, 1.0f, 1.0f),
      magenta = new Color3f(1.0f, 0.0f, 1.0f);
  public float shininess = 100.0f;
  private Transform3D t = new Transform3D(),
      t1 = new Transform3D(),
      t2 = new Transform3D();
  TransformGroup tg = new TransformGroup(t);
  Appearance ap = new Appearance();
  TransparencyAttributes ta = new TransparencyAttributes();
  private double xRot, yRot, z;

  public final void build() {
    Material m = new Material(ambientColor,
                              emissiveColor,
                              diffuseColor,
                              specularColor, shininess);
    m.setLightingEnable(true);
    m.setCapability(m.ALLOW_COMPONENT_READ);
    m.setCapability(m.ALLOW_COMPONENT_WRITE);
    ap.setMaterial(m);
    ap.setCapability(ap.ALLOW_MATERIAL_READ);
    ap.setCapability(ap.ALLOW_MATERIAL_WRITE);
    tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    tg.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
    createGeometry();
    setCapability(ALLOW_DETACH);
    set(pos,scale);
    addChild(tg);
    setUserData(model);
  }

  public void set(Vector3d position,double scale0) {
    pos.set(position);
    scale = scale0;
    t.set(pos);
    t.setScale(scale);
    tg.setTransform(t);
  }

  public void set(Vector3d position, Vector3d direction, double scale0) {
    pos.set(position);
    dir.set(direction);
    scale = scale0;
    xRot = -1 * Math.asin(dir.y);
    z = dir.z; if (dir.y!=0) z = z/Math.cos(dir.y);
    yRot = Math.acos(z) * signal(dir.x);
    t.set(t.IDENTITY);
    t1.rotX(xRot);
    t2.rotY(yRot);
    t.mul(t2,t1);
    t.setTranslation(pos);
    t.setScale(scale);
    tg.setTransform(t);
  }

  public Transform3D getTransform() { return t; }
  public TransformGroup getTransformGroup() { return tg; }
  public Material getMaterial() { return ap.getMaterial(); }
  public void createGeometry() {  } // The only one that must be overriden

  public void setTransparency(float transparency) {
    this.transparency = transparency;
    ta.setTransparencyMode(ta.BLENDED);
    ta.setTransparency(transparency);
    ap.setTransparencyAttributes(ta);
  }

  public void setTexture(String filename) {
    texturefile = filename;
    java.net.URL texImage = null;
    try { texImage = new java.net.URL(filename); }
    catch (java.net.MalformedURLException ex) { System.out.println(ex.getMessage()); }
    TextureLoader tl = new TextureLoader(texImage, new java.awt.Panel());
    ap.setTexture(tl.getTexture());
    TextureAttributes att = new TextureAttributes();
    att.setTextureMode(TextureAttributes.MODULATE);
    ap.setTextureAttributes(att);
  }

  public final void  setColor(Color3f color) {
    emissiveColor.set(color);
    ap.getMaterial().setEmissiveColor(emissiveColor);
  }
  public final void  setColor(float r, float g, float b) {
    emissiveColor.set(r, g, b);
    ap.getMaterial().setEmissiveColor(emissiveColor);
  }
  public final void setAllColors() {
    ap.getMaterial().setEmissiveColor(emissiveColor);
    ap.getMaterial().setAmbientColor(ambientColor);
    ap.getMaterial().setDiffuseColor(diffuseColor);
    ap.getMaterial().setSpecularColor(specularColor);
    ap.getMaterial().setShininess(shininess);
  }

  public final Color3f getColor() {
    return emissiveColor;
  }

  public static double signal(double val) {
    if (val<0) return -1;
    else return 1;
  }
}
  // Hints
  // Avoid call "new" function, reuse objects!

