package etomica.nbr.cell;

import etomica.action.AtomsetAction;
import etomica.action.AtomsetCount;
import etomica.atom.AtomArrayList;
import etomica.atom.AtomSet;
import etomica.atom.iterator.ApiInterArrayList;
import etomica.atom.iterator.ApiIntraArrayList;
import etomica.atom.iterator.AtomsetIterator;
import etomica.atom.iterator.IteratorDirective;
import etomica.lattice.CellLattice;
import etomica.lattice.RectangularLattice;
import etomica.box.Box;
import etomica.space.BoundaryPeriodic;

/**
 * Returns iterates formed from all cell-based neighbor pairs.
 */
public class ApiAACell implements AtomsetIteratorCellular, java.io.Serializable {

    /**
     * Constructor makes iterator that must have box specified and then be
     * reset() before iteration.
     * 
     * @param D
     *            the dimension of the space of the simulation (used to
     *            construct cell iterators)
     * @param range
     *            the distance within which pairs of atoms are considered
     *            neighbors. Used to define neighbor cells; some iterates may
     *            exceed this separation
     */
	public ApiAACell(int D, double range, Box box) {
        cellIterator = new RectangularLattice.Iterator(D);
        neighborIterator = new CellLattice.NeighborIterator(D, range);
        neighborIterator.setDirection(IteratorDirective.Direction.UP);
        interListIterator = new ApiInterArrayList();
        intraListIterator = new ApiIntraArrayList();
        listIterator = intraListIterator;
        this.box = box;
	}

	public void setLattice(CellLattice lattice) {
        cellIterator.setLattice(lattice);
		neighborIterator.setLattice(lattice);
        unset();
	}
    
    /**
     * Performs action on all iterates.
     */
    public void allAtoms(AtomsetAction action) {
        cellIterator.reset();
        neighborIterator.checkDimensions();
        while(cellIterator.hasNext()) {//outer loop over all cells
            //get cell without advancing -- advance is done via nextIndex,
            // below
            Cell cell = (Cell)cellIterator.peek();
            AtomArrayList list = cell.occupants();
            
            //no molecules of species in cell
            if(list.isEmpty()) {
                cellIterator.nextIndex();
                continue;
            }
            
            //consider pairs formed from molecules in cell
            intraListIterator.setList(list);
            intraListIterator.allAtoms(action);

            //loop over neighbor cells
            interListIterator.setOuterList(list);
            neighborIterator.setSite(cellIterator.nextIndex());
            neighborIterator.reset();
            while(neighborIterator.hasNext()) {
                Cell neighborCell = (Cell)neighborIterator.next(); 
                interListIterator.setInnerList(neighborCell.occupants());
                if(neighborCell.occupants().getAtomCount() > 0) interListIterator.allAtoms(action);
            }
        }//end of outer loop over cells
    }//end of allAtoms
    
	/**
     * Returns the number of atom pairs the iterator will return if reset and
     * iterated in its present state.
     */
	public int size() {
        AtomsetCount counter = new AtomsetCount();
        allAtoms(counter);
        return counter.callCount();
	}
	
    public boolean hasNext() {
        throw new RuntimeException("oops");
    }
    
    public AtomSet nextPair() {
        AtomSet nextPair = listIterator.next();
        if (nextPair == null) {
            return advanceLists();
        }
        return nextPair;
    }
    
    public void unset() {
        listIterator.unset();
    }

    /**
     * Returns 2, indicating that this is a pair iterator.
     */
    public int nBody() {
        return 2;
    }
    
    public void reset() {
        neighborIterator.setPeriod(box.getBoundary().getDimensions());
        neighborIterator.setPeriodicity(((BoundaryPeriodic)box.getBoundary()).getPeriodicity());
        cellIterator.reset();
        neighborIterator.checkDimensions();
        neighborIterator.unset();
        listIterator.unset();
        //System.out.println("reset in ApiAACell");
    }//end of reset
    
    // Moves to next pair of lists that can provide an iterate
    // This should be invoked only if listIterator.hasNext is false
    private AtomSet advanceLists() {
        do {
              //advance neighbor cell
            if(neighborIterator.hasNext()) {
                interListIterator.setInnerList(((Cell)neighborIterator.next()).occupants());
                listIterator = interListIterator;
                interListIterator.reset();
                AtomSet pair = listIterator.next();
                if (pair != null) {
                    return pair;
                }

                //advance central cell and set up neighbor cell iterator if
                // central cell has some molecules
            } else if(cellIterator.hasNext()) {
                AtomArrayList list = ((Cell)cellIterator.peek()).occupants();
                neighborIterator.setSite(cellIterator.nextIndex());

                if(!list.isEmpty()) {//central cell has molecules
                    interListIterator.setOuterList(list); //for neighbor-cell looping
                    intraListIterator.setList(list);//for intra-cell looping
                    neighborIterator.reset();

                    listIterator = intraListIterator;
                    intraListIterator.reset();
                        
                    AtomSet pair = listIterator.next();
                    if (pair != null) {
                        return pair;
                    }
                } else {//no molecules in central cell
                    neighborIterator.unset();
                    listIterator.unset();
                }
            } else {//no more cells at all
                return null;
            }
        } while(true);
    }//end of advanceCell
    
    /**
     * @return Returns the cellIterator.
     */
    public CellLattice.NeighborIterator getNbrCellIterator() {
        return neighborIterator;
    }
   
    private static final long serialVersionUID = 1L;
    private AtomsetIterator listIterator;
    private final Box box;
    private final ApiIntraArrayList intraListIterator;
    private final ApiInterArrayList interListIterator;
    private final CellLattice.NeighborIterator neighborIterator;
    private final RectangularLattice.Iterator cellIterator;
}

@@ -347,16 +347,40 @@
 ective;%0A
+import etomica.box.Box;%0A
 import e
@@ -454,32 +454,8 @@
 ce;%0A
-import etomica.box.Box;%0A
 impo
@@ -3322,94 +3322,8 @@
 %7D%0A%09%0A
-    public boolean hasNext() %7B%0A        throw new RuntimeException(%22oops%22);%0A    %7D%0A    %0A
     

hasNext is dead