/* ---------------------------------------------------------------
 File:                           MyFileReader.java
 Package:                        FLAP
 Author:                         Dr. Ratnesh Kumar and Greg Stamp
 V2.0 10/28/2006
 Initial Developers: Yana Ong, Bharath Oruganti and Magda & Octavian Procopiuc
 ---------------------------------------------------------------*/
 
/*
 * Dr. Ratnesh Kumar, Greg Stamp.
 * Department of Electrical and Computer Engineering
 * Iowa State University
 * October, 2006.
 *
 * Copyright (c) 2006
 * All rights reserved.
 */

package flap;


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


/**
 * This class is used to read and parse the data from a given
 * file, and to construct a machine using this data.
 */

/* We're only reading file for Machine.FSA - Yana */

public class MyFileReader {

    public Machine	a = null;
    protected Desktop d = null;
    protected BufferedReader dis = null;

    /**
     * Tries to read a machine from the given file.
     */
    public void read(String fileName) throws Exception {
        FileInputStream in = null;

        in = new FileInputStream(fileName);

        setStream(in);
        parseStream();

        if (in != null) {
            in.close();
        }
        if (dis != null) {
            dis.close();
        } 

    }
  
    public void setStream(InputStream is) {
        dis = new BufferedReader(new InputStreamReader(is));
    }
  
    /**
     * Reads data from the current input stream
     * and parses it, building a new machine.
     */
    public void parseStream() throws Exception {
        String	line;
        Vector transitionLines = new Vector(4, 1);

        /* We're only reading from FSA machine */
        line = readNextLine(); // # of states.
        if (line == null) {
            throw (new EOFException("Wrong File Format"));
        }

        int stateCount = Integer.parseInt(line);

        d = new Desktop();

        if (stateCount == 0) {
            throw (new Exception("No Initial State"));
        }

        for (int i = 0; i < stateCount; i++) {
            State s = new State();

            s.id = i;

            line = readNextLine();	

            if (line == null) {
                throw (new EOFException("Wrong File Format"));
            }
            String token;
            StringTokenizer st = new StringTokenizer(line);

            if (st.countTokens() != 3) {
                throw (new EOFException("Wrong File Format"));
            }

            // State's information
            token = st.nextToken(); // State name
            s.SetStateLabel(token);
            token = st.nextToken();	
            if (Integer.parseInt(token) == 1) { // Unmarked or marked state
                s.isFinal = true;
            } else {
                s.isFinal = false;
            }
            token = st.nextToken();
            s.transitionCount = Integer.parseInt(token); // # of outgoing transitions

            d.theStates.addElement(s);
            if (i == 0) {
                d.initialState = s;
            } // Initial state

            for (int j = 0; j < s.transitionCount; j++) { // skip transition inputs and place into transitionLines vector
                line = readNextLine();	

                if (line == null) {
                    throw (new EOFException("Wrong File Format"));
                }
                transitionLines.addElement(line);
            }
        }// finished adding states
   
        // adding transitions
        int id = 0;

        for (int i = 0; i < stateCount; i++) {
            State fromState = (State) d.theStates.elementAt(i);

            for (int j = 0; j < fromState.transitionCount; j++) {
                line = (String) transitionLines.remove(0);
                if (line == null) {
                    throw (new Exception(
                            "Error in traversing the file and vectors"));
                }

                String token;
                StringTokenizer st = new StringTokenizer(line);

                if (st.countTokens() != 2) {
                    throw (new EOFException("Wrong File Format"));
                }

                Transition t = new Transition(++id, fromState, null, null); // start transition id from 1

                // transition's information
                token = st.nextToken(); // reading transition label
                t.label = null;
                t.label = token;

                token = st.nextToken();
                if ((t.to = getStateWithLabel(token)) == null) {
                    throw(new EOFException("Wrong File Format"));
                }
                t.distance = (t.to != t.from)
                        ? Params._t_distance
                        : Params._t_ltheight;

                d.theTransitions.addElement(t);
            }
        }// finished adding transitions
   
        d.currentId = d.theStates.size() + 1;
        d.currenttrId = d.theTransitions.size() + 1;

        dis.close();
        a = new FSA(d);

        setStatePosition();
    }	// end of method read.

    /* helper function that finds and returns the next non-null line - Yana */
    protected String readNextLine() { 
        try {
            String tryLine = dis.readLine();

            while (dis.ready() && (tryLine.trim().equals(""))) {
                tryLine = dis.readLine();
            } // find the next non-space line to be returned
            return tryLine;
        } catch (Exception e) {
            System.err.println(
                    "Exception " + e.toString() + " caught in readNextLine.");
        }
        return null;
    }

    /**
     * Arrange position for newly created states - Yana
     */
    protected void setStatePosition() { 
        int statesPerLine = (int) Math.sqrt((double) d.theStates.size());
        int width = (Params._s_radius * statesPerLine)
                + (Params._t_distance * (statesPerLine - 1));
        int height = (Params._s_radius * statesPerLine)
                + (Params._t_ltheight * (statesPerLine - 1));
        int currX = 0, currY = 0, startX = 30, startY = 55; // added start position to move initial state from border
        int startingPoint = Params._s_radius;

        d.setSize(width, height);
        for (int i = 0; i < d.theStates.size(); i++) {
            currX = startX + startingPoint
                    + (i % statesPerLine)
                    * (2 * Params._s_radius + Params._t_distance); // next state coordinate is as far as one state diameter
            currY = startY + startingPoint
                    + (i / statesPerLine)
                    * (2 * Params._s_radius + Params._t_ltheight);

            State s = (State) d.theStates.elementAt(i);

            s.p.x = currX;
            s.p.y = currY;

        }
    }

    /**
     * Return the State with the same label as lbl
     * @param lbl    the state label to be compared/found
     */
    protected State getStateWithLabel(String lbl) {
        for (int i = 0; i < d.theStates.size(); i++) {
            State s = (State) d.theStates.elementAt(i);

            if (s.label.equals(lbl)) {
                return s;
            }
        }
        return null;
    }
 
}	// end of class FileReader.
