//file: parser.java
//

// import java libraries
//
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import java.util.*;
import java.io.*;
import java.lang.*;

/**
 * class that handles parsing of tokens
 */
public class Parser implements Constants {

    // create FileInputStream and BufferedReader so file input can be done
    //
    FileInputStream in_stream = null;
    BufferedReader input = null;
    Data data = null;
    String line = null;
    int line_index = 0;

    // create a variable holding the path of the front end gui
    //
    
    // ---------------------------------------------------
    //
    // declare class constructors
    //
    // ---------------------------------------------------

    /**
     * default class constructor
     *
     * @param d  data object to put all parsed data into
     *
     * @throws FileNotFoundException if resource file could not be initialized
     * @throws SecurityException if permissions were not allowed
     * @throws IllegalArgumentException if resource file was not proper
     */
    public Parser(Data d){
	
	// create the data class to hold all of the parsed data
	//
	data = d;
	
	// open input stream to file 'resources.txt'
	//
	try {
	    in_stream = new FileInputStream(RESOURCES_FILE);
	}
	catch (FileNotFoundException e) { 
	    System.err.println();
	    System.err.println("---------------------------------------");
	    System.err.println("Caught FileNotFoundException: " + e.getMessage());
	    System.err.println("---------------------------------------");
	    return; 
	}
	catch (SecurityException e) { return; }
	
	// open buffered reader with input coming from in_stream
	//
	try {
	    input = new BufferedReader(new InputStreamReader(in_stream));
	}
	catch (IllegalArgumentException e){
	    System.err.println();
	    System.err.println("---------------------------------------");
	    System.err.println("Caught IllegalArgumentException: " + e.getMessage());
	    System.err.println("---------------------------------------");
	    return;
	}
	
	// run parse function until stream is no longer ready
	//
	line_index = 0;
	while(parse());
    }

    /**
     * parses the text file 
     *
     * @throws IOException if input stream throws an exception
     * @throws ArrayIndexOutOfBoundsException if file indexes something out of
     *  range of container
     * @throws NullPointerException if a null pointer is accessed
     * @throws Exception if a exception of another type occurs
     *
     * @return true if properly parsed
     */    
    public boolean parse() {
		
	try {

	    // read in a line of text and parse	
	    //	    
	    line =input.readLine();
	    line_index++;

	    // if the line is null then skip it
	    //
	    if (line == null) {
		return false;
	    }

	    // trim whitespace from this string 
	    //
	    line = line.trim();
	    
	    // if there is a blank line skip it
	    //
	    if(line.equals("")){
		return true;
	    }
	    	    
	    // tokenize the string for working with
	    // eg: association.name type value1 value2 ... valueN
	    //
	    StringTokenizer tokens = new StringTokenizer(line);
	    
	    // step through each token and deal with it as appropriate
	    // 
	    for(int i=0; i <  3; i++){		
		
		// take a token and trim off all white space if there are any
		//
		String single_token = null;

		if(tokens.hasMoreTokens()){
		    single_token = new String(tokens.nextToken());
		    single_token.trim();
		
		    // if the line is commented, skip the rest of that line
		    // return is true as we want to continue reading beyond
		    // this particular line
		    //
		    if (single_token.equals("#")){
			return true;
		    }
		}
		
		// split the first token into two separate parts
		// eg: association.name
		//     
		if (i == 0) {
		    String delim = ".";
		    StringTokenizer mini_token = 
			new StringTokenizer(single_token, delim);
		
		    // write to cooresponding vectors in data object
		    //
		    data.association.add(mini_token.nextElement());
		    data.name.add(mini_token.nextElement());
		}
		
		// writes the type of parameter to the data.type
		// eg: association.name type
		//
		if (i == 1) {
		    data.type.add(single_token);
		}
		
		// write either the default or all possible values to 
		// data.values
		// eg: association.name type value1 value2 ... valueN
		//
		if (i == 2) {

		    // if the possible values are enumerated, add them properly
		    //
		    if (((String)data.type.lastElement()).equals("enum")){
			add_enums(tokens, single_token);

			//	System.out.println(tokens);
			//	System.out.println(single_token);
		    }

		    // if the variable is a path to an icon, set type to image
		    // and add path as the value
		    // eg: association.iconBig  images/small/foo_00.gif
		    //
		    else if (((String)data.name.lastElement()).
			     equals("iconBig")){
			data.values.add(DEFAULT_PATH+data.type.lastElement());
			data.type.setElementAt("image",
					       (data.type.size()-1));
		    }

		    // eg: association.iconSmall  images/small/foo_00.gif
		    //
		    else if (((String)data.name.lastElement()).
			     equals("iconSmall")){
			data.values.add(DEFAULT_PATH+data.type.lastElement());
			data.type.setElementAt("image",
					       (data.type.size()-1));
		    }
		    
		    // eg: association.iconName  
		    //
		    else if (((String)data.name.lastElement()).
			     equals("iconName")){
			data.values.add(data.type.lastElement());
			data.type.setElementAt("image",
					       (data.type.size()-1));
		    }

		    // if the line is telling me the names of all the 
		    // transformations, make it an enum
		    // eg: _transform.classes Arithmetic AutoCorrelation ...
		    //
		    else if (((String)data.association.
			       lastElement()).equals(TRANSFORM_TAG)){
			Vector<Object> enum_var = new Vector<Object>(10,10);
			enum_var.add(data.type.lastElement());
			enum_var.add(single_token);
			data.type.setElementAt("enum",
					       (data.type.size()-1));
			
			// reads through the rest of the tokens 
			// and adds them to a vector
		       	//
			while(tokens.hasMoreTokens()){
			
			    // take a token and trim off all 
			    // white space
			    String other_token = 
				new String(tokens.nextToken());
			    other_token.trim();
			    enum_var.add(other_token);
			}	
			
			// the vector of enumerated values 
			// is added to the values vector
			//
			data.values.add(enum_var);
		    }
		    
		    // if the line is of type text
		    // eg: Filter.ar_coeff     text      "1.0"
		    //
		    else if(((String)data.type.lastElement()).equals("text")){
			String text_string = new String("" + single_token);
			while(tokens.hasMoreTokens()) {
			    text_string = new String(text_string + " " + 
						     tokens.nextToken());
			}

			// delete the quotation marks
			//
			text_string = text_string.replace('\"',' ' );
			text_string = text_string.trim();
			data.values.add(text_string);
		    }

		    // if the line is of type vector
		    // eg: Filter.ma_coeff     vector      1.0, -3.0, 4.6
		    //
		    else if(((String)data.type.lastElement()).equals("vector")){
			String text_string = new String("" + single_token);
			while(tokens.hasMoreTokens()) {
			    text_string = new String(text_string + " " + 
						     tokens.nextToken());
			}

			// delete the quotation marks
			//
			text_string = text_string.replace('\"',' ' );
			text_string = text_string.trim();
			data.values.add(text_string);
		    }
		    
		    // if not enumerated or an image, then the value is a 
		    // default and can simply be added here
		    // eg: Filter.buffer_mode    boolean   false
		    //
		    else {
			data.values.add(single_token);
		    }
		}   
	    }
	}
	catch(IOException e) {
	    System.err.println();
	    System.err.println("---------------------------------------");
	    System.err.println("Caught IOException: " + e.getMessage());
	    System.err.println("Line Number: " + line_index);
	    System.err.println("File Line: " + line);
	    System.err.println("---------------------------------------");
	    System.exit(0);
	}
	catch(ArrayIndexOutOfBoundsException e) {
	    System.err.println();
	    System.err.println("---------------------------------------");
	    System.err.println("Caught ArrayIndexOutOfBoundsException: " + e.getMessage());
	    System.err.println("Line Number: " + line_index);
	    System.err.println("File Line: " + line);
	    System.err.println("---------------------------------------");
	    System.exit(0);
	}
	catch(NullPointerException e) {
	    System.err.println();
	    System.err.println("---------------------------------------");
	    System.err.println("Caught NullPointerException: " + e.getMessage());
	    System.err.println("Line Number: " + line_index);
	    System.err.println("File Line: " + line);
	    System.err.println("---------------------------------------");
	    System.exit(0);
	}	
	catch(Exception e) {
	    System.err.println();
	    System.err.println("---------------------------------------");
	    System.err.println("Caught Exception: " + e.getMessage());
	    System.err.println("Line Number: " + line_index);
	    System.err.println("File Line: " + line);
	    System.err.println("---------------------------------------");
	    System.exit(0);
	}	
	return true;	
    }

    /**
     * adds all the possible values for an enumerated type
     *
     * @param tokens   string tokenizer object
     * @param single   single token
     * @param enum_var   vector to hold the set of enum values
     */    
    private void add_enums(StringTokenizer tokens, String single) {

	// declare local variables
	//
	Vector<Object> enum_var = new Vector<Object>(5,5);
	
	// add the token that has already been taken
	//
	enum_var.add(single);

	// reads through the rest of the tokens and adds them to a vector
	//
	while(tokens.hasMoreTokens()){
	
	    // take a token and trim off all white space
	    //
	    String single_token = new String(tokens.nextToken());
	    single_token.trim();
	    enum_var.add(single_token);
	}		
	
	// vector of enumerated values is added to the values vector
	//
	data.values.add(enum_var);
    }
}

//
// end of file






