/*
 * IReportCompiler.java
 *
 *  iReport  --  Visual designer for generating JasperReports Documents
 *  Copyright (C) 2002-2003  Giulio Toffoli gt@businesslogic.it
 *
 *  This program is free software; you can redistribute  and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  Giulio Toffoli
 *  Via T.Aspetti, 233
 *  35100 Padova ITALY
 *  gt@businesslogic.it
 *
 *
 * Created on 6 giugno 2003, 0.44
 */

package it.businesslogic.ireport;
import it.businesslogic.ireport.gui.*;
import it.businesslogic.ireport.connection.*;
import it.businesslogic.ireport.util.*;
import java.util.*;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.data.*;
import net.sf.jasperreports.view.*;
import net.sf.jasperreports.engine.export.*;

/**
 * Please note that this class is totally different from the old IReportCompiler.class
 * shipped with iReport 1.
 * @author  Administrator
 */
public class IReportCompiler implements Runnable, JRExportProgressMonitor
{
   
   public static final int CMD_COMPILE  = 0x01;
   public static final int CMD_EXPORT   = 0x02;
   public static final int CMD_COMPILE_SCRIPTLET = 0x04;
   
   public static final String OUTPUT_DIRECTORY     = "OUTPUT_DIRECTORY";
   public static final String OUTPUT_FORMAT        = "OUTPUT_FORMAT";
   public static final String USE_EMPTY_DATASOURCE = "USE_EMPTY_DATASOURCE";
   public static final String USE_CONNECTION = "USE_CONNECTION";
   public static final String CONNECTION = "CONNECTION";   
   public static final String SCRIPTLET_OUTPUT_DIRECTORY = "SCRIPTLET_OUTPUT_DIRECTORY";
   private javax.swing.JList threadList = null;
   
   static PrintStream myPrintStream = null;
   int filledpage=0;
   
   
   private String status="Staring";
   private IReportConnection iReportConnection;
   
   private JReportFrame jrf;
   
   private MainFrame mainFrame;
   
   private int command;
   
   private HashMap properties;
   
   private Thread thread;
   
   private String javaFile = "";
   static private String outputBuffer = "";
      
   /** Creates a new instance of IReportCompiler */
   public IReportCompiler()
   {
      properties = new HashMap();
      command = 0;
   }
   
   /** When an object implementing interface <code>Runnable</code> is used
    * to create a thread, starting the thread causes the object's
    * <code>run</code> method to be called in that separately executing
    * thread.
    * <p>
    * The general contract of the method <code>run</code> is that it may
    * take any action whatsoever.
    *
    * @see     java.lang.Thread#run()
    *
    */
   public void run()
   {
      
      if (threadList != null)
      {
         javax.swing.DefaultListModel dlm = (javax.swing.DefaultListModel)threadList.getModel();
         dlm.addElement(this);
         threadList.updateUI();
      }
         
      boolean compilation_ok = true;
      long start = System.currentTimeMillis();
      // Redirect output stream....
      PrintStream out = System.out;
      PrintStream err = System.err;
      if (myPrintStream == null)
         myPrintStream  =new PrintStream(new FilteredStream(new ByteArrayOutputStream()));
      
      if (out != myPrintStream)
         System.setOut(myPrintStream);
      if (err != myPrintStream)
         System.setErr(myPrintStream);
      
      outputBuffer="";
      
      
	//by Egon - DEBUG: Something is wrong here, please check. ok? thx.
	//1 - Line 148 - srcScriptletFileName = C:\jasperreports-0.5.3\demo\samples\jasper\FirstJasper.jrxmScriptlet.java -> scriptlet filename
	//2 - Line 157 - Misc.nvl( new File(fileName).getParent(), ".") =>  .  -> report directory
      
      // Add an entry in the thread list...
    //by Egon - DEBUG: C:\jasperreports-0.5.3\demo\samples\jasper\FirstJasper.jrxml
      String fileName = jrf.getReport().getFilename();
      
	//by Egon - DEBUG: C:\jasperreports-0.5.3\demo\samples\jasper\FirstJasper.jrxml
      String srcFileName = jrf.getReport().getFilename();
	//by Egon - DEBUG: C:\jasperreports-0.5.3\demo\samples\jasper\FirstJasper.jasper
      fileName = Misc.changeFileExtension(fileName,"jasper");
      
      
      File f = new File(fileName);
      if (properties.get(this.OUTPUT_DIRECTORY) != null)
      {
		//by Egon - DEBUG: .\FirstJasper.jasper
         fileName = (String)properties.get(this.OUTPUT_DIRECTORY) + f.separatorChar + f.getName();
      }
      
	//by Egon - DEBUG: C:\jasperreports-0.5.3\demo\samples\jasper\FirstJasper.jrxml
      String scriptletFileName = jrf.getReport().getFilename();
	//by Egon - DEBUG: C:\jasperreports-0.5.3\demo\samples\jasper\FirstJasper.jrxml
      String srcScriptletFileName = jrf.getReport().getFilename();
	//by Egon - DEBUG: .\FirstJasper.
      //fileName = Misc.changeFileExtension(fileName,"");
	//by Egon - DEBUG: C:\jasperreports-0.5.3\demo\samples\jasper\FirstJasper.jrxmScriptlet.java
      scriptletFileName = srcScriptletFileName.substring(0,scriptletFileName.length()-1)+"Scriptlet.java";
	//1 - by Egon - DEBUG: C:\jasperreports-0.5.3\demo\samples\jasper\FirstJasper.jrxmScriptlet.java
      srcScriptletFileName = scriptletFileName;
      
      File f2 = new File(scriptletFileName);
      if (properties.get(this.SCRIPTLET_OUTPUT_DIRECTORY) != null)
      {
         scriptletFileName = (String)properties.get(this.SCRIPTLET_OUTPUT_DIRECTORY) + f2.separatorChar + f2.getName();
      }
            
      
       String reportDirectory = new File(jrf.getReport().getFilename()).getParent();
       String classpath = System.getProperty("jasper.reports.compile.class.path");
       if(classpath != null){
            classpath += File.pathSeparator + reportDirectory; 
            System.setProperty("jasper.reports.compile.class.path", classpath);
       } else if (System.getProperty("java.class.path") != null){
        classpath = System.getProperty("java.class.path");
        classpath += File.pathSeparator + reportDirectory; 
        System.setProperty("java.class.path", classpath);
        }
       reportDirectory = reportDirectory.replace('\\', '/');
       if(!reportDirectory.endsWith("/")){
            reportDirectory += "/";//the file path separator must be present
       }
       if(!reportDirectory.startsWith("/")){
            reportDirectory = "/" + reportDirectory;//it's important to JVM 1.4.2 especially if contains windows drive letter
       }
       ReportClassLoader reportClassLoader = new ReportClassLoader();
       reportClassLoader.setRelodablePaths( reportDirectory );
       reportClassLoader.rescanLibDirectory();
       
       /******************/
       
       try{
            Thread.currentThread().setContextClassLoader(new URLClassLoader(new URL[]{new URL("file://"+reportDirectory)},  reportClassLoader));
       } catch (MalformedURLException mue){
            mue.printStackTrace();
       }
       /******************/
       
       //.setContextClassLoader(reportClassLoader);
       
       if ((command & CMD_COMPILE_SCRIPTLET) != 0)
      {
         status  ="compiling scriptlet";
         updateThreadList();
         start = System.currentTimeMillis();
      
         // Compile the scriptlet class...
         
         String tempDirStr = System.getProperty("jasper.reports.compile.temp");
         String oldCompileTemp  = tempDirStr;
         if (tempDirStr == null || tempDirStr.length() == 0 || mainFrame.isUsingCurrentFilesDirectoryForCompiles())
         {
            tempDirStr = mainFrame.getTranslatedCompileDirectory();
         }
         File tempDirFile = new File(tempDirStr);
         javaFile = srcScriptletFileName;
         javaFile = (new File(tempDirFile,javaFile)).getPath();
         
         javaFile = jrf.getReport().getScriptletFileName();
         
         mainFrame.logOnConsole("</font><font face=\"SansSerif\" size=\"3\" color=\"#000000\">Compiling file... " + scriptletFileName + " -> "+javaFile+"</font><br><font face=\"Courier New\" size=\"3\">",true);
         
         try
         {
            /*
            if( mainFrame.isUsingCurrentFilesDirectoryForCompiles() )
            {
               System.setProperty("jasper.reports.compile.temp", tempDirStr);
            }
            */
            
            //JasperCompileManager.compileReportToFile(srcFileName, fileName);
            net.sf.jasperreports.engine.design.JRJdk13Compiler compiler = new net.sf.jasperreports.engine.design.JRJdk13Compiler();
            compiler.compileClass( new File(javaFile),   Misc.getClassPath() );
             
         } 
         /*
         catch (Exception jrex)
         {
             
            mainFrame.logOnConsole("</font><font face=\"SansSerif\"  size=\"3\" color=\"#CC0000\"><b>Errors compiling "+scriptletFileName+"!</b></font><br><font face=\"Courier New\" size=\"3\">",true);
            //1. load the java file
            Vector source = new Vector();
            try
            {
               java.io.BufferedReader is = new java.io.BufferedReader(new java.io.FileReader( javaFile ));
               while (true)
               {
                  String line = is.readLine();
                  if (line == null) break;
                  source.addElement(line);
               }
               is.close();
            } catch (Exception ioex)
            {
               // No file readed....
            }
            //2. write exception in a string
            StringWriter sw = new StringWriter(0);
            jrex.printStackTrace(new PrintWriter(sw));
            
            System.out.println("\n\n\n");
            myPrintStream.flush();
            parseException( outputBuffer+sw.getBuffer()+"", source);

         }
         */
         catch (Exception ex)
         {
            mainFrame.logOnConsole("</font><font face=\"SansSerif\"  size=\"3\" color=\"#CC0000\"><b>Error compiling the Scriptlet java source!</b></font><br><font face=\"Courier New\" size=\"3\">",true);
            StringWriter sw = new StringWriter(0);
            ex.printStackTrace(new PrintWriter(sw));
            myPrintStream.flush();
            parseException( outputBuffer+sw.getBuffer()+"", null);
            compilation_ok = false;
         }
         finally
         {
            if(mainFrame.isUsingCurrentFilesDirectoryForCompiles())
            {
                /*
               if( oldCompileTemp != null )
               {
                  System.setProperty("jasper.reports.compile.temp", oldCompileTemp);
               }
               else
               {
                  System.setProperty("jasper.reports.compile.temp", "");
               }
                 */
            }//end if using current files directory for compiles
         }//end finally
         mainFrame.logOnConsole(outputBuffer);
         outputBuffer="";
         mainFrame.logOnConsole("</font><hr><font face=\"SansSerif\"  size=\"3\" color=\"#0000CC\"><b>Compilation running time : " + (System.currentTimeMillis() - start) + "</b></font><br><hr><font face=\"Courier New\" size=\"3\">",true);
       
      }
      
      if (!compilation_ok) {
          
          removeThread();
          return;
      }
      
      if ((command & CMD_COMPILE) != 0)
      {
         status  ="compiling report";
         updateThreadList();
         
         System.setProperty("jasper.reports.compile.keep.java.file", "true");
         //System.setProperty("jasper.reports.compile.temp", "C:\\");
         // Compile report....
         javaFile = this.jrf.getReport().getName()+".java";
         
         String tempDirStr = System.getProperty("jasper.reports.compile.temp");
         String oldCompileTemp  = tempDirStr;
         if (tempDirStr == null || tempDirStr.length() == 0 || mainFrame.isUsingCurrentFilesDirectoryForCompiles())
         {
            tempDirStr = mainFrame.getTranslatedCompileDirectory();
         }
         File tempDirFile = new File(tempDirStr);
         javaFile = (new File(tempDirFile,javaFile)).getPath();
                  
         mainFrame.logOnConsole("</font><font face=\"SansSerif\" size=\"3\" color=\"#000000\">Compiling to file... " + fileName + " -> "+javaFile+"</font><br><font face=\"Courier New\" size=\"3\">",true);
         
         try
         {
            if( mainFrame.isUsingCurrentFilesDirectoryForCompiles() )
            {
               System.setProperty("jasper.reports.compile.temp", tempDirStr);
            }
            

            String old_jr_classpath = Misc.nvl( System.getProperty("jasper.reports.compile.class.path"), "");
            System.setProperty("jasper.reports.compile.class.path", Misc.nvl( new File(fileName).getParent(), ".")  + File.pathSeparator  + System.getProperty("java.class.path") + File.pathSeparator +  System.getProperty("java.class.path"));
                       
            JasperCompileManager.compileReportToFile(srcFileName, fileName);
            
            System.setProperty("jasper.reports.compile.class.path", old_jr_classpath);
         } catch (JRException jrex)
         {
             compilation_ok = false;
            mainFrame.logOnConsole("</font><font face=\"SansSerif\"  size=\"3\" color=\"#CC0000\"><b>Errors compiling "+fileName+"!</b></font><br><font face=\"Courier New\" size=\"3\">",true);
            //1. load the java file
            Vector source = new Vector();
            try
            {
               java.io.BufferedReader is = new java.io.BufferedReader(new java.io.FileReader( javaFile ));
               while (true)
               {
                  String line = is.readLine();
                  if (line == null) break;
                  source.addElement(line);
               }
               is.close();
               
            } catch (Exception ioex)
            {
               // No file readed....
            }
            //2. write exception in a string
            StringWriter sw = new StringWriter(0);
            jrex.printStackTrace(new PrintWriter(sw));
            
            System.out.println("\n\n\n");
            myPrintStream.flush();
            parseException( outputBuffer+sw.getBuffer()+"", source);
            
            
            
         }
         catch (Exception ex)
         {
            mainFrame.logOnConsole("</font><font face=\"SansSerif\"  size=\"3\" color=\"#CC0000\"><b>Error compiling the report java source!</b></font><br><font face=\"Courier New\" size=\"3\">",true);
            StringWriter sw = new StringWriter(0);
            ex.printStackTrace(new PrintWriter(sw));
            myPrintStream.flush();
            parseException( outputBuffer+sw.getBuffer()+"", null);
            compilation_ok = false;
         }
         finally
         {
            if(mainFrame.isUsingCurrentFilesDirectoryForCompiles())
            {
               if( oldCompileTemp != null )
               {
                  System.setProperty("jasper.reports.compile.temp", oldCompileTemp);
               }
               else
               {
                  System.setProperty("jasper.reports.compile.temp", "");
               }
            }//end if using current files directory for compiles
         }//end finally
         mainFrame.logOnConsole(outputBuffer);
         outputBuffer="";
         mainFrame.logOnConsole("</font><hr><font face=\"SansSerif\"  size=\"3\" color=\"#0000CC\"><b>Compilation running time : " + (System.currentTimeMillis() - start) + "</b></font><br><hr><font face=\"Courier New\" size=\"3\">",true);
         
      }
      
     
      if (!compilation_ok) {
          
          removeThread();
          return;
      }
            
      if  ((command & CMD_EXPORT) != 0)
      {
         status  ="generating report";
         updateThreadList();
          
         // Compile report....
         JasperPrint print = null;
         
         mainFrame.logOnConsole("</font><font face=\"SansSerif\" size=\"3\" color=\"#000000\">Filling report... </font><br><font face=\"Courier New\" size=\"3\">",true);
         
         if (properties.get(USE_EMPTY_DATASOURCE) != null && properties.get(USE_EMPTY_DATASOURCE).equals("true"))
         {
            try
            {
               
               print = JasperFillManager.fillReport(fileName,new HashMap(),new JREmptyDataSource());
            } catch (Exception ex)
            {
               mainFrame.logOnConsole("Error filling print...\n");
               ex.printStackTrace();
               mainFrame.logOnConsole(outputBuffer);
               outputBuffer ="";
            }
         }
         else if (properties.get(USE_CONNECTION) != null && properties.get(USE_CONNECTION).equals("true"))
         {
            try
            {
               
               IReportConnection connection = (IReportConnection)properties.get(CONNECTION);
               HashMap hm = new HashMap();
               if (connection.isJDBCConnection())
               {
                  print = JasperFillManager.fillReport(fileName,hm, connection.getConnection());
               }
               else
               {
                   JRDataSource ds = (JRDataSource)connection.getJRDataSource();
                   print = JasperFillManager.fillReport(fileName,hm,ds);
               
               }
               
            } catch (Exception ex)
            {
               mainFrame.logOnConsole("Error filling print...\n");
               ex.printStackTrace();
               mainFrame.logOnConsole(outputBuffer);
               outputBuffer ="";
            }
         }
         net.sf.jasperreports.view.JRViewer jrv = null;
         net.sf.jasperreports.engine.JRExporter exporter=null;
         if (print != null)
         {
             status  ="exporting report";
            updateThreadList();
             
            String  format = Misc.nvl(properties.get(OUTPUT_FORMAT),"pdf");
            String  viewer_program = "";
            
            mainFrame.logOnConsole(properties.get(OUTPUT_FORMAT) + "Exporting\n");
            
            try
            {
               
               if (format.equalsIgnoreCase("pdf"))
               {
                  exporter = new  net.sf.jasperreports.engine.export.JRPdfExporter();
                  
                  fileName = Misc.changeFileExtension(fileName,"pdf");
                  mainFrame.logOnConsole("Exporting pdf to file... \""+fileName+"\"\n");
                  viewer_program = mainFrame.getProperties().getProperty("ExternalPDFViewer");
               }
               else if (format.equalsIgnoreCase("csv"))
               {
                  exporter = new  net.sf.jasperreports.engine.export.JRCsvExporter();
                  fileName = Misc.changeFileExtension(fileName,"csv");
                  mainFrame.logOnConsole("Exporting CSV to file... "+fileName+"\n");
                  viewer_program = Misc.nvl( mainFrame.getProperties().getProperty("ExternalCSVViewer"), "");
               }
               else if (format.equalsIgnoreCase("html"))
               {
                  exporter = new  net.sf.jasperreports.engine.export.JRHtmlExporter();
                  fileName = Misc.changeFileExtension(fileName,"html");
                  mainFrame.logOnConsole("Exporting HTML to file... "+fileName+"\n");
                  viewer_program = Misc.nvl( mainFrame.getProperties().getProperty("ExternalHTMLViewer"), "");
               }
               else if (format.equalsIgnoreCase("xls"))
               {
                  exporter = new  net.sf.jasperreports.engine.export.JRXlsExporter();
                  fileName = Misc.changeFileExtension(fileName,"xls");
                  mainFrame.logOnConsole("Exporting xls to file... "+fileName+"\n");
                  viewer_program = Misc.nvl( mainFrame.getProperties().getProperty("ExternalXLSViewer"), "");
               }
               else if (format.equalsIgnoreCase("java2D"))
               {
                  
                  exporter = new  net.sf.jasperreports.engine.export.JRGraphics2DExporter();
                  mainFrame.logOnConsole("Exporting to Java2D \n");
                  viewer_program = null;
               }
               else if (format.equalsIgnoreCase("jrviewer"))
               {
                  mainFrame.logOnConsole("Viewing with JasperReports Viewer\n");
                  exporter = null;
                  viewer_program = null;
                  
               }
               else if (format.equalsIgnoreCase("txt"))
               {
                  exporter = new  it.businesslogic.ireport.export.JRTxtExporter();
                  fileName = Misc.changeFileExtension(fileName,"txt");
                  mainFrame.logOnConsole("Exporting txt (experimental) to file... "+fileName+"\n");
                  viewer_program = Misc.nvl( mainFrame.getProperties().getProperty("ExternalEditor"), "");
               }
               
               if (exporter != null)
               {
                  exporter.setParameter(JRExporterParameter.OUTPUT_FILE_NAME,fileName);
                  exporter.setParameter(JRExporterParameter.JASPER_PRINT,print);
                  exporter.setParameter(JRExporterParameter.PROGRESS_MONITOR, this);
                  exporter.exportReport();
               }
               else if (format.equalsIgnoreCase("jrviewer"))
               {
                  //jrv = new net.sf.jasperreports.view.JRViewer(print);
                  JasperViewer jasperViewer =
                  new JasperViewer(print,false);
                  jasperViewer.setTitle("iReport JasperViewer");
                  // Find JRViewer...
                    /*
                    javax.swing.JComponent button = searchButton( (javax.swing.JComponent)jasperViewer.getRootPane() , "Print");
                    if (button != null) ((javax.swing.JButton)button).setText("Ciccio");
                    button = searchButton( (javax.swing.JComponent)jasperViewer.getRootPane() , "Reload");
                    if (button != null) ((javax.swing.JButton)button).setText("Ricarica");
                     */
                  jasperViewer.show();
                  
                  //net.sf.jasperreports.view.JasperViewer.viewReport( print, false);
               }
            } catch (Exception ex2)
            {
               
               
               mainFrame.logOnConsole("Error exporting print...\n");
               ex2.printStackTrace();
               mainFrame.logOnConsole(outputBuffer);
               outputBuffer ="";
               
            }
            mainFrame.logOnConsole("Running time : " + (System.currentTimeMillis() - start)+"\n");
            
            // Export using the rigth program....
            
            Runtime rt = Runtime.getRuntime();
            if (viewer_program == null || viewer_program.equals(""))
            {
               
               if (format.equalsIgnoreCase("jrviewer"))
               {
                  
               }
               else
                  mainFrame.logOnConsole("No external viewer specified for this type of print. Set it in the options frame!\n");
               
            }
            else
            {
               try
               {
                  String execute_string = viewer_program + " "+fileName+"";
                  mainFrame.logOnConsole("Executing: "+ execute_string + "\n");
                  rt.exec( execute_string );
               } catch (Exception ex)
               {
                  
                  mainFrame.logOnConsole("Error viewing report...\n");
                  ex.printStackTrace();
                  mainFrame.logOnConsole(outputBuffer+"\n");
                  outputBuffer ="";
               }
               mainFrame.logOnConsole("Finished...\n");
            }
         }
         else
         {
            mainFrame.logOnConsole("Print not filled. Try to use an EmptyDataSource...!\n");
         }
      }
      
      removeThread();
      //System.setOut(out);
      //System.setErr(err);
   }
   
   
   public void removeThread()
   {
       if (threadList != null)
      {
         javax.swing.DefaultListModel dlm = (javax.swing.DefaultListModel)threadList.getModel();
         dlm.removeElement(this);
         threadList.updateUI();
      }
       
   }
   /** Getter for property command.
    * @return Value of property command.
    *
    */
   public int getCommand()
   {
      return command;
   }
   
   /** Setter for property command.
    * @param command New value of property command.
    *
    */
   public void setCommand(int command)
   {
      this.command = command;
   }
   
   /** Getter for property iReportConnection.
    * @return Value of property iReportConnection.
    *
    */
   public it.businesslogic.ireport.IReportConnection getIReportConnection()
   {
      return iReportConnection;
   }
   
   /** Setter for property iReportConnection.
    * @param iReportConnection New value of property iReportConnection.
    *
    */
   public void setIReportConnection(it.businesslogic.ireport.IReportConnection iReportConnection)
   {
      this.iReportConnection = iReportConnection;
   }
   
   /** Getter for property jrf.
    * @return Value of property jrf.
    *
    */
   public JReportFrame getJrf()
   {
      return jrf;
   }
   
   /** Setter for property jrf.
    * @param jrf New value of property jrf.
    *
    */
   public void setJrf(JReportFrame jrf)
   {
      this.jrf = jrf;
   }
   
   /** Getter for property mainFrame.
    * @return Value of property mainFrame.
    *
    */
   public MainFrame getMainFrame()
   {
      return mainFrame;
   }
   
   /** Setter for property mainFrame.
    * @param mainFrame New value of property mainFrame.
    *
    */
   public void setMainFrame(MainFrame mainFrame)
   {
      this.mainFrame = mainFrame;
   }
   
   /** Getter for property properties.
    * @return Value of property properties.
    *
    */
   public HashMap getProperties()
   {
      return properties;
   }
   
   /** Setter for property properties.
    * @param properties New value of property properties.
    *
    */
   public void setProperties(HashMap properties)
   {
      this.properties = properties;
   }
   
   public String toString()
   {
      return status;
   }
   
   class FilteredStream extends FilterOutputStream
   {
      public FilteredStream(OutputStream aStream)
      {
         super(aStream);
      }
      
      public void write(byte b[]) throws IOException
      {
         String aString = new String(b);
         outputBuffer += aString;
      }
      
      public void write(byte b[], int off, int len) throws IOException
      {
         String aString = new String(b , off , len);
         outputBuffer += aString;
         
         //mainFrame.logOnConsole(aString);
      }
   }
   
   public void start()
   {
      this.thread = new Thread(this);
      
	//using the report directory to load classes and resources
	try{
		  String reportDirectory = new File(jrf.getReport().getFilename()).getParent();
      
		  //set classpath
		  String classpath = System.getProperty("jasper.reports.compile.class.path");
		  if(classpath != null){
			
			  classpath += File.pathSeparator + reportDirectory; 
			  System.setProperty("jasper.reports.compile.class.path", classpath);
			
		  }else if(System.getProperty("java.class.path") != null){
			
			  classpath = System.getProperty("java.class.path");
			  classpath += File.pathSeparator + reportDirectory; 
			  System.setProperty("java.class.path", classpath);
		  }

		  //include report directory for resource search path
		  reportDirectory = reportDirectory.replace('\\', '/');
		  if(!reportDirectory.endsWith("/")){
			  reportDirectory += "/";//the file path separator must be present
		  }
		  if(!reportDirectory.startsWith("/")){
			  reportDirectory = "/" + reportDirectory;//it's important to JVM 1.4.2 especially if contains windows drive letter
		  }
		  thread.setContextClassLoader(new URLClassLoader(new URL[]{
			  new URL("file://"+reportDirectory)
		  }));
  
	}catch(MalformedURLException mue){
	  mue.printStackTrace();
	}
      
      this.thread.start();
   }
   
   public void parseException(String exception, Vector sourceLines)
   {
      
      // Create a single outString...
      String outString = "";
      
      // For each row, looking for a file name followed by a row number...
      //javax.swing.JOptionPane.showMessageDialog(null,exception);
      StringTokenizer st = new StringTokenizer(exception, "\n");
      while (st.hasMoreElements())
      {
         
         String line = st.nextToken();
         if (line.startsWith(this.javaFile))
         {
            // The next line is an expression error....
            //mainFrame.logOnConsole(line+"\n");
            outString += Misc.toHTML(line+"\n");
            String lineNumber = line.substring( this.javaFile.length()+1);
            lineNumber = lineNumber.substring(0, lineNumber.indexOf(':'));
            int ln = Integer.parseInt(lineNumber);
            if (ln >= 3) ln -=3;
            
            // Take the element name....
            
            String reference = "";
            if (sourceLines.size() >= ln)
            {
               
               String lineCode = (String)sourceLines.elementAt(ln);
               //mainFrame.logOnConsole( "Line: " + ln + "> " + lineCode+"\n");
               if (lineCode.indexOf("            case") == 0 &&
               lineCode.indexOf(" : // ") >0)
               {
                  // We have found the comment where jasperReport puts the expression ref.
                  reference = lineCode.substring(lineCode.indexOf(" : // ")+6).trim();
               }
            }
            
            if (st.hasMoreElements())
            {
               try
               {
                  String error_line = st.nextToken();
                  if (error_line.startsWith("found"))
                  {
                     //mainFrame.logOnConsole( error_line+"\n");
                     outString += Misc.toHTML(error_line+"\n");
                     error_line = st.nextToken();
                  }
                  if (error_line.startsWith("required"))
                  {
                     //mainFrame.logOnConsole( error_line+"\n");
                     outString += Misc.toHTML(error_line+"\n");
                     error_line = st.nextToken();
                  }
                  if (error_line.startsWith("symbol"))
                  {
                     //mainFrame.logOnConsole( error_line+"\n");
                     outString += Misc.toHTML(error_line+"\n");
                     error_line = st.nextToken();
                  }
                  if (error_line.startsWith("location"))
                  {
                     //mainFrame.logOnConsole( error_line+"\n");
                     outString += Misc.toHTML(error_line+"\n");
                     error_line = st.nextToken();
                  }
                  
                  // Find the link....
                  // Count space at begin of line...
                  String html = "";
                  for (int i=0; i<error_line.length(); ++i)
                  {
                     if (error_line.charAt(i) == ' ')
                     {
                        html += "&nbsp;";
                     }
                     else break;
                  }
                  error_line = error_line.trim();
                  html += "<a href=\"http://error:"+ jrf.getWindowID()+ "/"+reference+"\">"+Misc.toHTML(error_line)+"</a><br>";
                  //mainFrame.logOnConsole( html,true);
                  outString += html;
               } catch (Exception ex)
               {
                  //mainFrame.logOnConsole( "Error parsing\n!");
                  outString += Misc.toHTML("Error parsing\n!");
               }
            }
         }
         else if (line.startsWith("Warning :") && line.indexOf("y=")>0 && line.indexOf("height=")>0 && line.indexOf("band-height=")>0)
         {
            //mainFrame.logOnConsole("<a href=\"http://warning\">"+Misc.toHTML(line)+"</a><br>",true);
            outString += "<a href=\"http://warning:"+ jrf.getWindowID() +"\">"+Misc.toHTML(line)+"</a><br>";
         }
         else
         {
            //mainFrame.logOnConsole(line+"\n");
            outString += Misc.toHTML(line+"\n");
         }
      }
      mainFrame.logOnConsole(outString,true);
      //mainFrame.logOnConsole( "<a href=\"http://problem\">*****<hr><font face=\"Courier New\" size=\"3\">"+ exception +"</a>", true);
      outputBuffer = "";
   }
   
   public javax.swing.JComponent searchButton(javax.swing.JComponent root, String text)
   {
      if (root instanceof javax.swing.JButton && ((javax.swing.JButton)root).getText()!=null && ((javax.swing.JButton)root).getText().equals(text) ) return root;
      for (int i=0; i<root.getComponentCount(); ++i)
      {
         
         if (root.getComponent(i) instanceof javax.swing.JComponent)
         {
            mainFrame.logOnConsole(""+ ((javax.swing.JComponent)root.getComponent(i)) +"\n");
            javax.swing.JComponent res = searchButton((javax.swing.JComponent)root.getComponent(i),  text);
            if (res != null) return res;
         }
      }
      return null;
   }
   
   public void afterPageExport() {
       
       filledpage++;
       /*
       if (filledpage != 1 && (filledpage % 10 != 0)) return;
       javax.swing.text.Document doc = mainFrame.getLogDocument();
       try {
       String doc_str = doc.getText(0, doc.getLength() );
       int index = doc_str.lastIndexOf("Exported page ");
       if (index <=0 )
       {
        mainFrame.logOnConsole("</font><font face=\"SansSerif\" size=\"3\" color=\"#000000\">Exported page " + filledpage +"</font><br><font face=\"Courier New\" size=\"3\">",true);
       }
       else
       {
          String str_old = "Exported page " + (filledpage-10);
          doc.remove(index, str_old.length());
          doc.insertString(0, "Exported page " + filledpage, null);
       }
       } catch (Exception ex) {}
       */
   }

    public javax.swing.JList getThreadList() {
        return threadList;
    }

    public void setThreadList(javax.swing.JList threadList) {
        this.threadList = threadList;
    }
    
    public void updateThreadList()
    {
        try {
         if (threadList != null) javax.swing.SwingUtilities.invokeAndWait( 
            new java.lang.Runnable() { 
                    public void run() { 
                            threadList.updateUI(); 
                    }
            } );
         } catch (Exception ex) {}
    }
    
}

