/*
 * Copyright 
 *   2008 axYus - www.axyus.com
 *   2008 jp.tessier - jean-philippe.tessier@axyus.com
 * 
 * This file is part of XEMELIOS.
 * 
 * XEMELIOS is free software; you can redistribute it 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.
 * 
 * XEMELIOS 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 XEMELIOS; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package fr.gouv.finances.cp.xemelios.plugin.generatorEdmn;

import fr.gouv.finances.cp.utils.xml.marshal.CharacterEscaper;
import fr.gouv.finances.cp.utils.xml.marshal.escapers.DefaultCharacterEscaper;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.zip.Adler32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;

import org.apache.log4j.Logger;
import org.jdesktop.swingworker.SwingWorker;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.DefaultHandler;

import fr.gouv.finances.dgfip.xemelios.common.FileInfo;
import fr.gouv.finances.dgfip.xemelios.common.PJRef;
import fr.gouv.finances.dgfip.xemelios.common.config.DocumentModel;
import fr.gouv.finances.dgfip.xemelios.importers.EtatImporteur;
import fr.gouv.finances.cp.xemelios.ui.MainWindow;
import fr.gouv.finances.dgfip.xemelios.common.config.Loader;
import fr.gouv.finances.dgfip.xemelios.data.impl.pool.PoolManager;
import fr.gouv.finances.dgfip.xemelios.importers.XemeliosArchiveImporter;
import fr.gouv.finances.dgfip.xemelios.utils.XmlUtils;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileFilter;

/**
 * Classe a surcharger pour creer des importeurs 
 * @author chm
 */
public class EdmnImporteurWorker extends SwingWorker<String, String> {

    private static Logger logger = Logger.getLogger(EdmnImporteurWorker.class);
    private static final boolean DEBUG = false;

    public static final int MAX_SIZE_FILE = 5000;
    protected File[] filesToTreat;
    protected Exception inProcessException = null;
    protected long start;
    public final int MSG_TYPE_INFORMATION = 1;
    public final int MSG_TYPE_ERROR = 2;
    public static String TABLE_INDEX = "EDMN_INDEX_NUM_LIASSE";
    
    public static String TABLE_BUDGETS = "EDMN_BUDGS";
    public static String TABLE_ORDOS = "EDMN_ORDOS";
    public static String TABLE_COMPTABLES = "EDMN_COMPTAS";
    public static String TABLE_MINISTERES = "EDMN_MINISTERES";

    public static final transient String ENCODING = "ISO-8859-1";
    
    public static final String EDMN_NS_URI = "http://projets.admisource.gouv.fr/xemelios/namespaces#edmn";
    private ProgressFrame progress;
    private int progressShowing = 0;
    private String fireName = "";
    private Object fireValue;
    private File dirEDMN=null;
    private File budgets=null, ordos=null, comptables=null, output=null;
    private ArrayList<File> generatedFiles;
    /** Taille du buffer pour les lectures/écritures */
	private static final int BUFFER_SIZE = 8 * 1024;

    private DlgGenEdmn dlg;

    private Connection con = null;

    CharacterEscaper escaper = null;
	
    public EdmnImporteurWorker(Connection con,File budgets, File ordos, File comptables,File output,DlgGenEdmn dlg) {
        super();
        this.con=con;
        this.budgets=budgets;
        this.ordos=ordos;
        this.comptables=comptables;
        this.output=output;
        this.dlg=dlg;
        this.escaper = new DefaultCharacterEscaper();
    }

    @Override
    public String doInBackground() {
        FileInfo fileInfo = new FileInfo();
        start = System.currentTimeMillis();
        this.getProgressDlg().displayProgress();
        
        
     	filesToTreat[2]=budgets;
     	filesToTreat[3]=ordos;
     	filesToTreat[4]=comptables;
        //saveNomenclatures(filesToTreat);
        
        try {
            try {
                File f = filesToTreat[1];
                final String fName = f.getName();

                // Sauvegarde de l'index en base
                fireProperty("FILE_NAME", fName);
                fireProperty("initialize", getProgressDlg().nbLines[1]);
                saveIndex(f, getProgressDlg().nbLines[1]);
                fireProperty("currentTerminated", null);
            } catch (Exception ex) {
                inProcessException = ex;
                ex.printStackTrace();
            }
            try {
                File f = filesToTreat[2];
                final String fName = f.getName();

                // Sauvegarde des budgets en base
                fireProperty("FILE_NAME", fName);
                fireProperty("initialize", getProgressDlg().nbLines[2]);
                saveBudgets(f, getProgressDlg().nbLines[2]);
                fireProperty("currentTerminated", null);
            } catch (Exception ex) {
                inProcessException = ex;
                ex.printStackTrace();
            }
            try {
                File f = filesToTreat[3];
                final String fName = f.getName();

                // Sauvegarde des ordos en base
                fireProperty("FILE_NAME", fName);
                fireProperty("initialize", getProgressDlg().nbLines[3]);
                saveOrdos(f, getProgressDlg().nbLines[3]);
                fireProperty("currentTerminated", null);
            } catch (Exception ex) {
                inProcessException = ex;
                ex.printStackTrace();
            }
            try {
                File f = filesToTreat[4];
                final String fName = f.getName();

                // Sauvegarde des comptables en base
                fireProperty("FILE_NAME", fName);
                fireProperty("initialize", getProgressDlg().nbLines[4]);
                saveComptas(f, getProgressDlg().nbLines[4]);
                fireProperty("currentTerminated", null);
            } catch (Exception ex) {
                inProcessException = ex;
                ex.printStackTrace();
            }
            generatedFiles = new ArrayList<File>();
            try {
                File f = filesToTreat[0];
                final String fName = f.getName();

                // Création du fichier EDMN
                fireProperty("FILE_NAME", fName);
                fireProperty("initialize", getProgressDlg().nbLines[0]);
                importFile(f, getProgressDlg().nbLines[0]);
                fireProperty("currentTerminated", null);
            } catch (Exception ex) {
                inProcessException = ex;
                ex.printStackTrace();
            }
        } catch (Exception ex) {
            inProcessException = ex;
            ex.printStackTrace();
        } finally {
            if(con!=null) {
                try {
                    PoolManager.getInstance().releaseConnection(con);
                } catch(Exception sqlEx) {
                    // nothing to do
                }
            }
        }
        StringBuffer msg = new StringBuffer();
        if (!isCancelled()) {
            long ms = (System.currentTimeMillis() - start);
            int s = Integer.parseInt(String.valueOf(ms / 1000));
            int m = Integer.parseInt(String.valueOf(s / 60));
            int h = Integer.parseInt(String.valueOf(m / 60));


            StringBuffer sb = new StringBuffer("La génération a duré : ");
            if (Integer.parseInt(String.valueOf(h)) != 0) {
                sb.append(h + "h ");
            }
            if (Integer.parseInt(String.valueOf(m)) != 0) {
                sb.append((h != 0 ? " et " : "") + (m - (h * 60)) + "mins ");
            }
            if (Integer.parseInt(String.valueOf(s)) != 0) {
                sb.append(((h != 0 || m != 0) ? " et " : "") + (s - (m * 60)) + "s ");
            }
            if (Integer.parseInt(String.valueOf(ms)) != 0) {
                sb.append(((h != 0 || m != 0 || s != 0) ? " et " : "") + (ms - (s * 1000)) + "ms ");
            }

            msg.append("La génération du fichier est terminé.\n"/* + sb.toString()*/);
            if (false/*fileInfo.getGlobalCount() == 0*/) {
                msg.append("Pas de données générées.");
            } else {
                try {
                    msg.append(fileInfo.toString(Loader.getDocumentsInfos(null)));
                } catch(Exception ex) {
                    // on ignore tout
                }
                msg.append("");
            }
        } else {
            msg.append("La génération du fichier EDMN a été interrompue.");
        }
        logger.info("\n" + msg);
        return msg.toString();
    }

    private void fireProperty(String name, Object value) {
        fireName = name;
        fireValue = value;
        try {
            if (SwingUtilities.isEventDispatchThread()) {
                firePropertyChange(name, null, value);
            } else {
                SwingUtilities.invokeAndWait(new Runnable() {

                    public void run() {
                        firePropertyChange(fireName, null, fireValue);
                    }
                });
            }
        } catch (Throwable t) {
            logger.fatal("in fire:", t);
        }
    }

    @Override
    protected void done() {
        super.done();
        if (inProcessException != null) {
            getProgressDlg().displayException(inProcessException);
        }
        String msg = "";
        try {
            msg = get();
        } catch (InterruptedException iEx) {
            iEx.printStackTrace();
        } catch (ExecutionException eEx) {
            eEx.printStackTrace();
        } catch (CancellationException cEx) {
            msg = "Génération annulée";
        }
        if(inProcessException==null) {
            //importEdmnFile();
            if(generateArchive()) {
                if(!DEBUG)
                    cleanTempFile();
            }
            JOptionPane.showMessageDialog(dlg, "Génération correctement terminée.");
            dlg.enableGenerateButton();
        } else {
            getProgressDlg().displayMessage(msg, MSG_TYPE_INFORMATION);
        }
        getProgressDlg().hide();
    }

    public void setFilesToTreat(File[] fichiers) throws Exception {
        filesToTreat = fichiers;
    }


    public ProgressFrame getProgressDlg() {
        return progress;
    }

    public void setProgressDlg(ProgressFrame prog) {
        this.progress = prog;
    }
    
    protected void saveIndex(File index, int nbLignes) throws Exception {
        BufferedReader br;
        String line;
        PreparedStatement ps = null;
        StringBuffer sb = new StringBuffer();
        File fSQL = new File(System.getProperty("user.home"), "insert_index.txt");
        FileWriter fw = new FileWriter(fSQL);
        progressShowing = (int) nbLignes / 500;

        try {

            br = new BufferedReader(new FileReader(index));
            line = br.readLine();

            int i = 0;
            int total = 0;
            Long tempsTotalTraitement = Long.parseLong("0");
            Date datedeb = new Date();
            while (line != null) {
                i++;
                total++;
                if (line.length() > 15) {
                    // Dernière ligne?
                    if (total == nbLignes) {
                        sb.append(line.substring(0, 2) + "," + line.substring(2, 3) + "," + line.substring(3, 9) + "," + line.substring(9, 12) + "," + line.substring(17, 21) + "," + line.substring(21, 24) + "," + line.substring(24, 26) + "," + line.substring(31, 37));
                    } else {
                        sb.append(line.substring(0, 2) + "," + line.substring(2, 3) + "," + line.substring(3, 9) + "," + line.substring(9, 12) + "," + line.substring(17, 21) + "," + line.substring(21, 24) + "," + line.substring(24, 26) + "," + line.substring(31, 37) + "\n");
                    }
                }
                if (i == progressShowing) {
                    fireProperty("progress", i);
                    i = 0;
                }
                line = br.readLine();
            }
            if (i != 0) {
                fireProperty("progress", i);
            }
            i = 0;
            fw.write(sb.toString());
            fw.flush();
            fw.close();
            // Insertion en base des valeurs
            ps = con.prepareStatement("LOAD DATA LOCAL INFILE '" + fSQL.getAbsolutePath().replaceAll("\\\\", "\\\\\\\\") + "' INTO TABLE " + TABLE_INDEX + " FIELDS TERMINATED BY ','");
            ps.execute();
            fSQL.delete();

            // Calcul de temps de traitement
            Date datefin = new Date();
            tempsTotalTraitement += (datefin.getTime() - datedeb.getTime());
            int minutes = Integer.parseInt(Long.toString(tempsTotalTraitement / (60 * 1000)));
            int secondes = Integer.parseInt(Long.toString(tempsTotalTraitement / (1000)));
            int millis = Integer.parseInt(Long.toString(tempsTotalTraitement));

            logger.info("Temps d'insertion de l'index = " + ((minutes != 0) ? minutes + "mins et " : "") + ((secondes) - (minutes * 60)) + "s et " + ((millis) - (secondes * 1000)) + "ms");

        } catch (IOException e) {
            if (e.getClass().equals(FileNotFoundException.class)) {
                logger.debug("Le fichier d'index n'a pas été trouvé !", e.getCause());
            } else {
                logger.debug("IOException sur le fichier " + index.getAbsolutePath() + " !", e.getCause());
            }
        } catch (SQLException e) {
            throw e;
        } finally {
            if (ps != null) {
                try {
                    ps.close();
                } catch (Throwable t) {
                }
            }
        }
    }

    protected void saveBudgets(File budgets, int nbLignes) throws Exception {
        BufferedReader br;
        String line;
        PreparedStatement ps = null;
        File fSQL = new File(System.getProperty("user.home"), "insert_budgets.txt");
        FileWriter fw = new FileWriter(fSQL);
        progressShowing = (int) nbLignes / 500;

        try {
            br = new BufferedReader(new FileReader(budgets));
            line = br.readLine();

            int i = 0;
            int total = 0;
            Long tempsTotalTraitement = Long.parseLong("0");
            Date datedeb = new Date();
            ArrayList<String> ministeres = new ArrayList<String>();
            while (line != null) {
                i++;
                total++;
                if (line.length() > 15) {
                    // Dernière ligne?
                    if(line.substring(8, "00000000".length()+8).equals("00000000")) {
                        ministeres.add(line);
                    }
                    if (total == nbLignes) {
                        fw.write(line.substring(0,4)+line.substring(12,16) + "," + line.substring(16,line.length()-1));
                    } else {
                    	fw.write(line.substring(0,4)+line.substring(12,16) + "," + line.substring(16,line.length()-1) + "\n");
                    }
                }
                if (i == progressShowing) {
                    fireProperty("progress", i);
                    i = 0;
                }
                line = br.readLine();
            }
            if (i != 0) {
                fireProperty("progress", i);
            }
            i = 0;        
            fw.flush();
            fw.close();
            // Insertion en base des valeurs
            ps = con.prepareStatement("LOAD DATA LOCAL INFILE '" + fSQL.getAbsolutePath().replaceAll("\\\\", "\\\\\\\\") + "' INTO TABLE " + TABLE_BUDGETS + " FIELDS TERMINATED BY ','");
            ps.execute();
            fSQL.delete();

            ps = con.prepareStatement("INSERT INTO "+TABLE_MINISTERES+" (CODE,LIBELLE) VALUES(?,?)");
            for(String s: ministeres) {
                ps.setString(1,s.substring(6, 8));
                ps.setString(2,s.substring(16).trim());
                ps.executeUpdate();
            }

            // Calcul de temps de traitement
            Date datefin = new Date();
            tempsTotalTraitement += (datefin.getTime() - datedeb.getTime());
            int minutes = Integer.parseInt(Long.toString(tempsTotalTraitement / (60 * 1000)));
            int secondes = Integer.parseInt(Long.toString(tempsTotalTraitement / (1000)));
            int millis = Integer.parseInt(Long.toString(tempsTotalTraitement));

            logger.info("Temps d'insertion budgets = " + ((minutes != 0) ? minutes + "mins et " : "") + ((secondes) - (minutes * 60)) + "s et " + ((millis) - (secondes * 1000)) + "ms");

        } catch (IOException e) {
            if (e.getClass().equals(FileNotFoundException.class)) {
                logger.debug("Le fichier des budgets n'a pas été trouvé !", e.getCause());
            } else {
                logger.debug("IOException sur le fichier " + budgets.getAbsolutePath() + " !", e.getCause());
            }
        } catch (SQLException e) {
            throw e;
        } finally {
            if (ps != null) {
                try {
                    ps.close();
                } catch (Throwable t) {
                }
            }
        }
    }
    
    protected void saveOrdos(File ordos, int nbLignes) throws Exception {
        BufferedReader br;
        String line;
        PreparedStatement ps = null;
        File fSQL = new File(System.getProperty("user.home"), "insert_ordos.txt");
        FileWriter fw = new FileWriter(fSQL);
        progressShowing = (int) nbLignes / 50;

        try {
            br = new BufferedReader(new FileReader(ordos));
            line = br.readLine();

            int i = 0;
            int total = 0;
            Long tempsTotalTraitement = Long.parseLong("0");
            Date datedeb = new Date();
            while (line != null) {
                //i++;
                total++;
                if (line.length() > 15) {
                    // Dernière ligne?
                    if (total == nbLignes) {
                    	fw.write(line.substring(5,10) + "," + line.substring(10,line.length()-1));
                    } else {
                    	fw.write(line.substring(5,10) + "," + line.substring(10,line.length()-1) + "\n");
                    }
                }
                if (i == progressShowing) {
                    fireProperty("progress", i);
                    i = 0;
                }
                line = br.readLine();
            }
            if (i != 0) {
                fireProperty("progress", i);
            }
            i = 0;            
            fw.flush();
            fw.close();
            // Insertion en base des valeurs
            ps = con.prepareStatement("LOAD DATA LOCAL INFILE '" + fSQL.getAbsolutePath().replaceAll("\\\\", "\\\\\\\\") + "' INTO TABLE " + TABLE_ORDOS + " FIELDS TERMINATED BY ','");
            ps.execute();
            fSQL.delete();

            // Calcul de temps de traitement
            Date datefin = new Date();
            tempsTotalTraitement += (datefin.getTime() - datedeb.getTime());
            int minutes = Integer.parseInt(Long.toString(tempsTotalTraitement / (60 * 1000)));
            int secondes = Integer.parseInt(Long.toString(tempsTotalTraitement / (1000)));
            int millis = Integer.parseInt(Long.toString(tempsTotalTraitement));

            logger.info("Temps d'insertion ordos = " + ((minutes != 0) ? minutes + "mins et " : "") + ((secondes) - (minutes * 60)) + "s et " + ((millis) - (secondes * 1000)) + "ms");

        } catch (IOException e) {
            if (e.getClass().equals(FileNotFoundException.class)) {
                logger.debug("Le fichier d'ordos n'a pas été trouvé !", e.getCause());
            } else {
                logger.debug("IOException sur le fichier " + ordos.getAbsolutePath() + " !", e.getCause());
            }
        } catch (SQLException e) {
            throw e;
        } finally {
            if (ps != null) {
                try {
                    ps.close();
                } catch (Throwable t) {
                }
            }
        }
    }
    
    protected void saveComptas(File comptas, int nbLignes) throws Exception {
        BufferedReader br;
        String line;
        PreparedStatement ps = null;
        File fSQL = new File(System.getProperty("user.home"), "insert_comptas.txt");
        FileWriter fw = new FileWriter(fSQL);
        progressShowing = (int) nbLignes / 500;

        try {
            br = new BufferedReader(new FileReader(comptas));
            line = br.readLine();

            int i = 0;
            int total = 0;
            Long tempsTotalTraitement = Long.parseLong("0");
            Date datedeb = new Date();
            while (line != null) {
                //i++;
                total++;
                if (line.length() > 15) {
                    // Dernière ligne?
                    if (total == nbLignes) {
                    	fw.write(line.substring(0,6) + "," + line.substring(6,line.length()-1));
                    } else {
                    	fw.write(line.substring(0,6) + "," + line.substring(6,line.length()-1) + "\n");
                    }
                }
                if (i == progressShowing) {
                    fireProperty("progress", i);
                    i = 0;
                }
                line = br.readLine();
            }
            if (i != 0) {
                fireProperty("progress", i);
            }
            i = 0;
            fw.flush();
            fw.close();
            // Insertion en base des valeurs
            ps = con.prepareStatement("LOAD DATA LOCAL INFILE '" + fSQL.getAbsolutePath().replaceAll("\\\\", "\\\\\\\\") + "' INTO TABLE " + TABLE_COMPTABLES + " FIELDS TERMINATED BY ','");
            ps.execute();
            fSQL.delete();

            // Calcul de temps de traitement
            Date datefin = new Date();
            tempsTotalTraitement += (datefin.getTime() - datedeb.getTime());
            int minutes = Integer.parseInt(Long.toString(tempsTotalTraitement / (60 * 1000)));
            int secondes = Integer.parseInt(Long.toString(tempsTotalTraitement / (1000)));
            int millis = Integer.parseInt(Long.toString(tempsTotalTraitement));

            logger.info("Temps d'insertion comptas = " + ((minutes != 0) ? minutes + "mins et " : "") + ((secondes) - (minutes * 60)) + "s et " + ((millis) - (secondes * 1000)) + "ms");

        } catch (IOException e) {
            if (e.getClass().equals(FileNotFoundException.class)) {
                logger.debug("Le fichier des comptas n'a pas été trouvé !", e.getCause());
            } else {
                logger.debug("IOException sur le fichier " + comptas.getAbsolutePath() + " !", e.getCause());
            }
        } catch (SQLException e) {
            throw e;
        } finally {
            if (ps != null) {
                try {
                    ps.close();
                } catch (Throwable t) {
                }
            }
        }
    }
    
    protected FileInfo importFile(File f, int nbLignes) throws Exception {
        FileInfo ret = new FileInfo();
        
        dirEDMN = File.createTempFile("tmp", "edmn", f.getParentFile());
        dirEDMN.delete();
        dirEDMN.mkdir();
        if(dirEDMN!=null && dirEDMN.listFiles().length>0){
        	for(File fToDelete:dirEDMN.listFiles()){
        		fToDelete.delete();
        	}
        }
        
        generateXmlFileText(f,dirEDMN,nbLignes);
        return ret;
    }

    protected static String fmtNumLiasse(int i) {
        String v = Integer.toString(i);
        while(v.length()<4) v="0".concat(v);
        return v;
    }

    protected String getNumLiasseNationale(
            String annee,
            String trimestre,
            String comptable,
            String ministere,
            String numLiasseLocaleDeb,
            String numLiasseLocaleFin,
            Connection con) {

        PreparedStatement ps = null;
        StringBuffer ret = new StringBuffer();

        StringBuffer numLiasses = new StringBuffer();
        int start = 0;
        int end = 0;
        try {
            start = Integer.parseInt(numLiasseLocaleDeb);
        } catch(NumberFormatException nfEx) {
        }
        try {
            end = Integer.parseInt(numLiasseLocaleFin);
        } catch(NumberFormatException nfEx) {
        }
        numLiasses.append("(");
        for(int i=start;i<end;i++) {
            numLiasses.append("'").append(fmtNumLiasse(i)).append("',");
        }
        numLiasses.append("'").append(fmtNumLiasse(end)).append("')");
        try {
            // Création d'un prepared statement
            ps = con.prepareStatement("SELECT NATIONALE FROM " + TABLE_INDEX + " WHERE ANNEE = ? AND TRIMESTRE = ? AND COMPTABLE = ? AND MINISTERE = ? AND LOCALE IN "+numLiasses.toString()+" ORDER BY 1");
            ps.setString(1, annee);
            ps.setString(2, trimestre);
            ps.setString(3, comptable);
            ps.setString(4, ministere);

            ResultSet rs = ps.executeQuery();
            while (rs.next()) {
                ret.append("<Liasse V=\"").append(rs.getString(1)).append("\"/>");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (ps != null) {
                try {
                    ps.close();
                } catch (Throwable t) {
                }
            }
        }
        return ret.toString();
    }

    protected String getLibelleBudget(String code, Connection con) {

        PreparedStatement ps = null;
        String ret = "";
        long start=System.currentTimeMillis();
        try {
            // Création d'un prepared statement
        	ps = con.prepareStatement("SELECT LIBELLE FROM " + TABLE_BUDGETS + " WHERE CODE = ?");
        	ps.setString(1, code);
            
            ResultSet rs = ps.executeQuery();
            if (rs.next()) {
                ret = escape(rs.getString(1));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (ps != null) {
                try {
                    ps.close();
                } catch (Throwable t) {
                }
            }
        }
        return ret;
    }
    protected String getLibelleMinistere(String code, Connection con) {

        PreparedStatement ps = null;
        String ret = "";
        try {
        	ps = con.prepareStatement("SELECT LIBELLE FROM " + TABLE_MINISTERES + " WHERE CODE = ?");
        	ps.setString(1, code);
            ResultSet rs = ps.executeQuery();
            if (rs.next()) {
                ret = escape(rs.getString(1));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (ps != null) {
                try {
                    ps.close();
                } catch (Throwable t) {
                }
            }
        }
        return ret;
    }
    
    protected String getLibelleOrdo(String code, Connection con) {

        PreparedStatement ps = null;
        String ret = "";
        try {
            // Création d'un prepared statement
            ps = con.prepareStatement("SELECT LIBELLE FROM " + TABLE_ORDOS + " WHERE CODE = ?");
            ps.setString(1,code);
            
            ResultSet rs = ps.executeQuery();
            if (rs.next()) {
                ret = escape(rs.getString(1));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (ps != null) {
                try {
                    ps.close();
                } catch (Throwable t) {
                }
            }
        }
        return ret;
    }
    
    protected String getLibelleCompta(String code, Connection con) {

        PreparedStatement ps = null;
        String ret = "";
        try {
            // Création d'un prepared statement
            ps = con.prepareStatement("SELECT LIBELLE FROM " + TABLE_COMPTABLES + " WHERE CODE = ?");
            ps.setString(1, code);
            
            ResultSet rs = ps.executeQuery();
            if (rs.next()) {
                ret = escape(rs.getString(1));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (ps != null) {
                try {
                    ps.close();
                } catch (Throwable t) {
                }
            }
        }
        return ret;
    }

    protected void generateXmlFileText(File source, File dirDest, int nbLignes) throws IOException, SAXException, SQLException {
        progressShowing = nbLignes / (nbLignes / 500);
        
        dirDest.mkdir();
        
        FileOutputStream fWriter=null;
        BufferedReader br = new BufferedReader(new FileReader(source));
       
        int breakFile=MAX_SIZE_FILE;
        long nbTotalLines = Long.parseLong(String.valueOf(nbLignes));
        int nbLignesToSplitFile = (int)Math.ceil(nbTotalLines/breakFile);
        if(nbTotalLines%breakFile > 0) nbLignesToSplitFile++;
        int nbLignesParcourues = 0;
        int i = 0;
        int iLines = 0;
        Vector<String> vLignes = new Vector<String>();
        long start = 0L;
        long startLines = 0L;
        int nbLinesToGroup = 500;
        boolean firstEtat=true;
    	String line = br.readLine();
        for(int numFile = 1;numFile<=nbLignesToSplitFile;numFile++) {
            File destFile = new File(dirDest.getAbsolutePath(),source.getName()+"-"+numFile+".xml");
        	fWriter = new FileOutputStream(destFile);
            generatedFiles.add(destFile);
        	fWriter.write(("<?xml version=\"1.0\" encoding=\""+ENCODING+"\"?>\n<Edmn xmlns=\"" + EDMN_NS_URI + "\" xmlns:n=\"" + EDMN_NS_URI + "\">\n").getBytes(ENCODING));
        	fWriter.write(("<ReferenceNomenclature>\n<Code V=\""+getCodeReferenceNomenclature(line)+"\"/>\n<Libelle V=\""+getLibelleReferenceNomenclature(line)+"\"/>\n</ReferenceNomenclature>\n").getBytes(ENCODING));
        	fWriter.write("<Budget><Code V=\"0000\"/><Libelle V=\"LFI\"/></Budget>\n".getBytes(ENCODING));
        	fWriter.write("<Collectivite><Code V=\"000000000000\"/><Libelle V=\"ETAT\"/></Collectivite>\n".getBytes(ENCODING));
        	fWriter.write("<EtatEdmn>\n".getBytes(ENCODING));
        	try {
                while (line != null && nbLignesParcourues!=breakFile) {
                	nbLignesParcourues++;
                	if(!firstEtat){
                    if (iLines == 0) {
                        startLines = System.currentTimeMillis();
                    }
                    i++;
                    iLines++;
                    long startLine = System.currentTimeMillis();
                    vLignes.add(createLineText(line.toCharArray(), con));                    
                    if (vLignes.size() == nbLinesToGroup) {
                        iLines = 0;
                        start = System.currentTimeMillis();
                        StringBuilder sb = new StringBuilder();
                        for (String s : vLignes) {
                            sb.append(s);
                        }
                        fWriter.write(sb.toString().getBytes(ENCODING));
                        vLignes.clear();
                    }
                    if (i == progressShowing) {
                        fireProperty("progress", i);
                        i = 0;
                    }
                    line = br.readLine();
                	}
                }
            } catch (SAXException e) {
                logger.debug("", e);
            }
            nbLignesParcourues=0;
            if (vLignes.size() > 0) {
                StringBuilder sb = new StringBuilder();
                for (String s : vLignes) {
                    sb.append(s);
                }
                fWriter.write(sb.toString().getBytes(ENCODING));
                vLignes.clear();
            }
            fWriter.write("</EtatEdmn>\n".getBytes(ENCODING));
            if(firstEtat) {
            	firstEtat=false;
            	fWriter.write("<Nomenclatures>\n".getBytes(ENCODING));
            	createRepositorys(fWriter,budgets, ordos, comptables);
            	fWriter.write("</Nomenclatures>\n".getBytes(ENCODING));
            }
            fWriter.write("</Edmn>".getBytes(ENCODING));
            fWriter.flush();
            fWriter.close();
        }
        if (i != 0) {
            fireProperty("progress", i);
        }
    }

    /**
     * 
     * @param budgets : Fichier contenant les codes/libelles des budgets
     * @param ordonateurs : Fichier contenant les codes/libelles des ordonateurs
     * @param comptables : Fichier contenant les codes/libelles des comptables
     */
    private void createRepositorys(FileOutputStream writer,File budgets,File ordonateurs,File comptables){
    	createBudgetRepository(writer,budgets);
    	createOrdoRepository(writer,ordonateurs);
    	createComptaRepository(writer,comptables);
    }
    
    private void createBudgetRepository(FileOutputStream writer,File f){
    	try{
    		writer.write(("<NomenclatureBudgets>\n<Description V=\"Nomenclature des Budgets\"/>\n").getBytes());
	        BufferedReader br = new BufferedReader(new FileReader(f));
	        String line = br.readLine();        
	        while (line != null) {
	        	writer.write(("<Correspondance><Code V=\""+line.substring(0,16).trim()+"\"/><Libelle V=\""+line.substring(16,line.length()-1).trim().replaceAll("\"","'")+"\"/></Correspondance>\n").replaceAll("&","&amp;").getBytes());
	        	line = br.readLine();
	        }
	        writer.write(("</NomenclatureBudgets>\n").getBytes());
	        br.close();
    	}catch (Exception e) {
    		logger.debug("Problème lors de la création de la nomenclature budget !");
    		e.printStackTrace();
		}
    }
    
    private void createOrdoRepository(FileOutputStream writer,File f){
    	try{
    		writer.write(("<NomenclatureOrdonnateurs>\n<Description V=\"Nomenclature des Ordonateurs\"/>\n").getBytes());
	        BufferedReader br = new BufferedReader(new FileReader(f));
	        String line = br.readLine();        
	        while (line != null) {
	        	writer.write(("<Correspondance><Code V=\""+line.substring(0,10).trim()+"\"/><Libelle V=\""+line.substring(10,line.length()-1).trim().replaceAll("\"","'")+"\"/></Correspondance>\n").replaceAll("&","&amp;").getBytes());   
	        	line = br.readLine();
	        }
	        writer.write(("</NomenclatureOrdonnateurs>\n").getBytes());
	        br.close();
    	}catch (Exception e) {
    		logger.debug("Problème lors de la création de la nomenclature budget !");
    		e.printStackTrace();
		}
    }
    
    private void createComptaRepository(FileOutputStream writer,File f){
    	try{
    		writer.write(("<NomenclatureComptables>\n<Description V=\"Nomenclature des Comptables\"/>\n").getBytes());
	        BufferedReader br = new BufferedReader(new FileReader(f));
	        String line = br.readLine();        
	        while (line != null) {
	        	writer.write(("<Correspondance><Code V=\""+line.substring(0,6).trim()+"\"/><Libelle V=\""+line.substring(6,line.length()-1).trim().replaceAll("\"","'")+"\"/></Correspondance>\n").replaceAll("&","&amp;").getBytes());    
	        	line = br.readLine();
	        }
	        writer.write(("</NomenclatureComptables>\n").getBytes());
	        br.close();
    	}catch (Exception e) {
    		logger.debug("Problème lors de la création de la nomenclature budget !");
    		e.printStackTrace();
		}
    }
    
    
    public String getAdditionalMessage() {
        return "";
    }


    private String getLine(char[] tab, int deb, int fin) {
        String s = "";
        for (int i = deb; i < fin; i++) {
            s += String.valueOf(tab[i]);
        }
        return escaper.escapeString(s.trim());
    }

    private String getCodeReferenceNomenclature(String line){
    	 return line.substring(72, 76)+"-"+line.substring(69,70);
    }
    
    private String getLibelleReferenceNomenclature(String line){
   	 return "Année "+line.substring(72, 76)+" - Trimestre "+line.substring(69,70);
   }
    
    protected void writeNode(String nodeName, String value, DefaultHandler h) throws SAXException {
        AttributesImpl attr = new AttributesImpl();
        attr.addAttribute("", "V", "V", "String", value);
        h.startElement(EDMN_NS_URI, nodeName, "n:" + nodeName, attr);
        h.endElement(EDMN_NS_URI, nodeName, "n:" + nodeName);
    }

    private String createLineText(char[] line, Connection con) throws SAXException {
        StringBuilder sb = new StringBuilder("<LigneEdmn>");
        sb.append("<Comptable V=\"").append(getLine(line, 0, 6)).append("\"/><LibelleComptable V=\"").append(getLibelleCompta(getLine(line, 0, 6),con));
        sb.append("\"/><Ministere V=\"").append(getLine(line, 7, 9)).append("\" LibelleMinistere=\"");
        sb.append(getLibelleMinistere(getLine(line,7,9),con)).append("\"/><Ordo V=\"").append(getLine(line, 9, 15)).append("\"/><LibelleOrdonnateur V=\"");
        sb.append(getLibelleOrdo(getLine(line, 7, 12),con)).append("\"/><LibelleBudget V=\"").append(getLibelleBudget(getLine(line, 72, 76)+getLine(line, 51, 55),con));
        sb.append("\"/><TypeEvt V=\"").append(getLine(line, 15, 18)).append("\"/><AnneeBudget V=\"20").append(getLine(line, 18, 20));
        sb.append("\"/><NumMandat V=\"").append(getLine(line, 20, 26)).append("\"/><CompteSpeTresor V=\"").append(getLine(line, 26, 31));
        sb.append("\"/><NumOpeInvest V=\"").append(getLine(line, 31, 39)).append("\"/><AnneeEngag V=\"").append(getLine(line, 39, 41));
        sb.append("\"/><NumEngag V=\"").append(getLine(line, 41, 47)).append("\"/><ChapBudg V=\"").append(getLine(line, 47, 51));
        sb.append("\"/><ArtBudgExec V=\"").append(getLine(line, 51, 53)).append("\"/><ParagBudgExec V=\"").append(getLine(line, 53, 55)).append("\"/>");
        String mtedm = getLine(line, 55, 68);
        while (mtedm.startsWith("<0")) {
            mtedm = mtedm.substring(1);
        }
        if (getLine(line, 68, 69).trim().equals("-")) {
            mtedm = "-" + mtedm;
        }
        sb.append("<MtPJ V=\"").append(mtedm).append("\"/><Trimestre V=\"").append(getLine(line, 69, 70)).append("\"/><Mois V=\"");
        sb.append(getLine(line, 70, 72)).append("\"/><AnneeCrea V=\"").append(getLine(line, 72, 76)).append("\"/><MoisCrea V=\"");
        sb.append(getLine(line, 76, 78)).append("\"/><JourCrea V=\"").append(getLine(line, 78, 80)).append("\"/><ChapClassPJ V=\"");
        sb.append(getLine(line, 80, 84)).append("\"/><TypePaiement V=\"").append(getLine(line, 84, 87)).append("\"/><ArtBudgPrev V=\"");
        sb.append(getLine(line, 87, 89)).append("\"/><Zone24 V=\"").append(getLine(line, 89, 113)).append("\"/><NumLiasseDeb V=\"");
        sb.append(getLine(line, 113, 117)).append("\"/><NumLiasseFin V=\"").append(getLine(line, 117, 121)).append("\"/><TypeSuiviEco1 V=\"").append(getLine(line, 121, 123));
        sb.append("\"/><TypeSuiviEco2 V=\"").append(getLine(line, 123, 125)).append("\"/><TypeSuiviEco3 V=\"").append(getLine(line, 125, 127));
        sb.append("\"/><CodeCorrection V=\"").append(getLine(line, 127, 131)).append("\"/><NumLiasseNationale>");
        sb.append(getNumLiasseNationale(getLine(line, 74, 76), getLine(line, 69, 70), getLine(line, 0, 6), getLine(line, 6, 9), getLine(line, 113, 117),getLine(line, 117, 121), con)).append("</NumLiasseNationale>");
        sb.append("<CodeManip V=\"").append(getLine(line, 137, 138)).append("\"/><Zone32 V=\"").append(getLine(line, 138, 170));
        sb.append("\"/><DateCreation V=\"").append(getLine(line, 72, 76)).append("-" + getLine(line, 76, 78)).append("-").append(getLine(line, 78, 80));
        sb.append("\"/></LigneEdmn>\n");
        return sb.toString();
    }    

    private boolean generateArchive() {
        boolean bRet = false;
//        JFileChooser jfc = new JFileChooser(budgets.getParentFile());
//        jfc.addChoosableFileFilter(new FileFilter() {
//            @Override
//            public boolean accept(File f) {
//                return f.getName().toUpperCase().endsWith(".XAR") || f.isDirectory();
//            }
//            @Override
//            public String getDescription() {
//                return "Archive Xemelios (.xar)";
//            }
//        });
//        jfc.setMultiSelectionEnabled(false);
//        jfc.setDialogTitle("Enregistrer l'archive Xemelios sous...");
//        int ret = jfc.showSaveDialog(null);
//        if(ret==JFileChooser.APPROVE_OPTION) {
            File target = output;
            try {
                ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(target));
                for(File f:generatedFiles) {
                    ZipEntry ze = new ZipEntry("data/"+f.getName());
                    zos.putNextEntry(ze);
                    byte[] buffer = new byte[2048];
                    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(f));
                    int read = bis.read(buffer);
                    while(read>0) {
                        zos.write(buffer,0,read);
                        read = bis.read(buffer);
                    }
                    bis.close();
                }
                ZipEntry manifestEntry = new ZipEntry(XemeliosArchiveImporter.MANIFEST_FILENAME);
                zos.putNextEntry(manifestEntry);
                StringBuffer sb = new StringBuffer();
                sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
                sb.append("<manifeste cgIdCol=\"000000000000\" cgLibelle=\"ETAT\">\n");
                sb.append("\t<volumes>\n");
                sb.append("\t\t<volume fichier=\"").append(target.getName()).append("\" num=\"1\" dateProduction=\"").append(getFormattedCurrentDateTime()).append("\"/>\n");
                sb.append("\t</volumes>\n");
                sb.append("\t<documents>\n");
                for(File f:generatedFiles) {
                    sb.append("\t\t<document volume=\"1\" path=\"data/").append(f.getName()).append("\" type=\"edmn\" buIdCol=\"000000000000\" buLibelle=\"ETAT\" buCode=\"0000\" libBudget=\"LFI\"/>\n");
                }
                sb.append("\t</documents>\n");
                sb.append("\t</manifeste>\n");
                zos.write(sb.toString().getBytes("UTF-8"));
                zos.flush();
                zos.close();
                bRet = true;
            } catch (Exception ex) {
                logger.error(null, ex);
            }
//        }
        return bRet;
    }
    private void cleanTempFile() {
        File[] files = dirEDMN.listFiles();
        for(File f:files) f.delete();
        dirEDMN.delete();
    }
    private static String getFormattedCurrentDateTime() {
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
        return sdf.format(new Date(System.currentTimeMillis()));
    }
    private void importEdmnFile(){
    	if(MainWindow.instance!=null) {
    		//int reponse = JOptionPane.showConfirmDialog(MainWindow.instance,"Souhaitez-vous importer le fichier généré ?","Question",JOptionPane.YES_NO_OPTION);
    		//if(JOptionPane.YES_OPTION == reponse){
    			DocumentModel dm = MainWindow.instance.getDocModels().getDocumentById("edmn");
    			try {
    				Class clazz = Class.forName(dm.getImportClass());
    		        Object obj = clazz.newInstance();
    				if(!(obj instanceof EtatImporteur)) {
    					JOptionPane.showMessageDialog(MainWindow.instance,"Cette classe n'est pas un importeur.\nLe fichier de configuration qui vous a été livré est certainement invalide.\nVeuillez contacter votre fournisseur.\n","Erreur",JOptionPane.ERROR_MESSAGE);
    					return;
    				}
    				EtatImporteur ei = (EtatImporteur)obj;
    				ei.setDocument(dm);
//    				ArrayList<File> array = new ArrayList<File>();
    				/* Zippage avant import */
// TODO: est-ce bien necessaire ? pour le transport, c'est pas mal...
        			File zip = makeZip();

                    MainWindow.ImportContent ic = new MainWindow.ImportContent();
                    File tmpDir = new File(System.getProperty("java.io.tmpdir"));

                    ZipFile zf = null;
                    try {
                        zf = new ZipFile(zip);
                        for (Enumeration<? extends ZipEntry> enumer = zf.entries(); enumer.hasMoreElements();) {
                            ZipEntry ze = enumer.nextElement();
                            if (!ze.isDirectory()) {
                                String fileName = ze.getName();
                                String entryName = fileName.toLowerCase();
                                fileName = fileName.replace(
                                        File.pathSeparatorChar, '_').replace(
                                        File.separatorChar, '_').replace(':',
                                        '|').replace('\'', '_').replace('/',
                                        '_');
//                                logger.debug(entryName);
                                if(PJRef.isPJ(ze)) {
                                    PJRef pj = new PJRef(ze);
                                    pj.writeTmpFile(tmpDir,zf);
                                    ic.getPjs().add(pj);
                                } else if ((entryName.endsWith(dm.getExtension().toLowerCase()) || entryName.endsWith(".xml")) && !fileName.startsWith("_")) {
                                    // on decompresse le fichier dans le
                                    // repertoire temporaire, comme ca il sera
                                    // supprime en quittant
                                    InputStream is = zf.getInputStream(ze);
                                    BufferedInputStream bis = new BufferedInputStream(is);
                                    File output = new File(tmpDir, fileName);
                                    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(output));
                                    byte[] buffer = new byte[1024];
                                    int read = bis.read(buffer);
                                    while (read > 0) {
                                        bos.write(buffer, 0, read);
                                        read = bis.read(buffer);
                                    }
                                    bos.flush();
                                    bos.close();
                                    bis.close();
                                    ic.getFilesToImport().add(output);
                                }
                            }
                        }
                        zf.close();
                    } catch (ZipException zEx) {
                        JOptionPane.showMessageDialog(MainWindow.instance, "Le fichier "
                                + zip.getName()
                                + " n'est pas une archive ZIP valide",
                                "Erreur", JOptionPane.ERROR_MESSAGE);
                    } catch (IOException ioEx) {
                        JOptionPane
                                .showMessageDialog(
                                MainWindow.instance,
                                "Le fichier "
                                + zip.getName()
                                + " est illisible. Vérifiez que les noms des fichiers\ncontenus dans l'archive ne comportent pas de caractères spéciaux ou accentués.",
                                "Erreur", JOptionPane.ERROR_MESSAGE);
                        ioEx.printStackTrace();
                    } finally {
                        if(zf!=null) {
                            try { zf.close(); } catch(Throwable t) {}
                        }
                    }

                    fireProperty("terminated", "Génération terminée.");	// histoire de pas faire un new

    				dirEDMN.delete();
//    				for(File f:dirEDMN.listFiles()){
//    					ic.getFilesToImport().add(f);
//    				}
//    				fToImport.setFilesToImport(array);
    				MainWindow.instance.doImport(ei,ic,dm,false);
    			} catch (IOException e) {
    				e.printStackTrace();    				
    			} catch (ClassNotFoundException e) {
    				e.printStackTrace();
    			} catch (InstantiationException e) {
    				e.printStackTrace();
    			} catch (IllegalAccessException e) {
    				e.printStackTrace();
    			} catch (SecurityException e) {
    				e.printStackTrace();
    			} catch (IllegalArgumentException e) {
    				e.printStackTrace();
    			}
    		/*}else if(JOptionPane.NO_OPTION == reponse){
    			DlgEdmnSaveAs dlgsaveas = new DlgEdmnSaveAs(MainWindow.instance,true,dirEDMN);    		
    			dlgsaveas.setVisible(true);
    			int reponse2 = JOptionPane.showConfirmDialog(MainWindow.instance,"Les fichiers générés se trouvent dans :\n"+dirEDMN.getAbsolutePath()+"\n\nDésirez-vous ouvrir ce dossier ?","Question",JOptionPane.YES_NO_OPTION);
        		if(JOptionPane.YES_OPTION == reponse2){
        			 try {
						Runtime.getRuntime().exec("explorer.exe \""+dirEDMN.getAbsolutePath()+"\"");
					} catch (IOException e) {
						e.printStackTrace();
					}
        		}*/
    			//JOptionPane.showMessageDialog(MainWindow.instance,"Les fichiers générés se trouvent dans :\n"+dirEDMN.getAbsolutePath(),"Information",JOptionPane.INFORMATION_MESSAGE);
    		//}
    	}
        fireProperty("terminated", "");	// histoire de pas faire un new
    }
    
    private File makeZip() throws IOException{
    	 //Création d'un flux d'écriture vers un fichier
    	File fout = new File(dirEDMN.getParent(),"EDMN.xml.zip");
    	FileOutputStream fos=null;
        try {
            fos = new FileOutputStream(fout);
            //Ajout du checksum : Adler32 (plus rapide) ou CRC32
            CheckedOutputStream checksum = new CheckedOutputStream(fos, new Adler32());
            try {
                //Création d'un buffer de sortie afin d'améliorer les performances
                BufferedOutputStream bos = new BufferedOutputStream(checksum, BUFFER_SIZE);
                try {
                    //Création d'un flux d'écriture Zip vers le fichier à  travers le buffer
                    ZipOutputStream zos = new ZipOutputStream(bos);
                    try {
                        //Compression maximale
                        try {
                            zos.setMethod(ZipOutputStream.DEFLATED);
                            zos.setLevel(Deflater.BEST_COMPRESSION);
                        } catch (Exception ignor) {}
                        zipDir(dirEDMN.getAbsolutePath(), null, zos);
                    } finally {
                        zos.close();
                    }
                }finally {
                    bos.close();
                }
            } finally {
                checksum.close();
            }
        } finally {         
			fos.close();            
        }
        return fout;
    }
    private static void zipDir(String basedir, String currentdir, ZipOutputStream zos) throws FileNotFoundException, IOException {
		//create a new File object based on the directory we have to zip
		File zipDir = (currentdir != null) ? new File(basedir, currentdir) : new File(basedir);
		//get a listing of the directory content
		String[] dirList = zipDir.list();
		byte[] readBuffer = new byte[BUFFER_SIZE];
		int bytesIn = 0;
		//On met pas File.separator, mais "/" parce que c'est le caractère utilisé
		//dans les ZIP.
		String currentdir2 = (currentdir != null) ? (currentdir + "/") : "";

		File f;
		FileInputStream fis;
		BufferedInputStream bis;
		ZipEntry anEntry;
		//Create an empty entry with just dir name, like WinZip, so unzipToDir will
		//behave correctly.
		if (currentdir2.length() > 0) {
			anEntry = new ZipEntry(currentdir2);
			zos.putNextEntry(anEntry);
			zos.closeEntry();
		}
		//loop through dirList, and zip the files
		for (int i = 0; i < dirList.length; i++) {
			f = new File(zipDir, dirList[i]);
			if (!f.exists())
				continue;
			if (f.isDirectory()) {
				//if the File object is a directory, call this
				//function again to add its content recursively
				zipDir(basedir, currentdir2 + dirList[i], zos);
				continue;
			}
			//if we reached here, the File object f was not a directory
			//create a FileInputStream on top of f
			fis = new FileInputStream(f);
			try {
				bis = new BufferedInputStream(fis, BUFFER_SIZE);
				try {
					//create a new zip entry
					anEntry = new ZipEntry(currentdir2 + dirList[i]);
					anEntry.setTime(f.lastModified());

					//place the zip entry in the ZipOutputStream object
					zos.putNextEntry(anEntry);
					//now write the content of the file to the ZipOutputStream
					while ((bytesIn = bis.read(readBuffer, 0, BUFFER_SIZE)) != -1) {
						zos.write(readBuffer, 0, bytesIn);
					}
					zos.closeEntry();
				}
				finally {
					bis.close();
				}
			}finally {
				//close the Stream
				fis.close();
			}
		}
	}

    public static String escape(String s) {
        StringBuffer sb = new StringBuffer();
        for(char c:s.trim().toCharArray()) {
            switch(c) {
                case '\'': { sb.append("&apos;"); break; }
                case '"': { sb.append("&quot;"); break; }
                case '&': { sb.append("&amp;"); break; }
                case '<': { sb.append("&lt;"); break; }
                case '>': { sb.append("&gt;"); break; }
                default: sb.append(c);
            }
        }
        return sb.toString();
    }
}
