/**

 http://www-128.ibm.com/developerworks/websphere/library/techarticles/0502_gawor/0502_gawor.html

 java -classpath build:/home/apps/apache-ant-1.6.5/lib/ant.jar:/home/apps/apache-ant-1.6.5/lib/ant-launcher.jar com.horstmann.grader.AntRunner
 */
package com.horstmann.labrat;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Scanner;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DefaultLogger;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.ProjectHelper;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.util.JavaEnvUtils;

/*
 * Need to include ant-nodeps.jar for org/apache/tools/ant/util/regexp/Jdk14RegexpRegexp.class
 */

public class AntRunner
{
   /**
    * 
    * @param args args[0] = type ("check" or "grade")<br>
    * args[1] = student submission directory<br>
    * args[2] = directory with grading instructions (only for type grade)
    */
    public static void main(String[] args)
    {       
       String mode = args[0];
       String submissionDirectory = args[1];
    
       AntRunner runner = new AntRunner();
       File baseDir = new File(submissionDirectory);
       runner.setBaseDir(baseDir);
       if (mode.equals("grade"))
       {
          String solutionDirectory = args[2];       
          runner.putProperty("testcases.dir", solutionDirectory);
       }
       // TODO: Put Ant output into submission directory?
       runner.setOut(System.out);
       runner.setErr(System.out);
       runner.run(mode, "check");
    }   
   
    public void run(String type, String fallback)
    {
        project = new Project();
        
        /*
         * If you want to find tools.jar, try  
        Path.systemBootClasspath
        Path.systemClasspath
        AntClassLoader classLoader = p.createClassLoader(new Path(p, javaHome + "/lib/tools.jar"));
        classLoader.setParent(getClass().getClassLoader());
        System.out.println(classLoader.getClasspath());
        System.out.println(javaHome);
        p.setCoreLoader(classLoader);       
        */
        
        // out.println("systemBootClasspath=" + Path.systemBootClasspath);
        // out.println("systemClasspath=" + Path.systemClasspath);
        // out.println(JavaEnvUtils.getJdkExecutable("javac"));
        
        // project.setProperty("build.compiler", InternalJavaCompiler.class.getName());
        
        project.setBaseDir(baseDir);
        File buildFile = new File(baseDir, type + ".xml");
        if (!buildFile.exists())
           buildFile = new File(baseDir, fallback + ".xml");
        report = new Report();
        project.addBuildListener(report);
        boolean buildFileIsTemporary = false;
        if (buildFile.exists())
            project.setUserProperty("ant.file", buildFile.getAbsolutePath());
        else
        {
            try
            {
                buildFile = File.createTempFile(type, ".xml");
                buildFileIsTemporary = true;
                PrintWriter out = new PrintWriter(buildFile);
                InputStream inStream = getClass().getResourceAsStream(type + ".xml");
                if (inStream == null) inStream = getClass().getResourceAsStream(fallback + ".xml");
                Scanner in = new Scanner(inStream);
                while (in.hasNextLine())
                {
                    out.println(in.nextLine());
                }
                in.close();
                out.close();                
            }
            catch (IOException ex)
            {
                ex.printStackTrace();
                return;
            }
        }
        DefaultLogger consoleLogger = new DefaultLogger();
        consoleLogger.setErrorPrintStream(err);
        consoleLogger.setOutputPrintStream(out);
        consoleLogger.setMessageOutputLevel(Project.MSG_INFO);
        project.addBuildListener(consoleLogger);
        for (Map.Entry<String, String> entry : props.entrySet())
           project.setProperty(entry.getKey(), entry.getValue());
        
        try
        {
            project.fireBuildStarted();
            project.init();
            ProjectHelper helper = ProjectHelper.getProjectHelper();
            project.addReference("ant.projectHelper", helper);
            helper.parse(project, buildFile);

            
            Properties defaultProps = new Properties();
            try
            {
                defaultProps.load(getClass().getResourceAsStream(type + ".properties"));                
            }
            catch (Exception ex) 
            {
               try
               {
                  defaultProps.load(getClass().getResourceAsStream(fallback + ".properties"));                  
               }
               catch (Exception ex2)
               {
                  // we tried...                  
               }
            }
            for (Map.Entry<Object, Object> entry : defaultProps.entrySet())
               project.setProperty("" + entry.getKey(), "" + entry.getValue());
            
            project.executeTarget(project.getDefaultTarget());
            project.fireBuildFinished(null);
        }
        catch (BuildException e)
        {
            project.fireBuildFinished(e);
        }
        if (buildFileIsTemporary) buildFile.delete();
    }

    public void setBaseDir(File baseDir)
    {
        this.baseDir = baseDir;
    }

    public void setErr(PrintStream err)
    {
        this.err = err;
    }

    public void setOut(PrintStream out)
    {
        this.out = out;
    }    
    
    public void putProperty(String key, String value) { props.put(key, value); }
    
    public Report getReport() { return report; }
    
    private Project project;
    private PrintStream out = System.out;
    private PrintStream err = System.err;
    private File baseDir;
    private Report report;
    private Map<String, String> props = new HashMap<String, String>();
}
