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

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

import org.freehep.jaco.rtti.Parser;

/**
 * @author Mark Donszelmann
 * @version $Id: CPlusPlusParser.java,v 1.16 2000/07/19 15:49:28 duns Exp $
 */
public class CPlusPlusParser implements Parser {

    private int compilerEdition;
    private String fileName;
    private Vector includeDirs;
    private Process process;

    public CPlusPlusParser(String name, Vector include, int version) {
        fileName = name;
        includeDirs = include;
        compilerEdition = version;
    }
    
    public CPlusPlusParser(String name, int version) {
        this(name, null, version);
    }
    
    public CPlusPlusParser(String name) {
        this(name, null, 1);
    }    
    
    public void parse() throws org.freehep.jaco.rtti.ParseException, FileNotFoundException {
    
        InputStream istream = null;

        try {
//            checkFile();
                                
            istream = createCPreProcessorStream();
            switch (compilerEdition) {
                case 1:
                case 2:
                default:
                    CPPParser parser = new CPPParser(new BufferedReader(new InputStreamReader(istream)));
                    parser.translation_unit();
                    break;
                case 3:
                    CPPParser3rd parser3rd = new CPPParser3rd(new BufferedReader(new InputStreamReader(istream)));
                    parser3rd.translation_unit();
                    break;
            }
            istream.close();
        } catch (IOException ioe) {
            throw new org.freehep.jaco.rtti.ParseException("IO: "+ioe.getMessage());
        } catch (UnsupportedException e) {
            String file;
            switch (compilerEdition) {
                case 1:
                case 2:
                default:
                    file = CPPParserTokenManager.beginFile;            
                    break;
                case 3:
                    file = CPPParser3rdTokenManager.beginFile;            
                    break;
            }            
            throw new org.freehep.jaco.rtti.ParseException("UnsupportedError in '"+file+"' "+
                "("+e.line+"): "+e.getMessage());                
        } catch (ParseException e) {
            int line = e.currentToken.next.beginLine;
            String file;
            switch (compilerEdition) {
                case 1:
                case 2:
                default:
                    file = CPPParserTokenManager.beginFile;
                    break;
                case 3:
                    file = CPPParser3rdTokenManager.beginFile;
                    break;
            }            
            throw new org.freehep.jaco.rtti.ParseException("ParseError in '"+file+"'): "+e.getMessage());
        }
        try {
            process.waitFor();
        } catch (InterruptedException ie) {
        }
        int exitValue = process.exitValue();
        process.destroy();
        process = null;
        if (exitValue != 0) {        
            throw new org.freehep.jaco.rtti.ParseException("CPreProcessorError in '"+fileName+"'");
        }
        System.err.println("File '"+fileName+"' is ok.");
    }

    public void addGlobalClasses() {
        switch (compilerEdition) {
            case 1:
            case 2:
            default:
                CPPParser.addGlobalClasses();
                break;
            case 3:
                CPPParser3rd.addGlobalClasses();
                break;
        }            
    }
    
    // (MD) extra test to see if all include files can be found!
    // the CPreProcessor stream throws an IOException, but that one seems to 
    // be consumed by the CPPParserTokenManager!
    private void checkFile() throws IOException {
        InputStream istream = createCPreProcessorStream();
        BufferedReader bufReader = new BufferedReader(new InputStreamReader(istream));
        String strLine;
        int lineNo = 1;
        while((strLine = bufReader.readLine()) != null) {
//            System.out.println(lineNo+strLine);
            lineNo++;
        }                                
        istream.close();
        System.err.println("Checked file: "+fileName);
    }

    private InputStream createCPreProcessorStream() throws IOException {
        String os = System.getProperty("os.name");
        String command;
        String include;
        String options;
        if (os.startsWith("Windows")) {
            command = "CL";
            include = "/I";
            // add /TP option
//            options = "/TP /C /E /DMIDL_PASS /D_WCHAR_T_DEFINED /D__inline=inline /D__asm=asm /U_MSC_VER /D__int64=long"; //  /D__cplusplus";
            options = "/nologo /TP /C /E /U_MSC_VER /DMIDL_PASS /D_WCHAR_T_DEFINED /D__inline=inline /D__asm=asm /D__int64=long"; //  /D__cplusplus";
        } else {
            command = "g++";
            include = "-I";
            options = "-x c++ -C -E -ansi -pedantic -D_WCHAR_T_DEFINED -U__GNUC__ -U__GNUG__"; // -U_MSC_VER -D__cplusplus";
        }
        for (int i=0; i<includeDirs.size(); i++) {
            String dir = (String)includeDirs.elementAt(i);
            options += " "+include+dir;
        }
        
        Runtime runtime = Runtime.getRuntime();
        System.err.println(command+" "+options+" "+fileName);
        process = runtime.exec(command+" "+options+" "+fileName);
        InputStream istream = process.getInputStream();
        Thread thread = new Thread(new Runnable() {
            public void run() {
                try {
                    InputStream estream = process.getErrorStream();
                    BufferedReader bufReader = new BufferedReader(new InputStreamReader(estream));
                    String strLine;
                    while((strLine = bufReader.readLine()) != null) {
                        System.err.println(strLine);
                    }
                    estream.close();
                } catch (IOException ioe) {
                    System.err.println(ioe);
                }
            }
        });
        thread.start();
        
//        try {
//            System.out.println(process.waitFor());
//        } catch (InterruptedException ie) {
//            System.out.println("Interrupted");
//        }
//        System.out.println("Exit value: "+process.exitValue());
        return istream;        
    }
}
