package etomica.potential;

import etomica.api.IAtomList;
import etomica.api.IPotentialAtomic;
import etomica.api.IVector;
import etomica.atom.AtomLeafAgentManager;
import etomica.integrator.IntegratorBox;

/**
 * Sums the force on each iterated atom and adds it to the integrator agent
 * associated with the atom.
 */
public class PotentialCalculationForceSum implements PotentialCalculation {
        
    protected AtomLeafAgentManager<? extends IntegratorBox.Forcible> integratorAgentManager;
    protected AtomLeafAgentManager.AgentIterator<? extends IntegratorBox.Forcible> agentIterator;
    
    public void setAgentManager(AtomLeafAgentManager<? extends IntegratorBox.Forcible> agentManager) {
        integratorAgentManager = agentManager;
        agentIterator = integratorAgentManager.makeIterator();
    }

    /**
     * Re-zeros the force vectors.
     *
     */
    public void reset(){
        
        agentIterator.reset();
        while(agentIterator.hasNext()){
            Object agent = agentIterator.next();
            if (agent instanceof IntegratorBox.Forcible) {
                ((IntegratorBox.Forcible)agent).force().E(0);
            }
        }
    }

    /**
     * Adds forces due to given potential acting on the atoms produced by the iterator.
     * Implemented for only 1- and 2-body potentials.
     */
    public void doCalculation(IAtomList atoms, IPotentialAtomic potential) {
        PotentialSoft potentialSoft = (PotentialSoft)potential;
        int nBody = potential.nBody();
        IVector[] f = potentialSoft.gradient(atoms);
        switch(nBody) {
            case 1:
                integratorAgentManager.getAgent(atoms.getAtom(0)).force().ME(f[0]);
                break;
            case 2:
                integratorAgentManager.getAgent(atoms.getAtom(0)).force().ME(f[0]);
                integratorAgentManager.getAgent(atoms.getAtom(1)).force().ME(f[1]);
                break;
            default:
                //XXX atoms.count might not equal f.length.  The potential might size its 
                //array of vectors to be large enough for one IAtomSet and then not resize it
                //back down for another IAtomSet with fewer atoms.
                for (int i=0; i<atoms.getAtomCount(); i++) {
                    integratorAgentManager.getAgent(atoms.getAtom(i)).force().ME(f[i]);
                }
		}
	}
}

@@ -1589,24 +1589,315 @@
 ch(nBody) %7B%0A
+        %09case 0:%0A        %09%09IAtomList boxAtoms = integratorAgentManager.getBox().getLeafList();%0A        %09%09for (int i=0; i%3CboxAtoms.getAtomCount(); i++) %7B%0A        %09%09%09((IntegratorBox.Forcible)integratorAgentManager.getAgent(boxAtoms.getAtom(i))).force().ME(f%5Bi%5D);%0A        %09%09%7D%0A        %09%09break;%0A%0A
             

handle 0-body potential