

import java.util.*;
import Jakarta.util.FixDosOutputStream;
import Jakarta.util.Util;
import java.io.*;

/******************** Main class **************************
 * @layer<CommonBase>
 */

// this layer assumes the following.
// a previous layer has defined in class Main a static method usageOftk
//   which prints out how the -t,-k options are interpreted
// a previous layer has defined in class JTSParseTree a pair of methods:

// public void preprocessTree( $TEqn.AST_Program root ) throws Exception
// for Jampack, this does nothing.  for Mixin, it is to prepare the tree

public class Main {

    public static boolean typeSort = false;
    public static boolean keySort  = false;
    public static boolean copyMode = false;
    public static boolean tagging = false;

    static void usageOftk() {} // to be refined!

    private static void usage( String err ) {
        System.err.println( "Error: " + err );
        System.err.print( "Usage: java " + "Main [options]" );
        System.err.println( " baseFile extensionFile1 extensionFile2 ..." );
        usageOftk(); // to be refined!
        System.err.println( "         -a <layerName> name of layer to generate " );
        System.err.println( "         -f <fileName> name file to generate" );
        System.err.println( "         -c copy single file equation" );
        System.err.println( "         -l label classes/methods with feature source" );
        System.exit( 1 );
    }
      
    public static void main( String[] args ) {
        int                 i;
        int                 argc = args.length;
        int                 non_switch_args;
        JTSParseTree  base = null;
        JTSParseTree  ext  = null;
        String              aspectName = null;
        String              fileName = null;
   
        // Step 1: a general routine to pick off command line options
        //         options are removed from command line and
        //         args array is adjusted accordingly.
        //         right now, there are no command-line options
        //         but this code is here for future expansion
      
        non_switch_args = 0;

        for ( i=0; i < argc; i++ ) {

            if ( args[i].charAt( 0 ) != '-' ) {
                args[non_switch_args] = args[i];
                non_switch_args++;
                continue ;
            }

            String arg = args [i] ;

            // Switches of form -xxx where xxx is a word:
            //
            if ( arg.equals( "-layer" ) && i + 1 < args.length ) {
                aspectName = args [++i] ;
                continue ;
            }

            if ( arg.equals( "-model" ) && i + 1 < args.length ) {
                setModelDirectory( args [++i] ) ;
                continue ;
            }

            if ( arg.equals( "-output" ) && i + 1 < args.length ) {
                fileName = args [++i] ;
                continue ;
            }

            // Switches of form -xxx where each x is a switch character:
            //
            for ( int j=1; j < arg.length(); j++ ) {

                char cur = arg.charAt( j );
                                 
                // Simple toggle switches:
                //
                if ( cur == 'k' ) {
                    keySort = true;
                    continue;
                }
                if ( cur == 't' ) {
                    typeSort = true;
                    continue;
                }
                if ( cur == 'c' ) {
                    copyMode = true;
                    continue;
                }
                if ( cur == 'l' ) {
                    tagging = true;
                    continue;
                }

                // Switches with an argument:
                //
                if ( cur != 'a' && cur != 'f' )
                    usage( "unrecognized option: " + cur );

                if ( i + 1 >= args.length )
                    usage( "option requires an argument: " + cur ) ;

                if ( cur == 'a' ) {
                    aspectName = args[++i];
                    continue;
                }
                if ( cur == 'f' ) {
                    fileName = args[++i];
                    continue;
                }

                usage( "unrecognized option: " + cur );
            }
        }
     
        if ( getModelDirectory() == null )
            setModelDirectory( null ) ;

        // Step 2: there must be at least one real input argument, 
        //         otherwise error

        if ( non_switch_args == 0 )
            usage( "must specify at least one input file" );

        // Step 3a: if we have an equation that has a single term (file) AND
                  //          we are in copy mode, then simply copy the file verbatim
                  //          and return
                  
        if ( copyMode && non_switch_args == 1 ) {
            try {
                if ( fileName == null )
                    ; //Util.copyFile( new File(args[0]), System.out );
                else
                    Util.copyFile( new File( args[0] ), new File( fileName ) );
            }
            catch ( Exception e ) {
                AstNode.fatalError( e, "failed to parse" );
            }
            return;
        }

        // Step 3: initialize JTSParseTree

        if ( fileName != null )
            setBaseURI( Util.getFullPath( new File( fileName ) ) ) ;
        else
            setBaseURI( "." ) ;

        JTSParseTree.resetCounters();
        JTSParseTree.setReportStream( new PrintWriter( System.err ) );

        // Step 4: parse the base file

        try {
            base = new  JTSParseTree( args[0] );
        }
        catch ( Exception e ) {
            AstNode.fatalError( e, "failed to parse" );
        }

        // Step 5: for each extension, parse it and compose it with base

        try {
            for ( i=1; i<non_switch_args; i++ ) {
                ext  = new  JTSParseTree( args[i] );
                base.compose( ext );
            }
        }
        catch ( ParseException pe ) {
            AstNode.fatalError( pe, "failed to parse" );
        }
        catch ( Exception e ) {
            AstNode.fatalError( e, "failed to compose" );
        }

        if ( aspectName != null )
            base.setAspectName( aspectName );

        // Step 6: do cleanup 

        if ( base.errorCount() == 0 ) {
            // we had no errors, maybe some warnings
            AstProperties props = AstProperties.open( fileName );
            base.root.reduce2java( props );
            props.close();
            /*
                        if ( fileName == null )
                            base.print();
                        else {
                            base.print2file( fileName );
                        }
            */
            System.out.flush();
        }
        else {
            AstNode.toolReport( base.errorCountString() );
        }

    } //end main()
}
