/*
 * DrawableClassicalParticle.java
 *
 * Created on November 7, 2004, 7:16 AM
 */

package JSciDraw.physics;

import JSciDraw.physics.*;
import JSciDraw.physics.fields.*;
import JSciDraw.physics.forces.Constraints;
import JSciDraw.interfaces.*;
import JSci.maths.*;
import JSci.physics.*;
import java.awt.*;
import java.awt.geom.*;
import java.util.*;
/**
 *
 * @author  arturo, modified by przemek 16.12.2004; 0:15 , modified by barbara,
 * applied constraints in a simple form
 */
public class ClassicalParticleV2D extends ClassicalParticle implements Drawable2D, Moveable2D{
    protected Color color=Color.red;
    protected double charge=0;
    protected double r = 5;
    protected Shape area0 = new Ellipse2D.Double(-r,-r,2*r,2*r);
    protected Shape area;
    protected Shape areaOld;
    protected AffineTransform af = new AffineTransform();
    protected ArrayList forces = new ArrayList();
    public ArrayList moveableObjects = new ArrayList();
    protected ArrayList generatedFields=new ArrayList();
    public double xOl, yOl; //poprzednie pozycje
    protected AbstractDoubleVector sumForce=new Double2Vector(0,0);
    
    //flagi odpowiadające za wlasnosci czastki
    protected boolean onConstraints=false;
    protected boolean hide=false;
    protected boolean grav=false;
    public Constraints constr;
    
    
    /** Creates a new instance of DrawableClassicalParticle */
    public ClassicalParticleV2D() {
        super(2);
    }
    public void setCharge(double charge)
    {
      this.charge=charge;
        if (charge>0) setColor(Color.green);
         else if (charge<0) setColor(Color.blue);
          else setColor(Color.red);
        addField(new CoulombField(this));
   }
 
   public void applyGravity(){
        grav = true;
        addField(new GravityField2(this));      
   }
    
   public double getCharge(){
       return charge;
   }
    
    
    public void setDrawRadius(int a){
        r=a;
        area0=new Ellipse2D.Double(-a,-a,2*a,2*a);
    }
    public void setHidden(boolean b)  {   hide=b;   }
    public boolean isHidden()  {  return hide;   }
    public void setConstraintsOff()  {   onConstraints=false;   }

    public void applyConstraints(Constraints c){
        onConstraints=true;
        this.constr=c;
    }
    
    public void draw2D(java.awt.Graphics2D g2D) {
     if (!hide){
        g2D.setColor(color);
        af.setToIdentity();
        af.translate(getPosition().getComponent(0), getPosition().getComponent(1));
        area = af.createTransformedShape(area0); 
        g2D.fill(area);
       }
     if (onConstraints){
            constr.draw(this,g2D);
        }
     if (charge!=0){
         if (charge>0) g2D.setColor(Color.red);
         else g2D.setColor(Color.yellow);
      double x = this.getPosition().getComponent(0);
      double y = this.getPosition().getComponent(1);
      double x1 = x-3;
      double x2 = x+3;
      double y1 = y-3;
      double y2 = y+3;
      if (charge!=0) g2D.drawLine((int)x1, (int)y, (int)x2,(int)y);  
      if (charge>0) g2D.drawLine((int)x, (int)y1, (int)x,(int)y2);
     }
     if (grav) {
         g2D.setColor(Color.blue);
         //rysuj
     }
     dr(moveableObjects,g2D);
    }    
    
    public void erase2D(java.awt.Graphics2D g2D) {
      if (!hide){
        g2D.setColor(Color.white);
        af.setToIdentity();
        af.translate(xOl, yOl);
        areaOld=af.createTransformedShape(area0); 
        g2D.fill(areaOld);
        }
     if (onConstraints){
            constr.erase(this,g2D);
        }
      er(moveableObjects,g2D);
    }
    public AbstractDoubleVector getForce(){
        return sumForce;
    }
    public void addToSumForce(AbstractDoubleVector t){
        sumForce=sumForce.add(t);
    }
    public AbstractDoubleVector countFreeForce()
    {
        AbstractDoubleVector temp=new Double2Vector();
        Iterator i = forces.iterator();
        while(i.hasNext()){
            temp=temp.add(((Force)i.next()).getVector(1));   
        }
        return temp;
    }
    public void calculateForces(double dt) {
        sumForce=sumForce.add(countFreeForce());
        if (moveableObjects.size()>0) calc(moveableObjects,dt);
     }
    private void mv(ArrayList a,double dt)
    {
      Iterator i=a.iterator();
      while (i.hasNext())
       ((MoveableObject)i.next()).moveBranch(dt);
      i=a.iterator();
      AbstractDoubleVector trans=this.getPosition().subtract(new Double2Vector(xOl,yOl));
      while (i.hasNext())
       ((MoveableObject)i.next()).translateBranch(trans);//tu na razie nie ma nowego interfejsu
    }
    private void calc(ArrayList a, double dt)
    {
      Iterator i=a.iterator();
      while (i.hasNext())
       ((MoveableObject)i.next()).calculateForces(dt);
    }
    
    private void dr(ArrayList a,Graphics2D g2D)
    {
      Iterator i=a.iterator();
      while (i.hasNext())
       ((Drawable2D)i.next()).draw2D(g2D);
    }
    private void er(ArrayList a,Graphics2D g2D)
    {
      Iterator i=a.iterator();
      while (i.hasNext())
       ((Drawable2D)i.next()).erase2D(g2D);
    }
    
    public void move2D(double dt) {
        xOl=getPosition().getComponent(0);
        yOl=getPosition().getComponent(1);
        if (onConstraints)
          constr.move(this,sumForce,dt);
        else {
           accelerate(sumForce.scalarDivide(getMass()),dt);
           super.move(dt);
        }
        if (moveableObjects.size()>0) mv(moveableObjects,dt);
        sumForce=new Double2Vector(0,0);
    }
    public void addExtForce(Force extForce)    {
       forces.add(extForce);
    }
    public void setPosition(AbstractDoubleVector pos) {
        af.setToIdentity();
        af.translate(pos.getComponent(0), pos.getComponent(1));
        area = af.createTransformedShape(area0); 
        areaOld = area;
        super.setPosition(pos);
    }
    //adds another field, for example gravity field
    public void addField(CentralForceField f){
        if (f.center==this) generatedFields.add(f);
    }
    
    public void applyFieldEffect(ArrayList a)    {
        Iterator i=generatedFields.iterator();
        while (i.hasNext())
          ((CentralForceField)i.next()).applyField(a);
    }

    
    public Color getColor() { return color; }
    public void setColor(Color c) { color = c; }
    
    
}
