content: /*
   * Copyright (C) 2014 - Martin Berger
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
  */
  package edu.stanford.rsl.conrad.data.generic.iterators;
  
  import edu.stanford.rsl.conrad.data.PointwiseIterator;
  import edu.stanford.rsl.conrad.data.generic.GenericGrid;
  import edu.stanford.rsl.conrad.data.generic.complex.ComplexGrid3D;
  import edu.stanford.rsl.conrad.data.generic.datatypes.Complex;
  import edu.stanford.rsl.conrad.data.generic.datatypes.Gridable;
  
  public class GenericFloatIterator<T extends Gridable<T>> extends PointwiseIterator{
  
  	protected GenericGrid<T> m_grid;
  
  	/**
  	 * The condition for out of bound values
  	 * 0 = clamp to zero
  	 * 1 = clamp to constant
  	 * 2 = clamp to edge value
  	 * 3 = symmetrically extend value
  	 * 4 = extend periodically
  	 */
  	protected int boundaryCondition;
  
  	/**
  	 * The boundary size for each dimension. 
  	 * Half of the boundary size is extended in each direction. 
  	 * If N is the given size and N is odd, the boundary on the right side is extended by N/2 + 1, 
  	 * whereas the boundary on the left side is extended by N/2.  
  	 */
  	protected int[] boundarySize;
  
  	/**
  	 * The value to set the boundary if using a clamp to constant boundary condition
  	 */
  	protected T clampValue;
  
  	/**
  	 * The iterators direction
  	 */
  	protected int[] direction;
  
  	/**
  	 * The current iterator position
  	 */
  	protected int[] position;
  
  	protected int dim;
  
  
  	public GenericFloatIterator(GenericGrid<T> g, T clampValue){
  		this(g, 0, new int[g.getSize().length], clampValue, new int[g.getSize().length]);
  	}
  
  	public GenericFloatIterator(GenericGrid<T> g, int boundCond, int[] boundSize, T clampValue, int[] pos, int []dir) {
  		// set the grid
  		this.m_grid = g;
  		// initialize the boundaries
  		boundaryCondition = boundCond;
  		boundarySize = boundSize;
  		this.clampValue = clampValue;
  		// set initial direction
  		direction = dir;
  		// set initial position
  		position = pos;
  		// the dimension
  		dim = g.getSize().length;
  	}
  
  	public GenericFloatIterator(GenericGrid<T> g, int boundCond, int[] boundSize, T clampValue, int[] pos) {
  		// set the grid
  		this.m_grid = g;
  		// initialize the boundaries
  		boundaryCondition = boundCond;
  		boundarySize = boundSize;
  		this.clampValue = clampValue;
  		// set initial direction
  		direction = new int[g.getSpacing().length];
  		direction[0]=1;
  		// set initial position
  		position = pos;
  		// the dimension
  		dim = g.getSize().length;
  	}
  
  
  	public boolean hasNext(){
  		boolean val = true;
  		for (int i=0; i < dim; ++i){
  			int tmp = position[i];
  			if (tmp < 0 - boundarySize[i]/2 || tmp >= m_grid.getSize()[i] + boundarySize[i]/2 + boundarySize[i]%2)
  				val = false;
  		}
  		return val;
  
  	}
  
  	private void move(){
  		for (int i=0; i < dim; ++i)
  			position[i]+=direction[i];
  	}
  
  	public T getNext(){
  		int[] currentPosition = null;
  		T val = null;
  		for (int i=0; i < dim; ++i){
  			boolean bleft=position[i] < 0;
  			boolean bright=position[i] >= m_grid.getSize()[i];
  			// check if we have a boundary case
  			if (bleft || bright) {
  				switch (boundaryCondition) {
  				case 0: 
  					val = clampValue.getNewInstance();
  					break;
  				case 1: 
  					val = clampValue;
  					break;
  				case 2:
  					currentPosition = (currentPosition==null) ? position.clone() : currentPosition;
  					currentPosition[i] = (bleft) ? 0 : m_grid.getSize()[i]-1;
  					break;
  				case 3:
  					currentPosition = (currentPosition==null) ? position.clone() : currentPosition;
  					// TODO not save if grid dimension is smaller than the boundary
  					currentPosition[i] = (bleft) ? Math.abs(position[i]) -1  : m_grid.getSize()[i] - (position[i] % m_grid.getSize()[i]) -1;
  					break;
  				case 4:
  					currentPosition = (currentPosition==null) ? position.clone() : currentPosition;
  					currentPosition[i] = (bleft) ? m_grid.getSize()[i] + ((position[i]+1) % m_grid.getSize()[i]) -1 : (position[i] % m_grid.getSize()[i]);
  					break;
  				default:
  					break;
  				}
  			}
  		}
  		T out = (val != null) ? val : ((currentPosition!=null) ? m_grid.getValue(currentPosition) : m_grid.getValue(position));
  		this.move();
  		return out;
  	}
  	
  	public int[] getPosition(){
  		return position;
  	}
  	
  	public void setPosition(int... pos){
  		position = pos;
  	}
  	
  	public void setDirection(int... dir){
  		direction = dir;
  	}
  	
  	public int[] getDirection(){
  		return direction.clone();
  	}
   
  	
  	public static void main(String[] args) {
  		GenericGrid<Complex> g = new ComplexGrid3D(8,8,12);
  		for (int i=0; i < 8; i++){
  			for (int j=0; j<8; j++)
  				for (int k=0; k<12; k++)
  			((ComplexGrid3D)g).setAtIndex(i, j, k, i, j*k);
  		}
  			
  		GenericFloatIterator<?> it = new GenericFloatIterator<Complex>(g,4,new int[]{0,0,0},new Complex(),new int[]{0,7,0},new int[]{0,0,1});
  		while (it.hasNext())
  		{
  			System.out.print(it.getPosition()[0]+ "/" + it.getPosition()[1] + ": " + it.getNext() + "\n");
  			
  		}
  	}
  
  }
  
  
  