package net.sf.jasperreports.engine;

import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collection;
import net.sf.jasperreports.crosstabs.JRCrosstab;
import net.sf.jasperreports.engine.design.JRCompiler;
import net.sf.jasperreports.engine.design.JRJavacCompiler;
import net.sf.jasperreports.engine.design.JRJdk13Compiler;
import net.sf.jasperreports.engine.design.JRJdtCompiler;
import net.sf.jasperreports.engine.design.JRVerifier;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.fill.JREvaluator;
import net.sf.jasperreports.engine.util.JRClassLoader;
import net.sf.jasperreports.engine.util.JRLoader;
import net.sf.jasperreports.engine.util.JRProperties;
import net.sf.jasperreports.engine.util.JRSaver;
import net.sf.jasperreports.engine.xml.JRXmlLoader;
import net.sf.jasperreports.engine.xml.JRXmlWriter;

public class JasperCompileManager {
  public static String compileReportToFile(String sourceFileName) throws JRException {
    File sourceFile = new File(sourceFileName);
    JasperDesign jasperDesign = JRXmlLoader.load(sourceFileName);
    File destFile = new File(sourceFile.getParent(), jasperDesign.getName() + ".jasper");
    String destFileName = destFile.toString();
    compileReportToFile(jasperDesign, destFileName);
    return destFileName;
  }
  
  public static void compileReportToFile(String sourceFileName, String destFileName) throws JRException {
    JasperDesign jasperDesign = JRXmlLoader.load(sourceFileName);
    compileReportToFile(jasperDesign, destFileName);
  }
  
  public static void compileReportToFile(JasperDesign jasperDesign, String destFileName) throws JRException {
    JasperReport jasperReport = compileReport(jasperDesign);
    JRSaver.saveObject(jasperReport, destFileName);
  }
  
  public static JasperReport compileReport(String sourceFileName) throws JRException {
    JasperDesign jasperDesign = JRXmlLoader.load(sourceFileName);
    return compileReport(jasperDesign);
  }
  
  public static void compileReportToStream(InputStream inputStream, OutputStream outputStream) throws JRException {
    JasperDesign jasperDesign = JRXmlLoader.load(inputStream);
    compileReportToStream(jasperDesign, outputStream);
  }
  
  public static void compileReportToStream(JasperDesign jasperDesign, OutputStream outputStream) throws JRException {
    JasperReport jasperReport = compileReport(jasperDesign);
    JRSaver.saveObject(jasperReport, outputStream);
  }
  
  public static JasperReport compileReport(InputStream inputStream) throws JRException {
    JasperDesign jasperDesign = JRXmlLoader.load(inputStream);
    return compileReport(jasperDesign);
  }
  
  public static JasperReport compileReport(JasperDesign jasperDesign) throws JRException {
    return getCompiler(jasperDesign).compileReport(jasperDesign);
  }
  
  public static Collection verifyDesign(JasperDesign jasperDesign) {
    return JRVerifier.verifyDesign(jasperDesign);
  }
  
  public static JREvaluator loadEvaluator(JasperReport jasperReport, JRDataset dataset) throws JRException {
    JRCompiler compiler = getCompiler(jasperReport);
    return compiler.loadEvaluator(jasperReport, dataset);
  }
  
  public static JREvaluator loadEvaluator(JasperReport jasperReport, JRCrosstab crosstab) throws JRException {
    JRCompiler compiler = getCompiler(jasperReport);
    return compiler.loadEvaluator(jasperReport, crosstab);
  }
  
  public static JREvaluator loadEvaluator(JasperReport jasperReport) throws JRException {
    return loadEvaluator(jasperReport, jasperReport.getMainDataset());
  }
  
  public static String writeReportToXmlFile(String sourceFileName) throws JRException {
    File sourceFile = new File(sourceFileName);
    JRReport report = (JRReport)JRLoader.loadObject(sourceFile);
    File destFile = new File(sourceFile.getParent(), report.getName() + ".jasper.jrxml");
    String destFileName = destFile.toString();
    writeReportToXmlFile(report, destFileName);
    return destFileName;
  }
  
  public static void writeReportToXmlFile(String sourceFileName, String destFileName) throws JRException {
    JRReport report = (JRReport)JRLoader.loadObject(sourceFileName);
    writeReportToXmlFile(report, destFileName);
  }
  
  public static void writeReportToXmlFile(JRReport report, String destFileName) throws JRException {
    JRXmlWriter.writeReport(report, destFileName, "UTF-8");
  }
  
  public static void writeReportToXmlStream(InputStream inputStream, OutputStream outputStream) throws JRException {
    JRReport report = (JRReport)JRLoader.loadObject(inputStream);
    writeReportToXmlStream(report, outputStream);
  }
  
  public static void writeReportToXmlStream(JRReport report, OutputStream outputStream) throws JRException {
    JRXmlWriter.writeReport(report, outputStream, "UTF-8");
  }
  
  public static String writeReportToXml(JRReport report) {
    return JRXmlWriter.writeReport(report, "UTF-8");
  }
  
  private static JRCompiler getJavaCompiler() {
    JRJdtCompiler jRJdtCompiler;
    JRJdk13Compiler jRJdk13Compiler;
    JRJavacCompiler jRJavacCompiler;
    JRCompiler compiler = null;
    try {
      JRClassLoader.loadClassForRealName("org.eclipse.jdt.internal.compiler.Compiler");
      jRJdtCompiler = new JRJdtCompiler();
    } catch (Exception e) {}
    if (jRJdtCompiler == null)
      try {
        JRClassLoader.loadClassForRealName("com.sun.tools.javac.Main");
        jRJdk13Compiler = new JRJdk13Compiler();
      } catch (Exception e) {} 
    if (jRJdk13Compiler == null)
      jRJavacCompiler = new JRJavacCompiler(); 
    return (JRCompiler)jRJavacCompiler;
  }
  
  private static JRCompiler getCompiler(JasperReport jasperReport) throws JRException {
    JRCompiler compiler = null;
    String compilerClassName = jasperReport.getCompilerClass();
    Class compilerClass = null;
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    if (classLoader != null)
      try {
        compilerClass = classLoader.loadClass(compilerClassName);
      } catch (ClassNotFoundException e) {} 
    if (compilerClass == null) {
      classLoader = JasperCompileManager.class.getClassLoader();
      try {
        if (classLoader == null) {
          compilerClass = Class.forName(compilerClassName);
        } else {
          compilerClass = classLoader.loadClass(compilerClassName);
        } 
      } catch (ClassNotFoundException e) {
        throw new JRException("Report compiler class not found : " + compilerClassName);
      } 
    } 
    try {
      compiler = (JRCompiler)compilerClass.newInstance();
    } catch (Exception e) {
      throw new JRException("Could not instantiate report compiler : " + compilerClassName, e);
    } 
    return compiler;
  }
  
  private static JRCompiler getCompiler(JasperDesign jasperDesign) throws JRException {
    JRCompiler compiler = null;
    String compilerClassName = JRProperties.getProperty("net.sf.jasperreports.compiler.class");
    if (compilerClassName == null || compilerClassName.trim().length() == 0) {
      String language = jasperDesign.getLanguage();
      compilerClassName = JRProperties.getProperty("net.sf.jasperreports.compiler." + language);
      if (compilerClassName == null || compilerClassName.trim().length() == 0) {
        if ("java".equals(language))
          return getJavaCompiler(); 
        throw new JRException("No report compiler set for language : " + language);
      } 
    } 
    try {
      Class clazz = JRClassLoader.loadClassForName(compilerClassName);
      compiler = clazz.newInstance();
    } catch (Exception e) {
      throw new JRException("Could not instantiate report compiler : " + compilerClassName, e);
    } 
    return compiler;
  }
}
