/*
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOUSE. See the GNU
 * General Public License for more details.
 *
 * You should have recieved a copy of the GNU General Public License
 * along with this program; if not write to the Free Software
 * Foundation, inc., 59 Temple Place, Suite 330, Boston MA 02111-1307
 * USA
 */

package run.readers;

import run.Constraint;
import run.Controlset;
import run.Element;
import run.Load;
import run.Material;
import run.ModifiedStreamTokenizer;
import run.Node;
import run.Reader;
import run.RplVector;
import run.Token;
import run.TrackWriter;
import run.Tracker;
import run.Writer;
import run.materials.*;
import uka.karmi.rmi.RemoteException;

import java.io.*;
import java.lang.reflect.Array;

import java.text.ParseException;

import java.util.*;

import jp.lang.RemoteObject;


/**
 * Insert the type's description here. Creation date: (2001-08-20 22:51:18)
 *
 * @author: Jonas Forssell
 */
public class GmshReader extends Reader {
    private java.io.BufferedReader br, br2;
    private java.lang.String filename;
    private java.lang.String[] keywords = {
        "$NOD", "$ENDNOD", "$ELM", "$ENDELM"
    };
    private boolean in_block = false;
    private boolean in_block2 = false;
    private java.io.StreamTokenizer str, str2;
    private Node temporary_node;
    private Constraint temporary_constraint;
    private Load temporary_load;
    private boolean element_in_block = false;
    private boolean tracker_in_block = false;
    private boolean material_in_block = false;
    private java.lang.String current_element_type;
    private java.lang.String current_tracker_type;
    private java.lang.String current_constraint_type;
    private Controlset temporary_controlset;
    private boolean control_in_block;
    private boolean constraint_in_block;
    private Token[] lastline;
    private int[] register;
    private int regpos;

    /**
     * This constructor immediately tries to open the file.
     */
    public GmshReader(String fn) {
        int i;

        // Remember this filename
        filename = new String(fn);
        
        // The Gmsh translator needs to rememeber temporary registrations.
        register = new int[99];
    }

    /**
     * Insert the method's description here. Creation date: (2001-08-20
     * 23:00:59)
     */
    public void close() {
        try {
            br.close();

			regpos = 0;
			Arrays.fill(register,0);

        } catch (IOException ioe) {
            System.out.println(
                "An IOException has occurred when closing the indata file"
            );

            return;
        }
    }

	/**
     * Insert the method's description here. Creation date: (2001-08-20
     * 23:00:59)
     */
    public void close2() {
        try {
            br2.close();
        } catch (IOException ioe) {
            System.out.println(
                "An IOException has occurred when closing the indata file"
            );

            return;
        }
    }

	/**
     * This method reads the next constraint, sets up all the paremeters and
     * returns a handle to the constraint. Creation date: (26/08/01 %T)
     *
     * @return krockpackage.Node
     *
     * @exception java.text.ParseException The exception description.
     */
    public void getControlSet(Controlset temporary_controlset)
        throws Error
    {
		Token[] t;

		try {

			// For now, this is hardcoded default controlset
			t = new Token[5];
		
			t[0] = new Token("RUN");
			t[1] = new Token("FROM");
			t[2] = new Token("0");
			t[3] = new Token("TO");
			t[4] = new Token("1");

	        temporary_controlset.parse_Fembic(t , str.lineno() );

			t = new Token[4];

			t[0] = new Token("PRINT");
			t[1] = new Token("EVERY");
			t[2] = new Token("0.1");
			t[3] = new Token("STEP");

	        temporary_controlset.parse_Fembic(t , str.lineno() );

            // Check all required data has been filled in
            temporary_controlset.checkIndata();

            // OK, everything read now. Lets end. The data has already been filled into the controlset given as an argument
            // so there is nothing to return.
        } catch (Error e) {
            throw e;
        } catch (ParseException e) {
            throw new Error(
                e.getMessage() + " in line: " + (e.getErrorOffset() - 1)
            );
        } catch (IllegalArgumentException e) {
            throw new Error(e.getMessage());
        }
    }


	/**
     * This method reads the next material, sets up all the paremeters and
     * returns a handle to the material. Creation date: (26/08/01 %T)
     *
     * @return krockpackage.Node
     *
     * @exception java.text.ParseException The exception description.
     */
    public Element getNextElement(RplVector materiallist, RplVector nodelist,
    		RplVector loadlist)
        throws java.text.ParseException, Error
    {
        int index, val;
        Element temporary_element;
        Token[] t;
 
        try {
 
            // Start examining the file.
            // We can assume that we have a unique material or no material ahead.

			do {

				t = this.tokenize(str);
				
				if (t.length > 6) index = (int)t[1].getn();
					else index = 100;
					
				} while (index >= 15);

			// Extract the element subtype
			val = (int)(t[2].getn()/1E9);
			val %= 10;
				
           	// Parse the element number and put into the object
           	temporary_element = Element.getElementOfType_Gmsh(index,val);

   	        // Continue and parse the constraint parameters.
            temporary_element.parse_Gmsh(
                t, str.lineno(), nodelist, materiallist, loadlist
			);

            // Check all required data has been filled in
            temporary_element.checkIndata();

			// Return the element
			return (Element) temporary_element;

        } catch (java.io.IOException e) {
            throw new Error(e.getMessage());
        } catch (Error e) {
            throw e;
        } catch (ParseException e) {
            throw new Error(
                e.getMessage() + " in line: " + (e.getErrorOffset() - 1)
            );
        } catch (IllegalArgumentException e) {
            throw new Error(e.getMessage());
        }
    }










    /**
     * This method reads the next constraint, sets up all the paremeters and
     * returns a handle to the constraint. Creation date: (26/08/01 %T)
     *
     * @return krockpackage.Node
     *
     * @exception java.text.ParseException The exception description.
     */
    public Tracker getNextTracker(RplVector nodelist, RplVector elementlist)
        throws java.text.ParseException, Error
    {
        int index, val, tpos;
        Tracker temporary_tracker;
        Token[] t,t2;
        Vector tmp;
        Node temp_node;
 
        try {
 
            // Start examining the file.

            val = 0;

			do {

				t = this.tokenize(str);
				
				if (t.length >= 6) 
					{
						val = (int)(t[2].getn()/1E8);
						val %= 10;
					}
					
				} while (val == 0 || this.compare(register,val) != -1);
				
			// We have found a point constraint. Now extract the tracker number.
			val = (int)(t[2].getn()/1E8);
			val %= 10;

           	// Parse the tracker number and put into the tracker object
           	temporary_tracker = Tracker.getTrackerOfType_Gmsh(val);

			tpos = 6;

			//Now, search through the file again and see if this tracker is
			//assigned to some other node as well.
			this.open2();

			tmp = new Vector();
			for (index=0; index < t.length; index++) tmp.add(t[index]);

			while (str2.nextToken() != java.io.StreamTokenizer.TT_EOF) {

				str2.pushBack();
				
				t2 = this.tokenize(str2);

				if (t2.length >= 6) {				

					// We have found a point constraint. Now extract the constraint number.
					index = (int)(t2[2].getn()/1E8);
					index %= 10;
			
					if (val == index) {
							// Add this node to the tracker indata
							tmp.add(t2[5]);
					}
	            }
			}
			this.close2();				

			t = new Token[tmp.size()];
			
			for (index = 0; index < tmp.size(); index++)
				t[index] = (Token)tmp.elementAt(index);

   	        // Continue and parse the constraint parameters.
            temporary_tracker.parse_Gmsh(
                t, val, nodelist, elementlist
			);

            // Check all required data has been filled in
            temporary_tracker.checkIndata();

			// Register the constraint
			register[regpos++] = val;

		
			return (Tracker) temporary_tracker;

        } catch (java.io.IOException e) {
            throw new Error(e.getMessage());
        } catch (Error e) {
            throw e;
        } catch (ParseException e) {
            throw new Error(
                e.getMessage() + " in line: " + (e.getErrorOffset() - 1)
            );
        } catch (IllegalArgumentException e) {
            throw new Error(e.getMessage());
        }
    }

	/**
     * This method reads the next constraint, sets up all the paremeters and
     * returns a handle to the constraint. Creation date: (26/08/01 %T)
     *
     * @return krockpackage.Node
     *
     * @exception java.text.ParseException The exception description.
     */
    public Constraint getNextConstraint(RplVector nodelist)
        throws java.text.ParseException, Error
    {
        int index, val,i;
        Constraint temporary_constraint;
        Token[] t;
        Node temp_node;
 
        try {
 
            // Start examining the file.
            // We can assume that we have a unique constraint or no constraint ahead.

            val = 0;

			do {

				t = this.tokenize(str);
				
				if (t.length >= 6) 
					{
						val = (int)(t[2].getn()/1E5);
						val %= 100;
					}
					
				} while (val == 0 || this.compare(register,val) != -1);
				

           	// Parse the constraint number and put into the tracker object
           	temporary_constraint = Constraint.getConstraintOfType_Gmsh(val);

   	        // Continue and parse the constraint parameters.
            temporary_constraint.parse_Gmsh(
                t, val, nodelist
			);

            // Check all required data has been filled in
            temporary_constraint.checkIndata();

			//Now, search through the file again and see if this constraint is
			//assigned to some other node as well.
			this.open2();

			while (str2.nextToken() != java.io.StreamTokenizer.TT_EOF) {

				str2.pushBack();
				
				t = this.tokenize(str2);

				if (t.length >= 6) {				
					// We have found a point constraint. Now extract the constraint number.
					index = (int)(t[2].getn()/1E5);
					index %= 100;
			
					if (val == index) {
							// Assign this constraint to the corresponding nodes
							
						for(i=5; i<5+(int)t[4].getn(); i++)
							for (index = 0; index < nodelist.size(); index++) {
				        		temp_node = (Node) nodelist.elementAt(index);
	
					            if (temp_node.getNumber() == t[i].getn()) 
                    		    	temp_node.setConstraint(temporary_constraint);
							}
					}
	            }
			}
			this.close2();				

			// Register the constraint
			register[regpos++] = val;

		
			return (Constraint) temporary_constraint;

        } catch (java.io.IOException e) {
            throw new Error(e.getMessage());
        } catch (Error e) {
            throw e;
        } catch (ParseException e) {
            throw new Error(
                e.getMessage() + " in line: " + (e.getErrorOffset() - 1)
            );
        } catch (IllegalArgumentException e) {
            throw new Error(e.getMessage());
        }
    }

	/**
     * This method reads the next material, sets up all the paremeters and
     * returns a handle to the material. Creation date: (26/08/01 %T)
     *
     * @return krockpackage.Node
     *
     * @exception java.text.ParseException The exception description.
     */
    public Material getNextMaterial()
        throws java.text.ParseException, Error
    {
        int val;
        Material temporary_material;
        Token[] t;
 
        try {
 
            // Start examining the file.
            // Repeat until a unique material is found
            // Remember that regpos is reset every time that a file is closed.

            val = 0;

			do {

				t = this.tokenize(str);
				
				if (t.length >= 6) 
					{
						val = (int)(t[2].getn()/1E3);
						val %= 100;
					}
					
				} while (val == 0 || this.compare(register,val) != -1);
				

           	// Unique material is found. Create a new object
           	temporary_material = Material.getMaterialOfType_Gmsh(0);

   	        // Continue and parse the constraint parameters.
            temporary_material.parse_Gmsh(
                t, str.lineno()
			);

            // Check all required data has been filled in
            temporary_material.checkIndata();

			// Register the material so we don't create duplicates
			register[regpos++] = val;

			// Return the material		
			return (Material) temporary_material;

        } catch (java.io.IOException e) {
            throw new Error(e.getMessage());
        } catch (Error e) {
            throw e;
        } catch (ParseException e) {
            throw new Error(
                e.getMessage() + " in line: " + (e.getErrorOffset() - 1)
            );
        } catch (IllegalArgumentException e) {
            throw new Error(e.getMessage());
        }
    }







    /**
     * This method reads the next load, sets up all the paremeters and returns
     * a handle to the load. Creation date: (26/08/01 %T)
     *
     * @return krockpackage.Node
     *
     * @exception java.text.ParseException The exception description.
     */
    public Load getNextLoad(RplVector nodelist)
        throws java.text.ParseException, Error
    {
        int index, val;
        Load temporary_load;
        Token[] t;
        Node temp_node;
 
        try {
 
            // Start examining the file.
            // We can assume that we have a unique constraint or no constraint ahead.

			if (lastline == null)
				do {

				t = this.tokenize(str);
				
				if (t.length == 6) index = (int)t[1].getn();
					else index = 0;
					
				regpos = 0;

				} while (index != 15);
			else
				t = lastline;
				
			// We have found a point constraint. Now extract the constraint number.
			val = (int)(t[2].getn()/1E7);
			val %= 10;

           	// Parse the tracker number and put into the tracker object
           	temporary_load = new Load();

   	        // Continue and parse the constraint parameters.
            temporary_load.parse_Gmsh(
                t, val, nodelist
			);

            // Check all required data has been filled in
            temporary_constraint.checkIndata();

			//Now, search through the file again and see if this constraint is
			//assigned to some other node as well.
			this.open2();

			while (str2.nextToken() != java.io.StreamTokenizer.TT_EOF) {

				str2.pushBack();
				
				t = this.tokenize(str2);

				if (t.length >= 6) {				
					// We have found a point constraint. Now extract the constraint number.
					index = (int)(t[2].getn()/1E7);
					index %= 10;
			
					if (val == index) {
							// Assign this constraint to the corresponding nodes
							for (index = 0; index < nodelist.size(); index++) {
				        		temp_node = (Node) nodelist.elementAt(index);
	
					            if (temp_node.getNumber() == t[5].getn()) 
                    		    	temp_node.setLoad(temporary_load);
							}
					}
	            }
			}
			this.close2();				

			// Register the constraint
			register[regpos++] = val;

			//Finally, read new lines until another constraint is encountered or EOF.

			while (str.nextToken() != java.io.StreamTokenizer.TT_EOF) {

				str.pushBack();
				
				t = this.tokenize(str);

				if (t.length > 2) {

				index = (int)(t[2].getn()/1E7);
				index %= 10;

				if (this.compare(register,index) < 0) {
	
					lastline = t;

					break;
				}
			}
			}
					
		return temporary_load;

        } catch (java.io.IOException e) {
            throw new Error(e.getMessage());
        } catch (Error e) {
            throw e;
        } catch (ParseException e) {
            throw new Error(
                e.getMessage() + " in line: " + (e.getErrorOffset() - 1)
            );
        } catch (IllegalArgumentException e) {
            throw new Error(e.getMessage());
        }
    }

    /**
     * This method reads the next node, sets up all the paremeters and returns
     * a handle to the node. Creation date: (26/08/01 %T)
     *
     * @return krockpackage.Node
     *
     * @exception java.text.ParseException The exception description.
     */
    public Node getNextNode(
    		RplVector constraintlist, RplVector loadlist
    )
        throws java.text.ParseException, Error
    {
        int index;
        Constraint temp_constraint;
        Load temp_load;

        // Assume the file has been opened
        // If we are not in a node block, search until we find one.
        try {
            // Start with "cleaning" out extra lines etc.
            while (str.nextToken() == java.io.StreamTokenizer.TT_EOL) {
                ;
            }

            str.pushBack();

            // Now, check that we are reading the node number
            while (
                (str.nextToken() != java.io.StreamTokenizer.TT_NUMBER) &&
                (str.ttype != java.io.StreamTokenizer.TT_EOF)
            ) {
                // This is not the case. Now search until next block of nodes is found and try again.
                in_block = false;
                str.pushBack();

                while (str.nextToken() != java.io.StreamTokenizer.TT_EOF) {
                    if (str.ttype == java.io.StreamTokenizer.TT_WORD) {
                        if (
                            str.sval.toUpperCase().equals("$NOD") &&
                            (str.nextToken() == str.TT_EOL)
                        ) {
                            in_block = true;

							// Skip next line also because this is not a node
	                        while (str.nextToken() != str.TT_EOL) {
    	                        ;
        	                }
	                        
                            break;
                        }
                    }
                }
            }

            // We should now be in a block. If not, throw an error
            if (! in_block) {
                throw new java.text.ParseException(
                    "No nodes block found or missing nodes", str.lineno()
                );
            }

            // Time to read the next node element
            // Parse and put into the node object
            
            temporary_node = new Node();
            temporary_node.setNumber((int) str.nval);

            // Continue and read the X coordinates for the node
            temporary_node.parse_Gmsh(
                tokenize(str), str.lineno(), constraintlist, loadlist
            );

            // Check all required data has been filled in
            temporary_node.checkIndata();

            return temporary_node;
        } catch (java.io.IOException e) {
            throw new Error(e.getMessage());
        } catch (Error e) {
            throw e;
        } catch (ParseException e) {
            throw new Error(
                e.getMessage() + " in line: " + (e.getErrorOffset() - 1)
            );
        } catch (IllegalArgumentException e) {
            throw new Error(e.getMessage());
        }
    }

    /**
     * Insert the method's description here. Creation date: (26/08/01 %T)
     *
     * @param param java.lang.String
     *
     * @return boolean
     */
    private boolean isAKeyword(String param) {
        int i;

        for (i = 0; i < keywords.length; i++) {
            if (keywords[i].equals(param.toUpperCase())) {
                return true;
            }
        }

        return false;
    }

    /**
     * Insert the method's description here. Creation date: (28/08/01 %T)
     *
     * @return int
     *
     * @exception java.text.ParseException The exception description.
     */
    public int numberOfConstraints()
        throws java.text.ParseException
    {
        int noc = 0, i = 0, val = 0;
        Token[] temp;
        int[] constraints = new int[99];
        boolean found;

        // Open file and start reading from beginning
        this.open();


        try {
            // Start examining the file and continue until end of file is reached
            while (str.nextToken() != str.TT_EOF) {
                // check token for the key word "constraints"
                if (str.ttype == str.TT_WORD) {
                    if (str.sval.toUpperCase().equals("$ELM")) {
                        while (str.nextToken() != str.TT_EOL) {
                            ;
                        }

                        str.pushBack();

                        while (str.nextToken() != str.TT_EOF) {
                            // Repeat this until a keyword is found. That means block is finished. 
                            if (str.ttype == str.TT_WORD) {
                                if (this.isAKeyword(str.sval)) {
                                    str.pushBack();

                                    break;
                                }
                            }

							// Getting this far means we now can assume we are inside the element block

							temp = this.tokenize(str);
							found = false;
		
							if (temp.length > 1) {
							// Single out the constraint digits
							val = (int)(temp[1].getn()/1E5);
							val %= 100;
							for (i=0; i<99; i++) if (constraints[i] == val) found = true;
							}
							
							// Check now if this constraint has been seen before
                            if ( found == false && val != 0) {
                                constraints[noc] = val;
                                noc++;
                            }
                        }
                    }
                }
            }

            System.out.println("Found" + noc + "constraints");
        } catch (IOException ioe) {
            System.out.println(
                "IOException when reading a constraintline from indata file"
            );
            this.close();

            return -1;
        }

        this.close();

        return noc;
    }

    /**
     * Insert the method's description here. Creation date: (28/08/01 %T)
     *
     * @return int
     *
     * @exception java.text.ParseException The exception description.
     */
    public int numberOfControls()
        throws java.text.ParseException
    {
        int noc;

		// hard coded dummy
		noc = 1;

        System.out.println("Found" + noc + "controls");

        return noc;
    }

    /**
     * This method examines the indata file to determine the number of elements
     * supplied there. Note that there may be several different types of
     * elements, each under a new headline. Example: elements of type beam 1
     * nodes=[1,2] A=5.0 ..... elements of type rod 1 nodes=[2,3] A=3.2 .....
     * Creation date: (21/08/01 %T)
     *
     * @return int
     */
    public int numberOfElements()
        throws java.text.ParseException
    {
        int noe = 0;

        // Open file and start reading from beginning
        this.open();

        try {
            // Start examining the file and continue until end of file is reached
            while (str.nextToken() != str.TT_EOF) {
                // check token for the key word "elements"
                if (str.ttype == str.TT_WORD) {
                    if (str.sval.toUpperCase().equals("$ELM")) {
                        while (str.nextToken() != str.TT_EOL) {
                            ;
                        }

                        str.pushBack();

						// Skip next line. It only states number of elements
                        while (
                                    (str.nextToken() != str.TT_EOL) &&
                                    (str.ttype != str.TT_EOF)
                        );
						
                        str.pushBack();

                        while (str.nextToken() != str.TT_EOF) {
                            // Repeat this until a keyword is found. That means block is finished. 
                            if (str.ttype == str.TT_WORD) {
                                if (this.isAKeyword(str.sval)) {
                                    str.pushBack();

                                    break;
                                }
                            }

                            /* getting this far means we are now about to read elements
                               The first token should be a line number if an element is defined */
                            if (str.ttype == str.TT_NUMBER) {
                            	str.nextToken();
								// Do not count the point elements as elements.
                            	if (str.nval != 15 && str.ttype == str.TT_NUMBER)                      	
                                	noe++;

                                // Move to end of line
                                while (
                                    (str.nextToken() != str.TT_EOL) &&
                                    (str.ttype != str.TT_EOF)
                                ) {
                                    ;
                                }
                            }
                        }
                    }
                }
            }

            System.out.println("Found" + noe + "elements");
        } catch (IOException ioe) {
            System.out.println(
                "IOException when reading a line from indata file"
            );
            this.close();

            return -1;
        }

        if (noe == 0) {
            this.close();
            throw new java.text.ParseException("No elements found", 0);
        }

        this.close();

        return noe;
    }

    /**
     * This method examines the indata file to determine the number of trackers
     * supplied there. Note that there may be several different types of
     * trackers, each under a new headline. Example: trackers of type
     * sectionforce 1 nodes = [1,2,3]  filename = ..... trackers of type
     * sectionmoment 1 nodes = [2,3] filename = .....         Creation date:
     * (21/08/01 %T)
     *
     * @return int
     */
    public int numberOfTrackers()
        throws java.text.ParseException
    {
        int not = 0, i = 0, val = 0;
        int[] trackers = new int[9];
        Token[] temp;
		boolean found;

        // Open file and start reading from beginning
        this.open();

        try {
            // Start examining the file and continue until end of file is reached
            while (str.nextToken() != str.TT_EOF) {
                // check token for the key word "trackers"
                if (str.ttype == str.TT_WORD) {
                    if (str.sval.toUpperCase().equals("$ELM")) {
                        while (str.nextToken() != str.TT_EOL) {
                            ;
                        }

                        str.pushBack();

                        while (str.nextToken() != str.TT_EOF) {
                            // Repeat this until a keyword is found. That means block is finished. 
                            if (str.ttype == str.TT_WORD) {
                                if (this.isAKeyword(str.sval)) {
                                    str.pushBack();

                                    break;
                                }
                            }

							// Getting this far means we now can assume we are inside the element block

							temp = this.tokenize(str);
							found = false;
		
							if (temp.length > 1) {
							// Single out the tracker digits
							val = (int)(temp[1].getn()/1E8);
							val %= 10;
							for (i=0; i<9; i++) if (trackers[i] == val) found = true;
							}
							
							// Check now if this constraint has been seen before
                            if ( found == false && val != 0) {
                                trackers[not] = val;
                                not++;
                            }
                        }
                    }
                }
            }

            System.out.println("Found" + not + "trackers");
        } catch (IOException ioe) {
            System.out.println(
                "IOException when reading a trackerline from indata file"
            );
            this.close();

            return -1;
        }

        this.close();

        return not;
    }

    /**
     * Insert the method's description here. Creation date: (28/08/01 %T)
     *
     * @return int
     *
     * @exception java.text.ParseException The exception description.
     */
    public int numberOfLoads()
        throws java.text.ParseException
    {
        int nol = 0, i = 0, val = 0;
        Token[] temp;
        int[] constraints = new int[9];
        boolean found;

        // Open file and start reading from beginning
        this.open();

        try {
            // Start examining the file and continue until end of file is reached
            while (str.nextToken() != str.TT_EOF) {
                // check token for the key word "materials"
                if (str.ttype == str.TT_WORD) {
                    if (str.sval.toUpperCase().equals("$ELM")) {
                        // Clean out line
                        while (str.nextToken() != str.TT_EOL) {
                            ;
                        }

                         str.pushBack();

                        while (str.nextToken() != str.TT_EOF) {
                            // Repeat this until a keyword is found. That means block is finished. 
                            if (str.ttype == str.TT_WORD) {
                                if (this.isAKeyword(str.sval)) {
                                    str.pushBack();

                                    break;
                                }
                            }

							// Getting this far means we now can assume we are inside the element block

							temp = this.tokenize(str);
							found = false;
		
							if (temp.length > 1) {
							// Single out the constraint digits
							val = (int)(temp[1].getn()/1E7);
							val %= 10;
							for (i=0; i<9; i++) if (constraints[i] == val) found = true;
							}
							
							// Check now if this constraint has been seen before
                            if ( found == false && val != 0) {
                                constraints[nol] = val;
                                nol++;
                            }
                        }                       
                    }
                }
            }

            System.out.println("Found" + nol + "loads");
        } catch (IOException ioe) {
            System.out.println(
                "IOException when reading a line from indata file"
            );
            this.close();

            return -1;
        }

        this.close();

        return nol;
    }

    /**
     * Insert the method's description here. Creation date: (21/08/01 %T)
     *
     * @return int
     */
    public int numberOfMaterials()
        throws java.text.ParseException
    {
        int nom = 0, val = 0, i;
        boolean found;
        Token[] temp;
        int[] constraints = new int[99];

        // Open file and start reading from beginning
        this.open();

        try {
            // Start examining the file and continue until end of file is reached
            while (str.nextToken() != str.TT_EOF) {
                // check token for the key word "materials"
                if (str.ttype == str.TT_WORD) {
                    if (str.sval.toUpperCase().equals("$ELM")) {
                        // Clean out line
                        while (str.nextToken() != str.TT_EOL) {
                            ;
                        }

                         str.pushBack();

                        while (str.nextToken() != str.TT_EOF) {
                            // Repeat this until a keyword is found. That means block is finished. 
                            if (str.ttype == str.TT_WORD) {
                                if (this.isAKeyword(str.sval)) {
                                    str.pushBack();

                                    break;
                                }
                            }

							// Getting this far means we now can assume we are inside the element block

							temp = this.tokenize(str);
							found = false;

							if (temp.length > 1) {
							// Single out the constraint digits
							val = (int)(temp[1].getn()/1E3);
							val %= 100;

							for (i=0; i<99; i++) if (constraints[i] == val) found = true;
							}
							// Check now if this constraint has been seen before
                            if ( found == false && val != 0) {
                                constraints[nom] = val;
                                nom++;
                            }
                        }                       
                    }
                }
            }

            System.out.println("Found" + nom + "materials");
        } catch (IOException ioe) {
            System.out.println(
                "IOException when reading a line from indata file"
            );
            this.close();

            return -1;
        }

        if (nom == 0) {
            this.close();
            throw new java.text.ParseException("No materials found", 0);
        }

        this.close();

        return nom;
    }

    /**
     * Insert the method's description here. Creation date: (21/08/01 %T)
     *
     * @return int
     */
    public int numberOfNodes()
        throws java.text.ParseException
    {
        int non = 0;

        // Open file and start reading from beginning
        this.open();

        try {
            // Start examining the file and continue until end of file is reached
            while (str.nextToken() != str.TT_EOF) {
                // check token for the key word "nodes"
                if (str.ttype == str.TT_WORD) {
                    if (
                        str.sval.toUpperCase().equals("$NOD") &&
                        (str.nextToken() == str.TT_EOL)
                    ) {
                        while (str.nextToken() != str.TT_EOF) {
                            // Repeat this until a keyword is found. That means block is finished. 
                            if (str.ttype == str.TT_WORD) {
                                if (this.isAKeyword(str.sval)) {
                                    break;
                                }
                            }

                            // getting this far means we are now about to read nodes
                            // The first token should be a line number if an element is defined
                            if (str.ttype == str.TT_NUMBER) {
                                non++;

                                // Move to end of line
                                while (
                                    (str.nextToken() != str.TT_EOL) &&
                                    (str.ttype != str.TT_EOF)
                                ) {
                                    ;
                                }
                            }
                        }
                    }
                }
            }

			// The first node number is actually number of nodes. This
			// should not be counted
			
			if (non > 0) non--;

            System.out.println("Found" + non + "nodes");
        } catch (IOException ioe) {
            System.out.println(
                "IOException when reading a line from indata file"
            );
            this.close();

            return -1;
        }

        if (non == 0) {
            this.close();
            throw new java.text.ParseException("No nodes found", 0);
        }

        this.close();

        return non;
    }

    /**
     * This constructor immediately tries to open the file.
     */
    public void open() {
        FileReader fr;

        // Opening the file means that parameters should be set to zero
        in_block = false;
        control_in_block = false;
        constraint_in_block = false;
        element_in_block = false;

        // Try to open the indata file
        try {
            fr = new FileReader(filename);
        } catch (FileNotFoundException fnfe) {
            System.out.println("Fembic file does not exist");

            return;
        }

        try {
            br = new BufferedReader(fr);
        } catch (IllegalArgumentException ioe) {
            System.out.println(
                "An IllegalArgumentException has occurred when opening the indata file"
            );

            return;
        }

        str = new ModifiedStreamTokenizer(br);
    }

	/**
     * This constructor immediately tries to open the file.
     */
    public void open2() {
        FileReader fr;

        // Opening the file means that parameters should be set to zero
        in_block2 = false;

        // Try to open the indata file
        try {
            fr = new FileReader(filename);
        } catch (FileNotFoundException fnfe) {
            System.out.println("Fembic file does not exist");

            return;
        }

        try {
            br2 = new BufferedReader(fr);
        } catch (IllegalArgumentException ioe) {
            System.out.println(
                "An IllegalArgumentException has occurred when opening the indata file"
            );

            return;
        }

        str2 = new ModifiedStreamTokenizer(br2);
    }






    /**
     * This method returns the writer to be used for the results
     */
    public Writer getWriter(
        RplVector nodelist, RplVector elementlist, Controlset control, RemoteObject[] cluster_nodes
    )
        throws Error, RemoteException
    {
        Writer a;
        a = Writer.getWriterOfType_Fembic(
                control.getWriter(), nodelist, elementlist, cluster_nodes
            );

        try {
            a.checkIndata();
        } catch (Error e) {
            throw e;
        }

        return a;
    }

    /**
     * This method returns the Trackwriter to be used for the trackers
     */
    public TrackWriter getTrackWriter(RplVector trackerlist, Controlset control, RemoteObject[] cluster_nodes)
        throws Error, RemoteException
    {
        TrackWriter a;
        a = TrackWriter.getTrackWriterOfType_Fembic(
                control.getTrackWriter(), trackerlist
            );

        try {
            a.checkIndata();
        } catch (Error e) {
            throw e;
        }

        return a;
    }

    /**
     * Overriding this routine to add some more features related to Fembic.
     */
    public Token[] tokenize(java.io.StreamTokenizer str)
        throws IOException
    {
        int i;
        double num;
        String temp;
        String temp1;
        String temp2;
        Vector v = new Vector();
        Token t;
        Token[] arr;

        // Start by reading all the words and numbers on the line into the p vector.
        while (
            (str.nextToken() != java.io.StreamTokenizer.TT_EOL) &&
            (str.ttype != java.io.StreamTokenizer.TT_EOF)
        ) {
            if (str.ttype == java.io.StreamTokenizer.TT_WORD) {
                v.add(new Token(str.sval.trim()));
            } else {
                v.add(new Token(str.nval));
            }
        }

        // Now, begin examining the vector for correct parsing.
        for (i = 0; i < v.size(); i++) {
            // Check if this token is a word.
            t = (Token) v.elementAt(i);

            if (t.is_a_word()) {
                temp = new String(t.getw());

                // This may be a beginning of a [ set. If so, search until next set if found.
                if (temp.startsWith("[") && ! temp.endsWith("]")) {
                    v.remove(i);

                    while (! temp.endsWith("]")) {
                        if (i >= v.size()) {
                            throw new IOException(
                                "IO Exception trying to find end ] of a parameter set in string\n"
                            );
                        }

                        t = (Token) v.elementAt(i);
                        v.remove(i);

                        if (t.is_a_number()) {
                            temp += new Double(t.getn()).toString();
                        } else {
                            temp += t.getw().trim();
                        }
                    }

                    v.insertElementAt(new Token(temp), i);
                } else
                // Check to see if there is an = sign in there (i.e. no spaces around the =)
                // If so, split up into three tokens and make the parser read them again.
                if ((temp.indexOf("=") != -1) && (temp.length() > 1)) {
                    v.remove(i);

                    if (temp.indexOf("=") != 0) {
                        v.insertElementAt(
                            new Token(temp.substring(0, temp.indexOf("="))), i
                        );
                    } else {
                        i--;
                    }

                    v.insertElementAt(new Token(new String("=")), i + 1);

                    if (temp.indexOf("=") != (temp.length() - 1)) {
                        v.insertElementAt(
                            new Token(
                                temp.substring(
                                    temp.indexOf("=") + 1, temp.length()
                                )
                            ), i + 2
                        );
                    }

                    i--;
                }
            } else
            // t is a number, leave it alone	
             {
            }
        }

        arr = new Token[v.size()];

        for (i = 0; i < v.size(); i++) {
            arr[i] = (Token) v.elementAt(i);
        }

        return arr;
    }
    
    /**
     * Insert the method's description here. Creation date: (2001-10-31
     * 00.46.27)
     *
     * @return int
     *
     * @exception java.text.ParseException The exception description.
     */
    public void preProcess() throws java.text.ParseException
 	{ 
    }
    
    
    private int compare(int[] a, int b) {
    	int i, res;
    
    	res = -1;
    		    	
    	for (i=0; i<a.length; i++)
    		if (a[i] == b) {
    			res = i;
    			break;
    		}
    
    	return res;
    }   	
    
}

