package com.horstmann.labrat;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.compilers.DefaultCompilerAdapter;
import org.apache.tools.ant.types.Commandline;
import org.apache.tools.ant.types.Path;

public class InternalJavaCompiler extends DefaultCompilerAdapter
{
   public Class getCompilerClass() throws BuildException
   {
      if (compilerClass != null)
         return compilerClass;
      
      String compilerClassName = "com.sun.tools.javac.Main";
      ClassLoader loader = getClass().getClassLoader();
      try
      {
         compilerClass = loader.loadClass(compilerClassName);
         return compilerClass;
      }
      catch (Exception ex)
      {
         // oh well...
      }
      
      // find tools.jar

      /*
       * Linux: /usr/local/jdk1.6.0-b90/jre/lib/rt.jar
       * Windows: c:\Program Files\jre1.6.0_01\lib\rt.jar
       */ 
      File rtJar = null;
      String[] paths = Path.systemBootClasspath.list();
      for (String path : paths)
      {
         if (path.toLowerCase().endsWith("rt.jar"))
         {
            rtJar = new File(path);
         }
      }

      if (rtJar == null)
         throw new BuildException("Error starting internal compiler--cannot locate rt.jar");           
      
      File toolsJar = null;
      while (toolsJar == null && (rtJar = rtJar.getParentFile()) != null)
      {
         File f = new File(new File(rtJar, "lib"), "tools.jar");
         if (f.exists()) toolsJar = f;
         else if (rtJar.getName().contains("jre"))
         {
            File f1 = new File(rtJar.getParentFile(), rtJar.getName().replace("jre", "jdk"));
            f = new File(new File(f1, "lib"), "tools.jar");
            if (f.exists()) toolsJar = f;
         }
      }

      getProject().log("tools.jar location=" + toolsJar);
      if (toolsJar == null)
         throw new BuildException("Error starting internal compiler--cannot locate tools.jar");
      try
      {
         loader = new URLClassLoader(new URL[] { toolsJar.toURL() });
         compilerClass = loader.loadClass(compilerClassName);
         return compilerClass;
      }
      catch (Exception ex)
      {
         throw new BuildException("Error starting internal compiler",
               ex, location);
      }      
   }
   

   /**
    * Integer returned by the compiler to indicate success.
    */
   private static final int INTERNAL_COMPILER_SUCCESS = 0;

   /**
    * Run the compilation.
    *
    * @exception BuildException if the compilation has problems.
    */
   public boolean execute() throws BuildException {
       attributes.log("Using internal compiler", Project.MSG_VERBOSE);
       Commandline cmd = setupModernJavacCommand();

       // Use reflection to be able to build on all JDKs >= 1.1:
       try {
           Class c = getCompilerClass();
           Object compiler = c.newInstance ();
           Method compile = c.getMethod ("compile",
               new Class [] {(new String [] {}).getClass ()});
           int result = ((Integer) compile.invoke
                         (compiler, new Object[] {cmd.getArguments()}))
               .intValue ();
           getProject().log("result=" + result);
           return (result == INTERNAL_COMPILER_SUCCESS);
       } catch (Exception ex) {
           if (ex instanceof BuildException) {
               throw (BuildException) ex;
           } else {
               throw new BuildException("Error starting internal compiler",
                                        ex, location);
           }
       }
   }

   private static Class compilerClass;

}
