import java.awt.*;
import java.awt.event.*;
import WizCard;
import Util;

public class ObjectFromEvent extends WizCard implements ItemListener
 {
  Choice eventChoice, refChoice, clockChoice;
  TextField vText, properText;

  Vector refVector;

  Universe u;
  PhysicalObject obj;
  int type;
  
  public ObjectFromEvent(Wizard w, Universe u, PhysicalObject obj, int type)
   {
    super(w);
    this.u = u;
    this.obj = obj;
    this.type = type;

    isFinal = true;  // Done! instead of next>>

    setLayout(new GridBagLayout());

    Util.add(this,
        new Label("Please specify the following parameters for the initial location of" + ((type == ObjectInit.LONG) ? " the center of " : " ") + obj.name + "."),
        Util.ENDL); 

    Util.add(this,
        new Label("Event: "),
        Util.DEFAULT); 

    Util.add(this,
        eventChoice = new Choice(),
        Util.ENDL);

    if (u.lorentz_symmetry)
     {
        Util.add(this,
          new Label("There is currently no preferred velocity in this scenario."),
          Util.ENDL);
        Util.add(this,
          new Label("Thus, there is no need to specify an initial velocity."),
          Util.ENDL);
     }
    else
     {
      Util.add(this,
        new Label(obj.name + "'s initial velocity is measured with respect to"),
        Util.DEFAULT);

      Util.add(this,
        refChoice = new Choice(),
        Util.ENDL); 

      Util.add(this,
        new Label("and is equal to: "),
        Util.DEFAULT); 

      Util.add(this,
        vText = new TextField("0.0",10),
        Util.ENDL);

      Util.add(this,
        new Label(obj.name + "'s clock is initially"),
        Util.DEFAULT);

      Util.add(this,
        clockChoice = new Choice(),
        Util.DEFAULT);

      Util.add(this,
        properText = new TextField("0.0",10),
        Util.ENDL);

      int i;

      clockChoice.add("set to time t = ");
      clockChoice.add("synchronized with ref. object");

      clockChoice.addItemListener(this);

      for (i = 0; i < u.events.size(); i++) 
        eventChoice.add(u.eventAt(i).name);

      for (i = 0; i < u.frames.size(); i++)
        addRef(u.frameAt(i).name, u.frameAt(i));

      for (i = 0; i < u.inertialObjects.size(); i++)
        addRef(u.inertialAt(i).name, u.inertialAt(i));

      for (i = 0; i < u.variableObjects.size(); i++)
        addRef(u.variableAt(i).name, u.variableAt(i));

      for (i = 0; i < u.longObjects.size(); i++)
        addRef(u.longAt(i).name, u.longAt(i));
     }
   }

  void addRef(String name, Object o)
   {
    refChoice.add(name);
    refVector.addElement(o);
   }

  public void itemStateChanged(ItemEvent e)
   {
    properText.setEditable(clockChoice.getSelectedIndex() == 0);
   }

  double properTime(SpacetimePoint p, Object o)
   {
    if (o instanceof ReferenceFrame) return ((ReferenceFrame)o).t(p);
    PhysicalObject obj = (PhysicalObject) o;

    return obj.intersect(new ReferenceFrame(), p.t);
   }

  boolean coincident(SpacetimePoint p, Object o)
   {
    if (o instanceof ReferenceFrame) return true;
    PhysicalObject obj = (PhysicalObject) o;

    if (!obj.existsAt(new ReferenceFrame(), p.t)) return false;

    double loc = obj.abs_x(properTime(p,o));

    if (loc < p.x - 0.001 || loc > p.x + 0.001) return false;

    return true;
   }

  double velocity(SpacetimePoint p, Object o)
   {
    if (o instanceof ReferenceFrame) return ((ReferenceFrame)o).v;
    PhysicalObject obj = (PhysicalObject) o;

    return obj.velocity(properTime(p,o));
   }

  public void doNext()
   {
    int i = eventChoice.getSelectedIndex();

    SpacetimeEvent e = u.eventAt(i);
     
    double v = 0;

    if (!u.lorentz_symmetry)
     {
      try
       {
        v = Util.doubleValue(vText);
       }
      catch (NumberFormatException e)
        {
         System.out.println("Error: v must be a number");
         return;
        }
     }

    if (v >= 1 || v <= -1)
     {
      System.out.println("Error: objects cannot exceed the speed of light.");
      return;
     }

    obj.setInitialLocation(e);

    Object refObj = refVector.elementAt(refChoice.getSelectedIndex());

    if (!coincident(e,refObj))
     {
      System.out.println("Error: Reference object is not co-incident with event.");
      return;
     }

    double v1 = velocity(e,refObj);

    obj.setInitialVelocity((v+v1)/(1+v*v1));

    double t0 = 0;

    switch (clockChoice.getSelectedIndex())
     {
      case 0: 
       try
        {
         t0 = Util.doubleValue(properText);
        }
       catch (NumberFormatException e)
        {
         System.out.println("Error: t must be a number");
         return;
        }
       break;
      case 1:
       t0 = properTime(e,refObj); 
       break;
     }   

    obj.setInitialProperTime(t0);

    switch (type)
     {
      case ObjectInit.INERTIAL: u.addInertialObject((InertialObject)obj); break;
      case ObjectInit.VARIABLE: u.addVariableObject((VariableObject)obj); break;
      case ObjectInit.LONG:     u.addLongObject((LongObject)obj); break;
     }

    w.reset();
   }
 }
