package edu.neu.ccs.demeterf.demfgen;

import edu.neu.ccs.demeterf.lib.List;
import edu.neu.ccs.demeterf.demfgen.classes.PackageDef;

import java.io.*;

/**  */
public class Make{
    static void p(String s){{ System.err.print(s); }}
    public static void make(String dir, PackageDef basepkg, boolean parse, List<String> opts,
            int libidx, List<String> pkgdirs){
        boolean win = Diff.optionSet(Diff.windows);
        boolean noshell = Diff.optionSet(Diff.noshell);
        boolean comp = Diff.optionSet(Diff.build);
        String basedir = DemFGenMain.pkgdir(dir, basepkg, true);
        
        if(parse){
            p(Diff.d.makeParseMsg+"\n");
            if(win)runCmd(Diff.d.mkWinParseCmd(basedir),Diff.d.parserGen);
            else if(noshell)runCmd(Diff.d.mkParseCmdNoShell(basedir),Diff.d.parserGen);
            else runCmd(Diff.d.mkParseCmd(basedir),Diff.d.parserGen);
        }
        if(libidx >= 0){
            p(Diff.d.makeBuildMsg+"\n");
            String name = opts.lookup(libidx);
            int colon = name.indexOf(":");
            if(win)runCmd(Diff.d.buildWinCmd(pkgdirs, true, name.substring(colon+1)), "CSC");
            else runCmd(Diff.d.buildCmd(pkgdirs, true, name.substring(colon+1)), Diff.d.compilerName);
        }else{
            if(comp){
                p(Diff.d.makeBuildMsg+"\n");
                if(win)runCmd(Diff.d.buildWinCmd(pkgdirs, false, ""), "CSC");
                else runCmd(Diff.d.buildCmd(pkgdirs, false, ""), Diff.d.compilerName);
            }
        }
    }
    static class Read extends Thread{
        StringBuffer sb;
        StringBuffer warn = new StringBuffer();
        BufferedReader rd;
        
        Read(StringBuffer s, InputStream i){ 
            sb = s;
            rd = new BufferedReader(new InputStreamReader(i));    
        }
        static final String tab = "    "; 
        public void run(){
            try{
                String s = "";
                while((s = rd.readLine()) != null){
                    if(s.startsWith("Warning")){
                        do{
                            sb.append(tab+breakUp(s)).append("\n");
                            warn.append(tab+breakUp(s)).append("\n");
                            s = rd.readLine();
                        }while(s != null && s.startsWith(" "));
                    }
                    if(s != null)
                        sb.append(tab+breakUp(s)).append("\n");
                }
            }catch(IOException e){
                System.err.println("\n\n !! Error:\n"+e.getMessage());
                System.exit(1);
            }
        }
        String breakUp(String s){
            if(s.length() > 80){
                int i = 80;
                while(i < s.length() && Character.isWhitespace(s.charAt(i)))
                    i++;
                return s.substring(0,i)+"\n"+tab+"  "+breakUp(s.substring(i));
            }
            return s;
        }
        public boolean didWarn(){ return warn.length()>0; }
        public String warnings(){ return warn.toString(); }
    }
    static void runCmd(String[] s, String label){
        try{
            Runtime run = Runtime.getRuntime();
            final Process cmd = run.exec(s);
            int result;
            // Windows doesn't seem to let a Process finish until it's OutputStream has
            //   been emptied... Lame.
            StringBuffer eb = new StringBuffer(),
                         ib = new StringBuffer();
            Read r = new Read(eb,cmd.getErrorStream());
            r.start();
            new Read(ib,cmd.getInputStream()).start();
            try{ result = cmd.waitFor(); }catch(InterruptedException ie){ result = 1; }
            try{ r.join(); }catch(InterruptedException e){}
            
            if(result != 0){
                p("\n\n !! "+label+" Errors:\n\n");
                p(eb.toString());
                p(ib.toString()+"\n");
                System.exit(1);
            }else if(r.didWarn()){
                p("\n\n !! "+label+" Warnings:\n\n");
                p(r.warnings()+"\n");
            }
        }catch(IOException e){
            p(" !! Exception :"+e.getMessage()+"\n");
        }
    }
}