package sudoku.parse;

import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Scanner;
import java.util.function.Supplier;
import java.io.File;
import java.io.FileNotFoundException;
import sudoku.Puzzle;

/**
 * <p>Parses the initial puzzle out of a Sadman Sudoku puzzle file. This format is defined at
 * http://www.sadmansoftware.com/sudoku/faq19.php (retrieved 25 May 2016).</p> <p>All elements of a
 * Sadman format file other than the initial state of the puzzle are ignored, including the number
 * of solutions.</p>
 * @author fiveham
 * @author fiveham
 *
 */
public class SadmanParser implements Parser{
	
    /**
     * <p>Content of the line prior to the statement of the initial state of the puzzle.</p>
     */
	public static final String INITIAL_PUZZLE_MARKER = "[Puzzle]";
	
    /**
     * <p>Indicates an empty cell in the initial puzzle state.</p>
     */
	public static final char EMPTY_CELL = '.';
	
	private final int mag;
	private final List<Integer> values;
	
    /**
     * <p>Constructs a Parser that interprets the contents of the file {@code f} as a Sadman-format
     * sudoku puzzle, using the specified {@code charset} to read the file.</p>
     * @param f the file to be interpreted
     * @param charset the name of the charset to be used in reading the file. If the
     * @throws FileNotFoundException
     */
	public SadmanParser(File f, String charset) throws FileNotFoundException{
		this(() -> {
			try{
				return new Scanner(f, charset);
			} catch(FileNotFoundException e){
				throw new IllegalArgumentException(e);
			}
		});
	}
	
	public SadmanParser(File f) throws FileNotFoundException{
		this(() -> {
			try{
				return new Scanner(f);
			} catch(FileNotFoundException e){
				throw new IllegalArgumentException(e);
			}
		});
	}
	
	private SadmanParser(Supplier<Scanner> supplier) throws FileNotFoundException{
		Scanner s = supplier.get();
		while(s.hasNext() && !INITIAL_PUZZLE_MARKER.equals(s.nextLine()));
		
		if(!s.hasNext()){
			s.close();
			s = supplier.get();
		}
		
		StringBuilder initCells;
		try{
			initCells = new StringBuilder(s.nextLine());
			this.mag = (int)Math.sqrt(initCells.length());
			for(int i=1; i<mag*mag; ++i){
				initCells.append(s.nextLine());
			}
		} catch(NoSuchElementException e){
			throw new IllegalArgumentException("Could not parse the file as Sadman format", e);
		} finally{
			s.close();
		}
		this.values = new ArrayList<>(initCells.length());
		for(int i=0; i<initCells.length(); ++i){
			char c = initCells.charAt(i);
			values.add(c == EMPTY_CELL 
					? Puzzle.BLANK_CELL 
					: Integer.parseInt(Character.toString(c), mag*mag+1));
		}
	}
	
	@Override
	public int mag() {
		return mag;
	}
	
	@Override
	public List<Integer> values() {
		return values;
	}
}

@@ -428,16 +428,19 @@
 16).%3C/p%3E
+%0A *
  %3Cp%3EAll 
@@ -452,19 +452,16 @@
 nts of a
-%0A *
  Sadman 
@@ -528,16 +528,20 @@
 gnored, 
+%0A * 
 includin
@@ -552,19 +552,16 @@
 e number
-%0A *
  of solu
@@ -594,30 +594,8 @@
 ham%0A
- * @author fiveham%0A *%0A
  */%0A
@@ -641,26 +641,22 @@
 rser%7B%0A%09%0A
-  
   /**%0A
-  
    * %3Cp%3E
@@ -733,34 +733,32 @@
  puzzle.%3C/p%3E%0A   
- 
- 
 */%0A%09public stati
@@ -806,34 +806,30 @@
 Puzzle%5D%22;%0A%09%0A
-  
   /**%0A
-  
    * %3Cp%3EIndi
@@ -880,26 +880,24 @@
 ate.%3C/p%3E%0A   
-  
 */%0A%09public s
@@ -996,18 +996,16 @@
 lues;%0A%09%0A
-  
   /**%0A  
@@ -1005,18 +1005,16 @@
  /**%0A   
- 
- 
 * %3Cp%3ECon
@@ -1103,18 +1103,16 @@
 rmat%0A   
-  
 * sudoku
@@ -1178,18 +1178,16 @@
 le.%3C/p%3E%0A
-  
    * @pa
@@ -1222,18 +1222,16 @@
 eted%0A   
-  
 * @param
@@ -1305,18 +1305,16 @@
  the%0A   
-  
 * @throw
@@ -1336,19 +1336,48 @@
 xception
-%0A  
+ if %7B@code f%7D could not be read%0A
    */%0A%09p
@@ -1604,16 +1604,244 @@
 );%0A%09%7D%0A%09%0A
+%09/**%0A%09 * %3Cp%3EConstructs a Parser that interprets the contents of the file %7B@code f%7D as a Sadman-format%0A   * sudoku puzzle.%3Cp%3E%0A%09 * @param f the file being read%0A%09 * @throws FileNotFoundException if %7B@code f%7D could not be read%0A%09 */%0A
 %09public 

update javadoc