// Copyright 2000, CERN, Geneva, Switzerland and SLAC, Stanford, California, U.S.A.
package org.freehep.jaco;

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

import org.freehep.util.commandline.CommandLine;
import org.freehep.util.commandline.CommandLineException;

import org.freehep.jaco.rtti.*;
import org.freehep.jaco.rtti.java.JavaParser;
import org.freehep.jaco.rtti.cpp.CPlusPlusParser;
import org.freehep.jaco.generator.*;

/**
 * @author Mark Donszelmann
 * @version $Id: Jaco.java,v 1.1.1.1 2004/05/31 05:08:50 kuromaru Exp $
 */
public class Jaco {

    private static String jacoVersion = "0.2";
    private static String jaco = "Java Access to C++ Objects (version "+jacoVersion+")";

    private static RTTI rtti = new RTTI();

    public static RTTI getRTTI() {
        return rtti;
    }

    public static void main(String[] args) {
  		CommandLine cl = new CommandLine("jaco", jaco, 1);
  		cl.addBailOutOption("help", "h", "Show this help page");
  		cl.addBailOutOption("version", "v", "Show product version");
  		cl.addOption("rtti", "r", "Print RTTI to stdout");
  		cl.addOption("nogenerate", "n", "Do not generate any code");
  		cl.addOption("directory", "d", "output dir", "Output into directory instead of current directory");
  		cl.addOption("package", "p", "package name", "Generate java code using package name");
  		cl.addOption("force", "f", "Force overwriting of output files");
        cl.addMultiOption("I", "directory", "Add directory to include search path");
        cl.addOption("cplusplus", "c", "edition", "Set edition of the C++ grammar [1..3]");
        cl.addOption("ignore", "i", "Ignore errors from the parser");
  		cl.addParameter("files...", "C++ header files");

        try {
            if (!cl.parse(args)) {
                if (cl.hasOption("help")) {
                    System.err.println(cl.getHelp());
                    System.exit(0);
                } else if (cl.hasOption("version")) {
                    System.err.println(jaco);
                    System.exit(0);
                }
                System.err.println("ERROR: unrecognized bail out option.");
                System.exit(1);
            }
        } catch (CommandLineException cle) {
            System.err.println("ERROR: "+cle.getMessage());
            System.err.println();
            System.err.println(cl.getHelp());
            System.exit(1);
        }

        String[] files = cl.getArguments();

        Vector includeDirs = cl.getMultiOption("I");

        int cplusplus = 2;
        try {
            cplusplus = Integer.parseInt(cl.getOption("cplusplus", "2"));
        } catch (NumberFormatException nfe) {
            System.err.println("Option 'cplusplus "+cl.getOption("cplusplus")+"' ignored, using "+cplusplus);
        }

        boolean ignore = cl.hasOption("ignore");

        // parse files
        Parser parser;
        for (int i=0; i<files.length; i++) {
            String filename = files[i];
            try {
                if (filename.endsWith(".java")) {
                    System.out.println("Parsing Java: "+filename);
                    parser = new JavaParser(new java.io.FileInputStream(filename));
                } else {
                    System.out.println("Parsing CPlusPlus: "+filename);
                    parser = new CPlusPlusParser(filename, includeDirs, cplusplus);
                }
                parser.parse();
                parser.addGlobalClasses();
            } catch (java.io.FileNotFoundException e) {
                System.err.println("ERROR: File " + filename + " not found.");
                if (!ignore) System.exit(1);
            } catch (ParseException e) {
                System.err.println("ERROR: Encountered errors during parse.");
                System.err.println(e.getMessage());
                if (!ignore) System.exit(1);
            } catch (Exception e) {
                System.err.println("ERROR: "+e);
                if (!ignore) System.exit(1);
            }
        }

        // check for package prefix
        String packagePrefix = cl.hasOption("package") ? cl.getOption("package") : "" ;

        // check to print out rtti
        if (cl.hasOption("rtti")) {
            System.out.println(Jaco.getRTTI().toString(packagePrefix));
        }

        // only generate
        if (cl.hasOption("nogenerate")) {
            System.out.println("No code generated.");
            System.exit(0);
        }

        // check if we forced overwrite mode
        boolean overwrite = (cl.hasOption("force")) ? true : false;

        try {
            // generate proxies
            String outDir = cl.hasOption("directory") ? cl.getOption("directory") : ".";
            StringBuffer s = new StringBuffer("");
            String[] names = Jaco.getRTTI().getClassNames();
            for (int i=0; i<names.length; i++ ) {
                IClass clazz = Jaco.getRTTI().getClass(names[i]);

                AbstractGenerator generator;
                generator = new JavaInterface();
                generator.setPackagePrefix(packagePrefix);
                writeClass(generator, clazz, outDir, overwrite);
                generator = new JavaProxy();
                generator.setPackagePrefix(packagePrefix);
                writeClass(generator, clazz, outDir, overwrite);
                generator = new JNIStub();
                generator.setPackagePrefix(packagePrefix);
                writeClass(generator, clazz, outDir, overwrite);
                generator = new JNIStubImplementation();
                generator.setPackagePrefix(packagePrefix);
                writeClass(generator, clazz, outDir, overwrite);

            }
        } catch (IOException ioe) {
            System.err.println(ioe);
            System.exit(1);
        }

        System.exit(0);
    }

    static void writeClass(Generator generator, IClass clazz, String outDir, boolean overwrite) throws IOException {

		File dir = new File(outDir+"/"+generator.directory(clazz));
        dir.mkdirs();
        File file = new File(dir, generator.filename(clazz));

        // Check if we are overwriting a class which was already generated by us
        if (!overwrite) {
            if (file.exists()) {
                BufferedReader reader = new BufferedReader(new FileReader(file));
                String line = reader.readLine();
                if ((line == null) || (line.indexOf("JACO-GENERATED") < 0)) {
                    throw new IOException("Non JACO-GENERATED file exists '"+file+"', cannot overwrite, use -force option");
                }
                reader.close();
            }
        }

		System.out.println("Generating: "+file);

		PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(file)));
		generator.print(writer, clazz);
        writer.close();
    }
}
