package sudoku;

import common.NCuboid;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import sudoku.Puzzle.IndexValue;
import sudoku.Puzzle.IndexInstance;

/**
 * <p>Wraps a three-dimensional array of Claims in order to expedite access to them based on their
 * spatial coordinates or geometric constraints.</p> <p>Using only
 * {@link Puzzle#claimStream() claimStream()} to find the one Claim with specific coordinates is a
 * O(n^6) technique, where n is the magnitude of the target. Accessing the desired Claim directly
 * via its spatial coordinates can be achieved in O(1) time when storing them in an array or
 * ordering them in the Puzzle's underlying Graph's underlying list of vertices. Providing a
 * secondary means to access Claims in a spatial manner is preferable to adding extra constraints
 * onto the backing collection of vertices for the puzzle's Graph.</p>
 * @author fiveham
 * @author fiveham
 *
 */
class SpaceMap implements Iterable<Claim>{
	
	private Claim[][][] stuff;
	private Puzzle puzzle;
	
    /**
     * <p>Constructs a SpaceMap pertaining to the specified Puzzle and creates the Claims for that
     * Puzzle.</p>
     * @param target the Puzzle whose Claims are created and managed
     */
	public SpaceMap(Puzzle puzzle) {
		this.puzzle = puzzle;
		stuff = new Claim[puzzle.sideLength()][puzzle.sideLength()][puzzle.sideLength()];
		for(IndexValue x : puzzle.indexValues()){
			for(IndexValue y : puzzle.indexValues()){
				for(IndexValue symbol : puzzle.indexValues()){
					stuff[x.intValue()][y.intValue()][symbol.intValue()] = new Claim(puzzle, x,y,symbol);
				}
			}
		}
	}
	
  /**
   * <p>Returns the Claim in this SpaceMap's puzzle having the specified spatial coordinates.</p>
   * @param x the x-coordinate of the Claim returned
   * @param y the y-coordinate of the Claim returned
   * @param z the z-coordinate (symbol - 1) of the Claim returned
   * @return the Claim in this Puzzle having the specified spatial coordinates
   * @throws ArrayIndexOutOfBoundsException if {@code x}, {@code y}, or {@code z} is less than 0 or 
   * greater than or equal to this SpaceMap's puzzle's {@link Puzzle#sideLength() side-length}
   */
	public Claim get(int x, int y, int z){
		return stuff[x][y][z];
	}
	
    /**
     * <p>Returns the Claim in this SpaceMap's target having the specified spatial coordinates.</p>
     * @param x the x-coordinate of the Claim returned
     * @param y the y-coordinate of the Claim returned
     * @param s the z-coordinate (symbol) of the Claim returned
     * @return the Claim in this SpaceMap's target having the specified spatial coordinates
     */
	public Claim get(IndexValue x, IndexValue y, IndexValue s){
		return stuff[x.intValue()][y.intValue()][s.intValue()];
	}
	
  /**
   * <p>Returns the Claim in this SpaceMap's target having the specified spatial coordinates.</p>
   * @param dimA a spatial coordinate that specifies its own {@link Puzzle.DimensionType dimension}
   * @param dimB a spatial coordinate that specifies its own {@link Puzzle.DimensionType dimension}
   * @param dimC a spatial coordinate that specifies its own {@link Puzzle.DimensionType dimension}
   * @return the Claim in this SpaceMap's target having the specified spatial coordinates
   */
	public Claim get(IndexInstance dimA, IndexInstance dimB, IndexInstance dimC){
		IndexValue x = puzzle.decodeX(dimA, dimB, dimC);
		IndexValue y = puzzle.decodeY(dimA, dimB, dimC);
		IndexValue z = puzzle.decodeSymbol(dimA, dimB, dimC);
		return get(x, y, z);
	}
	
	@Override
	public Iterator<Claim> iterator(){
		return new ClaimIterator();
	}
	
	private List<Integer> ints = null;
	
	/**
	 * <p>Returns a list of the legal dimensional indices for this SpaceMap's puzzle.</p>
	 * @return a list of the legal dimensional indices for this SpaceMap's puzzle
	 */
	private List<Integer> ints(){
		if(ints == null){
			ints = puzzle.getIndices().stream()
					.map(IndexValue::intValue)
					.collect(Collectors.toList());
		}
		return ints;
	}
	
  /**
   * <p>An {@literal Iterator<Claim>} that traverses claim-space starting from 0,0,0, ending at the 
   * opposite vertex, and passing through all the Claim coordinates.</p>
   * @author fiveham
	 */
	private class ClaimIterator implements Iterator<Claim>{
	  
		private final Iterator<List<Integer>> cubeIterator;
		
		private ClaimIterator(){
			this.cubeIterator =  new NCuboid<Integer>(ints(), ints(), ints()).iterator();
		}
		
		@Override
		public boolean hasNext(){
			return cubeIterator.hasNext();
		}
		
		@Override
		public Claim next(){
			List<Integer> coords = cubeIterator.next();
			int x = coords.get(Puzzle.X_DIM);
			int y = coords.get(Puzzle.Y_DIM);
			int z = coords.get(Puzzle.Z_DIM);
			return get(x,y,z);
		}
	}
}

@@ -234,23 +234,49 @@
 rray of 
+the 
 Claims 
+belonging to a Puzzle 
 in order
@@ -288,16 +288,20 @@
 xpedite 
+%0A * 
 access t
@@ -308,28 +308,24 @@
 o th
-em based on their%0A *
+ose Claims using
  spa
@@ -374,13 +374,29 @@
 %3C/p%3E
+%0A *
  %3Cp%3E
-U
+By contrast, u
 sing
@@ -400,19 +400,16 @@
 ing only
-%0A *
  %7B@link 
@@ -471,16 +471,20 @@
 im with 
+%0A * 
 specific
@@ -500,15 +500,13 @@
 tes 
-is a%0A *
+takes
  O(n
@@ -514,15 +514,10 @@
 6) t
-echniqu
+im
 e, w
@@ -547,22 +547,22 @@
  of the 
-target
+puzzle
 . Access
@@ -569,16 +569,20 @@
 ing the 
+%0A * 
 desired 
@@ -590,20 +590,8 @@
 laim
- directly%0A *
  via
@@ -619,329 +619,41 @@
 tes 
-can be achieved in O(1) time when storing them in an array or%0A * ordering them in the Puzzle's underlying Graph's underlying list of vertices. Providing a%0A * secondary means to access Claims in a spatial manner is preferable to adding extra constraints%0A * onto the backing collection of vertices for the puzzle's Graph
+with a SpaceMap takes O(1) time
 .%3C
-/
 p%3E%0A 
@@ -674,30 +674,8 @@
 ham%0A
- * @author fiveham%0A *%0A
  */%0A

document SpaceMap class header