

import java.util.Hashtable;
import java.util.Vector;
import Jakarta.util.FixDosOutputStream;
import java.io.*;

class Utility  {

    // this method decides whether to translate the parent state machine file
    // (and hence regenerate its .ser file.  It returns true if a retranslation
    // (i.e., recursive invocation of parse) is needed

    public static boolean retranslate( String serfilename, String jakfilename ) {

        // Step 1: get a handle to both files

        File ser = null;
        File jak = null;
        try {
            ser = new File( serfilename );
            jak = new File( jakfilename );
        }
        catch ( Exception e ) {
            AstNode.fatalError( e.getMessage() );
        }

        // Step 2: check to see if both exist

        boolean serExists = false;
        boolean jakExists = false;
        try {
            serExists = ser.exists();
            jakExists = jak.exists();
        }
        catch ( Exception e ) {
            AstNode.fatalError( e.getMessage() );
        }

        // Step 3: get the modification times of both files

        long serTime = 0;
        long jakTime = 0;
        try {
            if ( serExists )
                serTime = ser.lastModified();
            if ( jakExists )
                jakTime = jak.lastModified();
        }
        catch ( Exception e ) {
            AstNode.fatalError( e.getMessage() );
        }

        // Step 4: we must retranslate the .jak file (and thus regenerate
        //         the .ser file if (the .ser file does not exist) OR
        //         the jakfile was modified after the serfile

        boolean retrans = !serExists || jakTime > serTime;

        // Step 5: if the .jak file doesn't exist AND we have to retranslate, 
        //         we have a fundamental problem -- we can't translate 
        //         a non-existant file to produce a .ser file.
        //         Note: it is possible that a .ser file exists but no .jak
        //         file -- this happens when a single .jak file defines multiple
        //         state machines, listed in ancestor order.  In this way,
        //         parent state machines are translated first, and thus their
        //         .ser files will exist even though there is no .jak file, per se,
        //         that uniquely identifies parent state machines

        if ( retrans && !jakExists ) {
            AstNode.fatalError( "parent state machine in " + jakfilename + " does not exist" );
        }

        return retrans;

    }

    static String FileName( String n, String extension ) {
        String filename = n + extension;
        if ( kernelConstants.globals().sm4vars.ser_directory != null )
            filename =  kernelConstants.globals().sm4vars.ser_directory + 
                           File.separatorChar + filename;
        return filename;
    }

    static String SerFileName( String n ) {
        return FileName( n,  sm4data.serExtension );
    }

    static String JakFileName( String n ) {
	     // there are two ways of determining the extension of a jak file.
		  // we will first use the currentFileExt, and if that fails,
		  // default to the jakExtension set on the command-line (defaulting to .jak)

        String f = FileName( n,  kernelConstants.globals().currentFileExt );
		  try {
		     File fl = new File(f);
           if (fl.exists())
			     return f;
		  }
		  catch (Exception e) { /* ignore errors */ }
        return FileName( n,  kernelConstants.jakExtension );
    }

    static String SourceName() { // for reporting errors
        return "In State Machine " +  kernelConstants.globals().sm4vars.Sm.name + ": ";
    }

    // this method either reads a previously built .ser file, or 
    // invokes the parser to retranslate the .jak file

    public static  sdInfo LocateSuperSmFile() {

        // Step 1: get the file names for the .jak and .ser files

        String jakFile = JakFileName( kernelConstants.globals().sm4vars.Sm.superSm_name );
        String serFile = SerFileName( kernelConstants.globals().sm4vars.Sm.superSm_name );

        // Step 2: retranslate if necessary

        if ( retranslate( serFile,jakFile ) ) {
            Main.instance.processing( "jak2java", jakFile );
        }

        // Step 3: now read the ser file
        return ( sdInfo ) readObjectFromFile( serFile );
    }

    static void writeObjectToFile( Object o, String filename ) {
        ObjectOutputStream os = null;

        try {
            os = new ObjectOutputStream( new FileOutputStream( filename ) );
        }
        catch( Exception e ) {
            AstNode.fatalError( "writeObjectToFile(.., " + 
                            filename + e.getMessage() );
        }
   
        try {
            os.writeObject( o );
            os.close();
        }
        catch( Exception e ) {
            AstNode.fatalError( e.getMessage() );
        }

        // write is successful.  Now write object to $TEqn.kernelConstants.globals().sm4vars.serCache
 
        kernelConstants.globals().sm4vars.serCache.put( filename, o );
    }

    static Object readObjectFromFile( String filename ) {
        ObjectInputStream is = null;

        // first, see if object exists in the $TEqn.kernelConstants.globals().sm4vars.serCache.  If so,
        // return it, else read from file.

        Object o =  kernelConstants.globals().sm4vars.serCache.get( filename );
        if ( o != null )
            return o;

        try {
            is = new ObjectInputStream( new FileInputStream( filename ) );
            o = is.readObject();
            is.close();
        }
        catch ( Exception e ) {
            AstNode.fatalError( e.getMessage() );
        }

        // finally, put the object in the cache
        kernelConstants.globals().sm4vars.serCache.put( filename, o );
        return o;
    }
}
