package simulate;

public final class IntegratorVerlet extends IntegratorMD {

    AtomPair.Iterator.All pairIterator;
    Atom.Iterator atomIterator;
    AtomPair.Action forceSum;
    Atom.Action verletStep;
    Space.Vector work;
                
    public IntegratorVerlet() {
        super();
    }

    public void registerPhase(Phase p) {
        super.registerPhase(p);
        pairIterator = p.iteratorFactory().makeAtomPairIteratorAll();
        atomIterator = p.iteratorFactory().makeAtomIteratorUp();
//        spacePotential = (PotentialHard)p.space().makePotential(p);
    }
    
    public void setController(Controller c) {
        super.setController(c);
        work = Simulation.space().makeVector();
    //anonymous class; cannot do in construtor because need simulation()
        forceSum = new AtomPair.Action() {
            private Space.Vector f = Simulation.space.makeVector();
            public void action(AtomPair pair) {
                f.E(((PotentialSoft)Simulation.getPotential(pair)).force(pair));
                ((Agent)pair.atom1().ia).force.PE(f);
                ((Agent)pair.atom2().ia).force.ME(f);
            }
        };
    }
        
  private double t2;
  public final void setTimeStep(double t) {
    super.setTimeStep(t);
    t2 = timeStep*timeStep;
  }
          
//--------------------------------------------------------------
// steps all particles across time interval tStep

    public void doStep() {

        atomIterator.reset();
        while(atomIterator.hasNext()) {   //zero forces on all atoms
            ((Agent)atomIterator.next().ia).force.E(0.0);
        }
        pairIterator.allPairs(forceSum);

        atomIterator.reset();
        while(atomIterator.hasNext()) {
            Atom a = atomIterator.next();
            Agent agent = (Agent)a.ia;
            Space.Vector r = a.position();
            work.E(r);
            r.PE(agent.rMrLast);
            agent.force.TE(a.rm()*t2);
            r.PE(agent.force);
            agent.rMrLast.E(r);
            agent.rMrLast.ME(work);
        }
        return;
    }
    
//    private static class forceSum implements AtomPair.Action {
//        public void action(AtomPair pair) {
            
        
//--------------------------------------------------------------

    public void initialize() {
        deployAgents();
        atomIterator.reset();
        while(atomIterator.hasNext()) {
            Atom a = atomIterator.next();
            Agent agent = (Agent)a.ia;
            agent.rMrLast.Ea1Tv1(-timeStep*a.rm(),a.momentum());
        }
    }
              
//--------------------------------------------------------------

    public final Integrator.Agent makeAgent(Atom a) {
        return new Agent(a);
    }
            
    public final static class Agent implements Integrator.Agent {  //need public so to use with instanceof
        public Atom atom;
        public Space.Vector force;
        public Space.Vector rMrLast;  //r - rLast

        public Agent(Atom a) {
            atom = a;
            force = Simulation.space.makeVector();
            rMrLast = Simulation.space.makeVector();
        }
    }
}

