/*
 * $Header: /home/harald/repos/remotetea.sf.net/remotetea/src/org/acplt/oncrpc/apps/jrpcgen/jrpcgen.java,v 1.6 2007/05/29 19:38:30 haraldalbrecht Exp $
 *
 * Copyright (c) 1999, 2000
 * Lehrstuhl fuer Prozessleittechnik (PLT), RWTH Aachen
 * D-52064 Aachen, Germany.
 * All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This library 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 PURPOSE.  See the
 * GNU Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this program (see the file LICENSE.txt for more
 * details); if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
 */

//
// Personal note: this class probably suffers from a flashback on
// procedural programming ... but where do we need to be today?
//

package org.acplt.oncrpc.apps.jrpcgen;


import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.PrintStream;


/**
 * The class <code>jrpcgen</code> implements a Java-based rpcgen RPC protocol
 * compiler. jrpcgen is a Java-based tool that generates source code of Java
 * classes to implement an RPC protocol. The input to jrpcgen is a language
 * similiar to C (but more probably much more similiar to FORTRAN) known as
 * the RPC language (Remote Procedure Call Language).
 *
 * @version $Revision: 1.6 $ $Date: 2007/05/29 19:38:30 $ $State: Exp $ $Locker:  $
 * @author Harald Albrecht
 */
public class jrpcgen {

	/**
	 * Current version of jrpcgen.
	 */
	public static final String VERSION = "1.1.6";

    /**
     * A remote procedure has no parameters and thus needs to use the
     * XDR void wrapper class as a dummy.
     */
    public static final int PARAMS_VOID = 0;

    /**
     * A remote procedure expects only a single parameter, which is a
     * complex type (class).
     */
    public static final int PARAMS_SINGLE = 1;

    /**
     * A remote procedure expects only a single parameter, which is of
     * a base type, like integer, boolean, string, et cetera.
     */
    public static final int PARAMS_SINGLE_BASETYPE = 2;

    /**
     * A remote procedure expects more than one parameter and thus needs
     * an XDR wrapping class.
     */
    public static final int PARAMS_MORE = 3;

    
    private JrpcgenContext context;
    
    /**
     * The main part of jrpcgen where all things start.
     * 
     * @param args A string array containing the command line arguments passed on invocation. 
     */
    public static void main(String[] args) {
    	
    	/*
    	 * Evaluate the command line arguments first.
    	 */
    	JrpcgenOptions options = new JrpcgenOptions();
    	JrpcgenOptions.Arguments arguments = options.newArguments(args);
    	
    	String xfilename = null;
    	
    	switch (arguments.parse(System.out)) {
    	case VALID:
    	case LAST:
    		/*
    		 * The last argument is expected ot contain
    		 * the name of the x-file.
    		 */
    		xfilename = arguments.getXFilename();
    		
    		if (xfilename != null) {
    			/*
    			 * Open a context and try to parse the x-file.
    			 */
    	        try (JrpcgenContext context = JrpcgenContext.open(options, xfilename, VERSION)){
    	            jrpcgen generator = new jrpcgen(context);
    	            generator.doParse().generateJavaFiles();
    	        } catch ( Throwable t ) {
    	            System.out.println(t.getMessage());
    	            t.printStackTrace();
    	            //
    	            // Exit application with non-zero outcome, so in case jrpcgen is
    	            // used as part of, for instance, a make process, such tools can
    	            // detect that there was a problem.
    	            //
    	            System.exit(1);
    	        }
    		} else {
    			System.out.println(options);
    			printHelp(System.out);
    			System.exit(1);
    		}
    		break;
    		
    	case HELP_REQUESTED:
    		printHelp(System.out);
    		break;
    		
    	case VERSION_REQUESTED:
			System.out.println("jrpcgen version \"" + VERSION + "\"");
			break;

    	case INVALID:
    		System.exit(1);
    	}
    }

    public static void printHelp(PrintStream out) {
		out.println("Usage: jrpcgen [-options] x-file");
		out.println();
		out.println("where options include:");
		JrpcgenOptions.printOptions(out);
		out.println();
	}

    public jrpcgen(JrpcgenContext context) {
    	this.context = context;
    }
    
    public void reset()
    {
    	context.reset();
    }
    
    public JrpcgenContext context() {
    	return context;
    }
    
    public JrpcgenOptions options() {
    	return context.options();
    }

    /**
     * The real parsing and code generation part. This has been factored out
     * of main() in order to make it available as an Ant task.
     * 
     * @throws FileNotFoundException if the specified x-file does not exist or cannot be opened for reading.
     * @throws Exception if any kind of error like a parser error occurs.
     */
    public JrpcgenModule doParse()
           throws FileNotFoundException, Exception {    	
    	JrpcgenOptions options = context.options();
    	
        //
        // Get the base name for the client and server classes, it is derived
        // from the filename.
        //
        if ( options.baseClassname == null ) {
            String name = context.xFile.getName();
            int dotIdx = name.lastIndexOf('.');
            if ( dotIdx < 0 ) {
                options.baseClassname = name;
            } else {
                options.baseClassname = name.substring(0, dotIdx);
            }
        }
        //
        //
        //
        FileInputStream in = null;
        try {
            in = new FileInputStream(context.xFile.getCanonicalPath());
        } catch ( FileNotFoundException e ) {
            throw(new FileNotFoundException("jrpcgen: can not open source x-file \""
                                            + context.xFile.getCanonicalPath() + "\""));
        }
        JrpcgenScanner scanner = new JrpcgenScanner(in);
        JrpcgenParser parser = new JrpcgenParser(scanner);
        JrpcgenModule module = new JrpcgenModule(context);
        
        parser.setModule(module);
        
        try {
            //Symbol sym = 
            parser.parse();
            if ( !options.parseOnly ) {
                if ( module.getProgramInfos().size() <= 1 ) {
                    if ( options.clientClass == null ) {
                        options.clientClass = options.baseClassname + "Client";
                    }
                    if ( options.serverClass == null ) {
                        options.serverClass = options.baseClassname + "ServerStub";
                    }
                }
            }
        } catch ( JrpcgenParserException pe ) {
            throw(new Exception("jrpcgen: compilation aborted (" + pe.getMessage() + ")" , pe));
        }
        
        return module;
    }
}
// End of file jrpcgen.java
