import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.NoSuchElementException;
import javax.swing.JFileChooser;

public class ByteScanner {
    // Displays a dialog box for selecting a file, returning a ByteScanner
    // corresponding to the selected file. Canceling the dialog terminates
    // the program.
    public static ByteScanner promptUser() {
        JFileChooser chooser = new JFileChooser();
        chooser.setDialogTitle("Select Source File");
        int result = chooser.showDialog(null, "Select");
        if(result != JFileChooser.APPROVE_OPTION) { // dialog canceled
            System.err.println("File selection canceled; program complete");
            System.exit(0);
            return null; // should never happen
        }
        return new ByteScanner(chooser.getSelectedFile());
    }

    private FileInputStream in;
    private int next;
    private boolean hasNext;
    private boolean atEof;

    // Constructs an ByteScanner object for the given filename.
    // If the file doesn't exist, then the file will come up as
    // empty.
    private ByteScanner(File file) {
        atEof = false;
        hasNext = false;
        try {
            in = new FileInputStream(file);
        } catch(IOException e) {
            in = null;
            atEof = true;
        }
    }

    // Returns true if this file has any more characters left in it
    // (or if errors prevent it from reading any more characters).
    public boolean hasNext() {
        ensureNext();
        return !atEof;
    }

    // Returns the current byte in the file, and advances to the
    // next byte after it. Two successive calls to nextByte
    // return two successive bytes in the file.
    public int nextByte() {
        ensureNext();
        if(atEof) {
            throw new NoSuchElementException("at end of file");
        }
        hasNext = false;
        return next;
    }

    private void ensureNext() {
        if(!hasNext) {
            if(!atEof) {
                try {
                    int b = in.read();
                    if(b < 0) reachedEof();
                    next = b & 0xFF;
                } catch(IOException e) {
                    reachedEof();
                }
            }
            hasNext = true;
        }
    }

    private void reachedEof() {
        try {
            if(in != null) in.close();
        } catch(IOException e) { }
        in = null;
        atEof = true;
    }
}
