/*
 * 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 dori.jasper.engine.*;
import dori.jasper.engine.data.*;
import dori.jasper.view.*;

/**
 * Please note that this class is totally different from the old IReportCompiler.class
 * shipped with iReport 1.
 * @author  Administrator
 */
public class IReportCompiler implements Runnable {
    
    public static final int CMD_COMPILE  = 0x01;
    public static final int CMD_EXPORT   = 0x02;
    
    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";
    static PrintStream myPrintStream = null;
    
    
    private String status="";
    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() {
        
        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="";
        
        // Add an entry in the thread list...
        String fileName = jrf.getReport().getFilename();
            
        String srcFileName = jrf.getReport().getFilename();
	fileName = fileName.substring(0,fileName.length()-3)+"jasper";
        File f = new File(fileName);
        if (properties.get(this.OUTPUT_DIRECTORY) != null)
	{
            fileName = (String)properties.get(this.OUTPUT_DIRECTORY) + f.separatorChar + f.getName();  
        }
            
        if ((command & CMD_COMPILE) != 0)
        {
            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");
            if (tempDirStr == null || tempDirStr.length() == 0)
	    {
		tempDirStr = System.getProperty("user.dir");
	    }
            File tempDirFile = new File(tempDirStr);
            javaFile = (new File(tempDirFile,javaFile)).getPath();
            
            status = "Compiling";
	    
            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 {
            JasperCompileManager.compileReportToFile(srcFileName, fileName);

            } catch (JRException jrex)
            {
                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);
            }
            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  ((command & CMD_EXPORT) != 0)
        {
            // Compile report....
            JasperPrint print = null;
            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 instanceof JDBCConnection)
                    {
                        print = JasperFillManager.fillReport(fileName,hm, connection.getConnection()); 
                    }
                    else if (connection instanceof JRCustomDataSourceConnection)
                    {
                        JRCustomDataSourceConnection cds = (JRCustomDataSourceConnection)connection;
                        Object obj = Class.forName( cds.getFactoryClass() ).newInstance(); 
                        java.lang.reflect.Method m =  obj.getClass().getMethod( cds.getMethodToCall() , new Class[0] );
                        JRDataSource ds = (JRDataSource)m.invoke(obj, new Class[0]);                          
                        print = JasperFillManager.fillReport(fileName,hm,ds);                    
                    }
                    
                } catch (Exception ex){
                    mainFrame.logOnConsole("Error filling print...\n");
                    ex.printStackTrace();
                    mainFrame.logOnConsole(outputBuffer);
                    outputBuffer ="";
                }
            }
            dori.jasper.view.JRViewer jrv = null;
            dori.jasper.engine.JRExporter exporter=null;
            if (print != null)
            {
                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  dori.jasper.engine.export.JRPdfExporter();
			fileName = fileName.substring(0,fileName.length()-6)+"pdf";
			mainFrame.logOnConsole("Exporting pdf to file... \""+fileName+"\"\n");
                        viewer_program = mainFrame.getProperties().getProperty("ExternalPDFViewer");
		}
                else if (format.equalsIgnoreCase("csv"))
		{
			exporter = new  dori.jasper.engine.export.JRCsvExporter();
			fileName = fileName.substring(0,fileName.length()-6)+"csv";
			mainFrame.logOnConsole("Exporting CSV to file... "+fileName+"\n");
                        viewer_program = Misc.nvl( mainFrame.getProperties().getProperty("ExternalCSVViewer"), "");
		}
		else if (format.equalsIgnoreCase("html"))
		{
			exporter = new  dori.jasper.engine.export.JRHtmlExporter();
			fileName = fileName.substring(0,fileName.length()-6)+"html";
			mainFrame.logOnConsole("Exporting HTML to file... "+fileName+"\n");
                        viewer_program = Misc.nvl( mainFrame.getProperties().getProperty("ExternalHTMLViewer"), "");
                }
		else if (format.equalsIgnoreCase("xls"))
		{
			exporter = new  dori.jasper.engine.export.JRXlsExporter();
			fileName = fileName.substring(0,fileName.length()-6)+"xls";
			mainFrame.logOnConsole("Exporting xls to file... "+fileName+"\n");
                        viewer_program = Misc.nvl( mainFrame.getProperties().getProperty("ExternalXLSViewer"), "");
		}	
                else if (format.equalsIgnoreCase("java2D"))
		{
                    
			exporter = new  dori.jasper.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;
                        
		}
                
                if (exporter != null)
                {
                    exporter.setParameter(JRExporterParameter.OUTPUT_FILE_NAME,fileName);
                    exporter.setParameter(JRExporterParameter.JASPER_PRINT,print);   
                    exporter.exportReport();                
                }
                else if (format.equalsIgnoreCase("jrviewer"))
                {
                    //jrv = new dori.jasper.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();
                    
                    //dori.jasper.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");
            }
        }
        
        //System.setOut(out);
        //System.setErr(err);
    }
    
    /** 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);
        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;
    }
}

