import java.util.*;
import java.io.*;

/**
 * MyStreamTokenizer
 * provides simplified access to java.io.StreamTokenizer.
 * 
 * This class was written by Prof. Alan Jepson.
 *
 * YOU WILL USE THIS CLASS.  
 * THERE IS NO NEED FOR YOU TO MODIFY THIS CLASS.
 */

public class MyStreamTokenizer {

    /** The name of the opened input file */
    public String fileName;
  
    // Constants used to control how the input lines are parsed.  
    public final static char BLANK = ' ';
    public final static char QUOTE = '\"';
    public final static char MINUS = '-';
 
    // Constants describing the current token.
    /** End of file (EOF) indicator constant. */
    public final static int EOF = StreamTokenizer.TT_EOF;
    /** End of line (EOL) indicator constant. */
    public final static int EOL = StreamTokenizer.TT_EOL;
    /** Word token indicator. */
    public final static int WORD = StreamTokenizer.TT_WORD;
    /** Number token indicator. */
    public final static int NUMBER = StreamTokenizer.TT_NUMBER;

    // State variables.  These describe the current token. They
    // are public to match the way java.io.StreamTokenizer uses
    // ttype, sval and nval.
 
    /** The type (EOF, EOL, WORD, NUMBER) of the current token.  
     *  This is only defined after one or more calls to nextToken(). 
     */
    public int type;

    /** The String value of the current token (if type == WORD), otherwise
        null */
    public String sval;

    /** The Double value of the current token (if type == NUMBER), otherwise
        null */
    public Double nval;

    private StreamTokenizer inFile;  // For the current file.
    private FileReader inFileReader; // Reader for the current file.

    /**
     * Open the file named in the argument, and initialize the tokenizer.
     * This does NOT read the first token, so the public variables type, 
     * sval and nval are not yet set.
     **/
    public MyStreamTokenizer(String inFileName) throws FileNotFoundException {
        inFileReader = new FileReader(inFileName);
        inFile = new StreamTokenizer(inFileReader);
        // Initialize the StreamTokenizer.  See the documentation
        // for java.io.StreamTokenizer.

        // reset all ASCII characters to be ordinary.
        inFile.resetSyntax(); 
 
        // Treat characters from 0 to (int)BLANK to be whitespace.
        inFile.whitespaceChars(0, BLANK); 

        // Treat all characters from BLANK+1 to 255 to be part of a word.
        inFile.wordChars(BLANK+1, 255);

        // Treat tokens beginning with - . 0 1...9 as numbers.
        inFile.parseNumbers();

        // Use the quote character QUOTE to start and end quoted strings. 
        // Use \" to insert a " in the token (assuming QUOTE is ").
        inFile.quoteChar(QUOTE);

        // Identify the end of line as a distinct token.  EOL will also
        // terminate quotes which are missing the second quote mark.
        inFile.eolIsSignificant(true);

        fileName = inFileName;
    }

    /** Close the input file. */
    public void close() throws IOException {
        inFileReader.close();
        fileName = null;
    }

    /** Return the line number of the current token. */
    public int lineno() {
        return inFile.lineno();
    }

    /** Return the type of the next token (one of EOF, EOL, WORD, NUMBER).
     *  If the type is WORD or NUMBER, then the value of the token is
     *  available from public instance variables sval and nval, respectively.
     *  The method throws an IOException is there is a serious problem getting
     *  the next token, but not on EOF.  */
    public int nextToken() throws IOException {
        sval = null;
        nval = null;
        // Use the StreamTokenizer to get the next token.
        // Catching any EOFException.
        try {
            inFile.nextToken();
        } catch (EOFException e) {
            type = EOF;
        }
 
        // Represent the token type.  
        // Quotes in java.io.StreamTokenizer are represented by inFile.sval,
        // but the  return type is NOT TT_WORD.  Rather the type is the
        // particular quote character used (i.e. QUOTE).  Here we
        // hide that distinction, and quoted tokens are just WORDs.
        switch (inFile.ttype) {
        case StreamTokenizer.TT_EOF:
            type = EOF;
            break;
        case StreamTokenizer.TT_EOL:
            type = EOL;
            break;
        case StreamTokenizer.TT_WORD:
        case (int) QUOTE:
            type = WORD;
            sval = inFile.sval;
            // System.out.println("Debug: Token: word: " + sval);
            break;
        case (int) MINUS: // Leading -'s are returned as separate words,
            type = WORD;    // unless the subsequent character is . or 0-9,
            sval = "-";     // in which case a NUMBER token will be returned.
            break;
        case StreamTokenizer.TT_NUMBER:
            type = NUMBER;
            nval = new Double(inFile.nval);
            // System.out.println("Debug: Token: number: " + nval);
            break;
        default:
            throw new IOException("Unknown token type: "+inFile.ttype
                                  +":"+inFile.sval+": "+inFile.nval);
        }
        return type;
    }

    /** Read and discard all tokens up to the next EOL (or to the EOF).
     *  Postcondition: the current token is either of type EOL or EOF,
     *  or a (non EOF) IOException is raised.
     */
    public void flushLine() throws IOException {
        while((type != EOF) && (type != EOL)) {
            this.nextToken();
        }
    }

}
