import java.util.Scanner;
import java.io.File;
import java.util.List;
import java.util.ArrayList;

/**
 * Class for reading, storing, and accessing valid codes.
 *   @author Dave Reed
 *   @version 9/19/16
 */
public class ValidCodesB3 {
    private KeypadB3 pad;
    private List<String> codes;
    
    /**
     * Constructs a list of valid codes, read in from a file
     *   @param filename the file containing the valid codes, one per line
     */
    public ValidCodesB3(String filename) {
        this.pad = new KeypadB3();
        
        this.codes = new ArrayList<String>();
        try {
            Scanner infile = new Scanner(new File(filename));
            
            while (infile.hasNext()) {
                String code = infile.next();
                this.codes.add(code.trim());
            }
            infile.close();
        }
        catch (java.io.FileNotFoundException e) {
            System.out.println("File not found.");
        }        
    }
    
    /**
     * Determines whether the specified code is contained in the valid list.
     *   @param code the code to be searched for
     *   @return true if code is contained in the list of valid codes
     */
    public boolean isValid(String code) {
        return this.codes.contains(code);
    }
    
    /**
     * Finds all valid codes that differ by one adjacent key only.
     *   @param code the code to be searched for
     *   @return a list of all valid codes that differ from code by one adjacent key.
     */
    public List<String> getPossibles(String code) {
        ArrayList<String> poss = new ArrayList<String>();
        for (String str : this.codes) {
            if (this.offByOne(str, code)) {
                poss.add(str);
            }
        }
        return poss;
    }
    
    /************************************************************************/
    
    /**
     * Helper method that determines if two codes differ by one adjacent key.
     *   @param code1 the first code
     *   @param code2 the second code
     *   @return true if code1 and code2 differ by exactly one adjacent key
     */
    private boolean offByOne(String code1, String code2) {
        if (code1.length() != code2.length()) {
            return false;
        }
        int diff = 0;
        for (int i = 0; i < code1.length(); i++) {
            char ch1 = code1.charAt(i);
            char ch2 = code2.charAt(i);
            if (ch1 != ch2) {
                if (diff == 0 && this.pad.areAdjacent(ch1, ch2)) {
                    diff++;
                }
                else {
                    return false;
                }
            }
        }
        return (diff == 1);
    }
}
 