import PhysicalObject;
import MyCanvas;

public class VariableObject extends PhysicalObject
 {
  public static final int BEFORE = 0;
  public static final int AFTER = 1;
  public static final int AVERAGE = 2;

  public int continuity;  // how to handle velocity at turnarounds

  Vector frames;
  double frame_origin_time;
  boolean turnaround;

  public VariableObject()
   {
    this(new SpacetimePoint, 0);
   }

  public VariableObject(SpacetimePoint p0, double abs_v)
   {
    super();
    frames = new Vector();
    frames.addElement(new ReferenceFrame(p0,abs_v));
    this.continuity = BEFORE;
    frame_origin_time = 0;
    turnaround = false;
   }

  public VariableObject(ReferenceFrame f, double x, double t, double v)
   {
    this(f.location(x,t), f.abs_v(v));
   }

  public double gamma(double v)
   {
    return 1 / Math.sqrt(1 - v * v);
   }

  ReferenceFrame getFrame(int i)
   {
    return (ReferenceFrame) frames.elementAt(i);
   }

  double lifespan(int i)
   {
    return getFrame(i).t(getFrame(i+1).origin());
   }

  public void setInitialLocation(SpacetimePoint p)
   {
    frames.getFrame(0).setOrigin(p);
   }

  public void setInitialVelocity(double v)
   {
    frames.getFrame(0).v = v;
   }

  int getCurrentFrame(double properTime)
   { 
    int i = 0;
    double t;
    frame_origin_time = initProperTime;
    turnaround = false;

    while (true)
     {
      if (i == frames.size() - 1) return i;
      
      t = properTime - frame_origin_time - lifespan(i);
      if (t < -0.0001) return i;
      if (t < 0.0001) { turnaround = true; return i; }
      frame_origin_time += lifespan(i);
      i++;
     }   
   }

  ReferenceFrame turnaroundFrame(int i)
   {
    switch (continuity)
     {
      case BEFORE: return getFrame(i);
      case AFTER:  frame_origin_time += lifespan(i); return getFrame(i+1);
      case AVERAGE:
        frame_origin_time += lifespan(i);
        SpacetimePoint p = getFrame(i+1).origin();
        double v1 = getFrame(i).v;
        double v2 = getFrame(i+1).v;
        double v = (v1 * v2 + 1 - 1/(gamma(v1)*gamma(v2)))/(v1+v2);
        return new ReferenceFrame(p, v);
     } 
   }

  public double abs_t(double properTime)
   {
    int i = getCurrentFrame(properTime);

    return getFrame(i).abs_t(0,properTime - frame_origin_time);
   }

  public double abs_x(double properTime)
   {
    int i = getCurrentFrame(properTime);

    return getFrame(i).abs_x(0,properTime - frame_origin_time);
   }

  public double velocity(double properTime)
   {
    int i = getCurrentFrame(properTime);

    if (turnaround)
      return turnaroundFrame(i).v;
    else
      return getFrame(i).v;
   }

  public void display(MyCanvas g)
   {
    g.setColor(color);

    for (int i = 0; i < frames.size(); i++)
     {
      ReferenceFrame f = getFrame(i);
      if (i == 0 && prehistoric)
        g.drawBackwardLine(f.origin(), f.v);
      if (i < frames.size() - 1)
        g.drawLine(f.origin(), getFrame(i+1).origin());
      else if (immortal)
        g.drawForwardLine(f.origin(), f.v);
      else
        g.drawLine(f.origin(), destruction());
   }

// Fix all this!

  public double intersect(ReferenceFrame f, double t)
   {
    return initProperTime;
   }  

  public ReferenceFrame closest(SpacetimePoint p)
   {
    ReferenceFrame f = new ReferenceFrame(this);
    SpacetimePoint offset = f.location(0,f.t(p));
 
    f.x0 += offset.x;
    f.t0 += offset.t;
 
 
    return f;
   }

 }
