/*---------------------------------------------------------------------------
File:         			FileWrite.java
Package:                        JFLAP Version 3.0
Author:				Magda & Octavian Procopiuc V1.0 07/15/96
                                Eric Gramond V3.0 08/14/98
                                
Description of Contents:	Contains class FileWrite.
				
--------------------------------------------------------------------------*/

/* 
 * Susan H. Rodger, Magda Procopiuc, Octavian Procopiuc, Eric Gramond
 * Computer Science Department
 * Duke University
 * June 198
 * Supported by National Science Foundation DUE-9596002 and DUE-9555084.
 *
 * Copyright (c) 1998
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by the author.  The name of the author may not be used to
 * endorse or promote products derived from this software without
 * specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

package flap;

import java.util.*;
import java.io.*;
import java.awt.Point;

/**
 * This class is used to write a given machine in a given
 * file.
 *
 * @author	Octavian & Magda Procopiuc
 * @version	1.0 15 July 1996
 */
public class FileWrite {

  public Machine	a;
  private int		type;

  final static int INPUT = 0;
  final static int STACK = 1;

  public FileWrite(Machine a) {
    this.a = a;
    type = a.type;
  }

  /**
   * Tries to write the machine in the specified file.
   * @exception IOException if the file canot be written
   */
  public void write(String fileName) throws IOException{
    
    PrintWriter ps = new PrintWriter((new FileWriter(fileName)), true);

    ps.println(typeString());
    if (type == Machine.TM1 || type == Machine.TM2) {
      ps.println("TAPE");
      if (type == Machine.TM1)
        ps.println("1");
      else
        ps.println("2");
    }   
    if(type == Machine.PDA ) {
	if(((PDA) a).acceptanceType.equals(PDA.FINAL_STATE)) 
	    ps.println("FINAL");
	else if(((PDA) a).acceptanceType.equals(PDA.EMPTY_STACK)) 
	    ps.println("EMPTY");
	else if(((PDA) a).acceptanceType.equals(PDA.FINAL_AND_EMPTY)) 
	    ps.println("FINAL+EMPTY");
	else {
	    System.out.println("Warning: invalid acceptance type");
	    return;
	}
    }
    
    ps.println(a.d.theStates.size());
    ps.println(alphabet(INPUT));
    if (type == Machine.PDA)
	ps.println(alphabet(STACK));
    else if (type == Machine.TM1 || type == Machine.TM2)
	ps.println(alphabet(INPUT));
    ps.println(initialState());
    ps.println(finalStates());
    for (Enumeration e=a.d.theStates.elements(); e.hasMoreElements(); )
	ps.println(transitionsFrom((State) e.nextElement()));
    for (Enumeration e=a.d.theStates.elements(); e.hasMoreElements(); )
	ps.println(interfaceData((State) e.nextElement()));
    for (Enumeration e=a.d.theTransitions.elements(); e.hasMoreElements(); )
	ps.println(  ((Transition) e.nextElement()).distance);

    ps.close();
  }	


  // alphabets were only needed in the previous version of flap.
  // putting a '#' on the line and then ignoring it when loading allows 
  // old flap files to be loaded 
  private String alphabet(int which) {
    return "#";
  }	


  private String initialState() {

    int		i = 1;
    State	s = null;
    boolean	done = false;
    Enumeration	e = a.d.theStates.elements();

    while (e.hasMoreElements() && !done) {
      s = (State) e.nextElement();
      if (a.d.initialState == s) 
        done = true;
      else
        ++i;
    }

    return (done)?Integer.toString(i):"0";
  }	// end of method initialState.

  private String finalStates() {

    String	answer = "";
    int		i = 1;

    for (Enumeration e=a.d.theStates.elements(); e.hasMoreElements(); ) {
      if (((State) e.nextElement()).isFinal)
        answer += Integer.toString(i) + " ";
      i++;
    }
    return answer + "0";
  }	// end of method finalState.


  private String transitionsFrom(State s) {

    String	answer = "";
    Transition	t;
    StringTokenizer st = null;
    String	input, push, pop, direction, input2, push2, direction2;

    a.d.setTransitions(s, false);
    for (Enumeration e=s.transitions.elements(); e.hasMoreElements(); ) {
      t = (Transition) e.nextElement();
      if (type == Machine.FSA) {
        answer += ((t.label.trim().equals(""))?"null":t.label.trim())
               + " " + Integer.toString(1+a.d.theStates.indexOf(t.to)) + " ";
      } else if (type == Machine.PDA) {
        st = new StringTokenizer(t.label, ",;", false);
        input = st.nextToken().trim();
        input = (input.trim().equals("")) ? "null": input.trim();
        pop = st.nextToken().trim();
        pop = (pop.trim().equals("")) ? "null": pop.trim();
        push = st.nextToken().trim();
        push = (push.trim().equals("")) ? "null": push.trim();
        answer += input + " " + pop + " null " + Integer.toString(1+a.d.theStates.indexOf(t.to))
               + " " + push + " ";
      } else if (type == Machine.TM1) {
        st = new StringTokenizer(t.label, ";,", false);
        input = st.nextToken().trim();
        push = st.nextToken().trim();
        direction = st.nextToken().trim();
        answer += input + " " + Integer.toString(1+a.d.theStates.indexOf(t.to))
               + " " + push + " " + direction + " ";
      } else if (type == Machine.TM2) {
        st = new StringTokenizer(t.label, ";,|", false);
        input = st.nextToken().trim();
        push = st.nextToken().trim();
        direction = st.nextToken().trim();
        input2 = st.nextToken().trim();
        push2 = st.nextToken().trim();
        direction2 = st.nextToken().trim();
        answer += input + " " + Integer.toString(1+a.d.theStates.indexOf(t.to)) + " "
               + push + " " + direction + " " + input2 + " " + push2 + " " + direction2 + " ";
      }
    }
    return answer + "EOL";
  }	// end of method transitionsFrom.


  private String interfaceData(State s) {

    String	answer = "";
    Transition	t;
    Point	p;
    //Transition samet = new Transition(s, s, 0, null);
    //samet = a.d.sameStatesTransition(samet);

    answer = "q"+ s.id + " " + s.p.x + " " + s.p.y + " " + s.loopSize + " " + s.label;

    return answer;
  }	// end of method interfaceData.

  private String typeString() {
    switch (type) {
      case Machine.FSA: return "One-Way-FSA";
      case Machine.PDA: return "PDAP";
      case Machine.TM1: return "REGTM";
      case Machine.TM2: return "REGTM";
    }
    return "What type is that??";
  }	// end of method typeString.

}	//end of class FileWriter.
