/*
 * NAT - An universal Translator
 * Copyright (C) 2005 Bruno Mascret
 * Contact: bmascret@free.fr
 * 
 * This program 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.
 * 
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

package nat.transcodeur;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.im4java.core.CommandException;
import org.im4java.core.ConvertCmd;
import org.im4java.core.IMOperation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import outils.FileToolKit;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.File;
import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.io.FileOutputStream;
//import java.io.FileInputStream;
import java.util.ArrayList;

import net.sf.saxon.TransformerFactoryImpl;

import gestionnaires.GestionnaireErreur;

import nat.ConfigNat;
import nat.Nat;
/**
 * <p>La classe <code>TranscodeurNormal</code> réalise la transcription d'un fichier au format
 * XML interne en Braille</p>
 * @author  Bruno Mascret
 */
public class TranscodeurNormal extends Transcodeur 
{	
	/*  Configuration à utiliser   */
	//private ConfigNat confNat;
	/** La feuille de style xsl contenant les paramètres de transcription et mise en page */
	private String fic_paramsAll=ConfigNat.getUserTempFolder()+"paramsAll.xsl";	
	/** La feuille de style xsl contenant les paramètres spécifiques à la mise en page */
	private String fic_paramsMEP=ConfigNat.getUserTempFolder()+"paramsMEP.xsl";
	/** La feuille de style xsl contenant les paramètres spécifiques à la transcription */
	private String fic_paramsTrans=ConfigNat.getUserTempFolder()+"paramsTrans.xsl";
	
	/**
    * Construit un objet TranscodeurNormal
    *
    *  @param	e			<code>String</code> adresse du fichier d'entrée (format XML interne)
    *  @param	s			<code>String</code> adresse du fichier de sortie
    *  @param	se			<code>String</code> encodage du fichier de sortie
	 * @param g instance de {@link GestionnaireErreur}
    */
	
	public TranscodeurNormal(String e, String s, String se, GestionnaireErreur g)
	{
		super(e,s,se,g);
		filtre = ConfigNat.getCurrentConfig().getXSL();
		if (!ConfigNat.getCurrentConfig().getAbreger())
		{
			abrege = false;
		}
	}
	
	/**
	 * Fabrique le fichier params.xsl en fonction de la configuration de <code>configNat</code>
	 * @param	gestErreur	Un objet <code>GestionnaireErreur</code> pour l'affichage et la gestion
	 * des improbables erreurs.
	 * Fabrique ensuite xsl.xsl avec les xsl:include qu'il faut selon ce qui est traité.
	 */
	private void creerFiltres(GestionnaireErreur gestErreur)
	{
		/* Création du fichier xsl des paramètres */
		try
		{
			// TODO réfléchir à une réorganisation de la création des fichiers params
			createParamCommuns(gestErreur);
			createParamMEP(gestErreur);
			createParamTrans(gestErreur);
			createMainXsl();
		}		 
		catch (ParserConfigurationException pce)
		{
			gest.setException(pce);
			gest.gestionErreur();
		}
		catch (TransformerConfigurationException tce)
		{
			gest.setException(tce);
			gest.gestionErreur();
		}
		catch (TransformerException te)
		{
			gest.setException(te);
			gest.gestionErreur();
		}
	}
	/**
	 * Creates the xsl.xsl file including other xsl stylesheets depending on the configuration stored in <code>configNat</code>
	 * @throws ParserConfigurationException erreur de parsage
	 * @throws TransformerException erreur lors de la transformation
	 */
	private void createMainXsl() throws ParserConfigurationException, TransformerException
	{
		DocumentBuilderFactory fabrique = DocumentBuilderFactory.newInstance();
		DocumentBuilder constructeur= fabrique.newDocumentBuilder();
	    Document docXSL = constructeur.newDocument();
	    // Propriétés de docParam
	    docXSL.setXmlVersion("1.1");
	    docXSL.setXmlStandalone(true);
	    
	    //racine
	    Element racine = docXSL.createElement("xsl:stylesheet");
	    racine.setAttribute("version", "2.0");
	    racine.setAttribute("xmlns:xsl", "http://www.w3.org/1999/XSL/Transform");
	    racine.setAttribute("xmlns:xs","http://www.w3.org/2001/XMLSchema");
	    racine.setAttribute("xmlns:saxon","http://icl.com/saxon");
	    racine.setAttribute("xmlns:m","http://www.w3.org/1998/Math/MathML");
	    racine.setAttribute("xmlns:fn","http://www.w3.org/2005/xpath-functions");
	    racine.setAttribute("xmlns:lit","espacelit");
	    racine.setAttribute("xmlns:nat", "http://natbraille/free/fr/xsl");
	    racine.setAttribute("xmlns:doc","espaceDoc");
	    racine.appendChild(docXSL.createComment("Auto-generated file; see Transcodeur.java"));
	    racine.appendChild(docXSL.createComment(Nat.getLicence("", "")));

		//FileWriter fichierXSL2 = new FileWriter(filtre);
		Element output = docXSL.createElement("xsl:output");
		if(!sens)
		{
			output.setAttribute("method","xml");
		}
		else
		{
			output.setAttribute("doctype-system",ConfigNat.getInstallFolder()+"xsl/mmlents/xhtml-math11-f.dtd");
			output.setAttribute("doctype-public","-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN");
		}
		output.setAttribute("encoding",sortieEncoding);
		output.setAttribute("indent","yes");
		
		
		if(sens)
		{
			Element tan = docXSL.createElement("xsl:include");
			tan.setAttribute("href",ConfigNat.getInstallFolder()+"xsl/tan.xsl");
			racine.appendChild(tan);
		}
		else
		{
			String fichHyphens = ConfigNat.getUserTempFolder()+"hyphens.xsl";
			Element hyph = docXSL.createElement("xsl:import");
			hyph.setAttribute("href",fichHyphens);
			racine.appendChild(hyph);
			
			Element base = docXSL.createElement("xsl:include");
			base.setAttribute("href",ConfigNat.getInstallFolder()+"xsl/base.xsl");
			racine.appendChild(base);
			
			//if (ConfigNat.getCurrentConfig().getTraiterLiteraire())
			//{
			Element lit = docXSL.createElement("xsl:include");
			if (!ConfigNat.getCurrentConfig().getTraiterLiteraire()){lit.setAttribute("href",ConfigNat.getInstallFolder()+"xsl/no-lit.xsl");}
			else if (ConfigNat.getCurrentConfig().getAbreger())
			{
				lit.setAttribute("href",ConfigNat.getCurrentConfig().getXSL_g2());
				
				Element regles = docXSL.createElement("xsl:include");
				regles.setAttribute("href", new File(ConfigNat.getCurrentConfig().getXSL_g2_Rules()).getName());
				racine.appendChild(regles);
			}
			else{lit.setAttribute("href",ConfigNat.getCurrentConfig().getXSL_g1());}
			racine.appendChild(lit);
			//}
			if (ConfigNat.getCurrentConfig().getTraiterMaths())
			{
				Element math = docXSL.createElement("xsl:include");
				math.setAttribute("href",ConfigNat.getCurrentConfig().getXSL_maths());
				racine.appendChild(math);
			}
			
			if (ConfigNat.getCurrentConfig().getTraiterMusique())
			{
				Element mus = docXSL.createElement("xsl:include");
				mus.setAttribute("href",ConfigNat.getCurrentConfig().getXSL_musique());
				racine.appendChild(mus);
			}
		}
		racine.appendChild(output);
		Element strip = docXSL.createElement("xsl:strip-space");
		strip.setAttribute("elements","doc:doc lit espace phrase mot ponctuation m:* m:math m:semantics m:mrow m:msqrt");
		racine.appendChild(strip);
		
		Element paramAll = docXSL.createElement("xsl:include");
		paramAll.setAttribute("href","paramsAll.xsl");
		racine.appendChild(paramAll);
		
		Element paramTrans = docXSL.createElement("xsl:include");
		paramTrans.setAttribute("href","paramsTrans.xsl");
		racine.appendChild(paramTrans);
		docXSL.appendChild(racine);		    
	    /* Sauvegarde de document dans un fichier */
        Source source = new DOMSource(docXSL);
        
        // Création du fichier de sortie
        File f = new File(filtre);
        Result resultat = new StreamResult(f);
        
        // Configuration du transformer
        TransformerFactory tfabrique = TransformerFactory.newInstance();
        Transformer transformer = tfabrique.newTransformer();
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");  
        transformer.setOutputProperty(OutputKeys.VERSION, "1.1");
        transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, ConfigNat.getCurrentConfig().getDTD());
        // Transformation
        transformer.transform(source, resultat);
	}
	/**
	 * Fabrique le fichier paramsCommuns.xsl contenant les valeurs des éléments de configuration et de paramétrage
	 * partagés par la transcription et la mise en page
	 * @param gestErreur Une instance de GestionnaireErreur
	 * @throws ParserConfigurationException erreur de parsage
	 * @throws TransformerException erreur lors de la transformation
	 */
	private void createParamCommuns(GestionnaireErreur gestErreur) throws ParserConfigurationException, TransformerException
	{
		DocumentBuilderFactory fabrique = DocumentBuilderFactory.newInstance();
		DocumentBuilder constructeur= fabrique.newDocumentBuilder();
	    Document docParams = constructeur.newDocument();
	    // Propriétés de docParam
	    docParams.setXmlVersion("1.1");
	    docParams.setXmlStandalone(true);
	    
	    //racine
	    Element racine = docParams.createElement("xsl:stylesheet");
	    racine.setAttribute("version", "2.0");
	    racine.setAttribute("xmlns:xsl", "http://www.w3.org/1999/XSL/Transform");
	    racine.setAttribute("xmlns:xs","http://www.w3.org/2001/XMLSchema");
	    racine.appendChild(docParams.createComment("Auto-generated file; see Transcodeur.java"));
	    racine.appendChild(docParams.createComment(Nat.getLicence("", "")));
	    //paramètres
	    ArrayList<Element> params = new ArrayList<Element>();
	    params.add(fabriqueParam(docParams,"longueur",""+ConfigNat.getCurrentConfig().getLongueurLigne(),"xs:integer"));
	    params.add(fabriqueParam(docParams,"mise_en_page",ConfigNat.getCurrentConfig().getMep()+"()","xs:boolean"));
	    // caractères de marquage
	    String[] carSpec = donneCharNonUtilise(200,9,gestErreur);//je commence hors plage pénible
	    gestErreur.afficheMessage("\n** Dev : Utilisation de '"+ carSpec[0] +"' pour la coupure ",Nat.LOG_DEBUG);
		gestErreur.afficheMessage("\n** Dev : Utilisation de '"+ carSpec[1] +"' pour la coupure esthétique en mathématique ",Nat.LOG_DEBUG);
		gestErreur.afficheMessage("\n** Dev : Utilisation de '"+ carSpec[2] +"' pour début d'expression mathématique ",Nat.LOG_DEBUG);
		gestErreur.afficheMessage("\n** Dev : Utilisation de '"+ carSpec[3] +"' pour fin d'expression mathématique ",Nat.LOG_DEBUG);
		gestErreur.afficheMessage("\n** Dev : Utilisation de '"+ carSpec[4] +"' pour l'espace insécable à générer ",Nat.LOG_DEBUG);
		gestErreur.afficheMessage("\n** Dev : Utilisation de '"+ carSpec[5] +"' pour l'espace sécable à générer ",Nat.LOG_DEBUG);
		gestErreur.afficheMessage("\n** Dev : utilisation de '"+ carSpec[6] +"' pour début de table ",Nat.LOG_DEBUG);
		gestErreur.afficheMessage("\n** Dev : utilisation de '"+ carSpec[7] +"' pour fin de table ",Nat.LOG_DEBUG);
		gestErreur.afficheMessage("\n** Dev : utilisation de '"+ carSpec[8] +"' pour saut de ligne à générer ",Nat.LOG_DEBUG);
		params.add(fabriqueParam(docParams,"coupe",carSpec[0],"xs:string"));
		params.add(fabriqueParam(docParams,"coupeEsth",carSpec[1],"xs:string"));
		params.add(fabriqueParam(docParams,"debMath",carSpec[2],"xs:string"));
		params.add(fabriqueParam(docParams,"finMath",carSpec[3],"xs:string"));
		params.add(fabriqueParam(docParams,"espace",carSpec[4],"xs:string"));
		params.add(fabriqueParam(docParams,"espaceSecable",carSpec[5],"xs:string"));
		params.add(fabriqueParam(docParams,"debTable",carSpec[6],"xs:string"));
		params.add(fabriqueParam(docParams,"finTable",carSpec[7],"xs:string"));
		params.add(fabriqueParam(docParams,"sautAGenerer",carSpec[8],"xs:string"));
		
		Element e = fabriqueVariable(docParams,"apos","xs:string");
		e.setTextContent("'");
		params.add(e);
		e = fabriqueVariable(docParams,"quot","xs:string");
		e.setTextContent("\"");
		params.add(e);
		params.add(fabriqueVariable(docParams,"carcoup","concat($coupeEsth,$coupe,$debMath,$finMath,$debTable,$finTable)","xs:string"));
		
		//les comptes des rajouts
		Element rajCpt = fabriqueVariable(docParams,"compteRajouts","xs:boolean*");
		//la séquence pour les comptes des rajouts
		Element seqRajCpt = docParams.createElement("xsl:sequence");
		String seqRajString = ConfigNat.getCurrentConfig().getRajoutCompte();
		seqRajString = seqRajString.replaceAll(",", "(),")+"()";//pour avoir les booléens xsl
		seqRajCpt.setAttribute("select", "("+seqRajString+")");
		rajCpt.appendChild(seqRajCpt);
		params.add(rajCpt);
		
		//les rajouts
		Element raj = fabriqueVariable(docParams,"rajouts","xs:string*");
		//la séquence pour les rajouts
		Element seqRaj = docParams.createElement("xsl:sequence");
		//On double ici les apostrophes et les & pour pas que ça plante la séquence xsl
		//Il n'est pas possible d'avoir une chaine ajout contenant des champs vides car les string.split ne fonctionnent pas sinon
		//On est donc obligé d'encadrer dès maintenant les champs par des ''
		//ex: ajouts="'','','','','','a','b','c','d'" et pas ajouts=",,,,,,a,b,c,d"
		
		String [] tabSeqRaj =  ConfigNat.intelliSplit(ConfigNat.getCurrentConfig().getRajout(),",");
		String strSeqRaj="";
		for(int i=0;i<tabSeqRaj.length;i++)
		{
			strSeqRaj = strSeqRaj + "'" +tabSeqRaj[i].substring(1,tabSeqRaj[i].length()-1 ).replaceAll("'", "''") +"',";
		}
		seqRaj.setAttribute("select", "("+strSeqRaj.substring(0,strSeqRaj.length()-1)+")");
		raj.appendChild(seqRaj);
		params.add(raj);
		
		//ajout des parametres
	    for(int i=0; i< params.size();i++){racine.appendChild(params.get(i));}		    
	    docParams.appendChild(racine);		    
	    /* Sauvegarde de document dans un fichier */
        Source source = new DOMSource(docParams);
        
        // Création du fichier de sortie
        File f = new File(fic_paramsAll);
        Result resultat = new StreamResult(f);
        
        // Configuration du transformer
        TransformerFactory tfabrique = TransformerFactory.newInstance();
        Transformer transformer = tfabrique.newTransformer();
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");  
        transformer.setOutputProperty(OutputKeys.VERSION, "1.1");
        transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, ConfigNat.getCurrentConfig().getDTD());
        // Transformation
        transformer.transform(source, resultat);
	}
	
	/**
	 * Fabrique le fichier paramsMEP.xsl contenant les valeurs des éléments de configuration et de paramétrage
	 * utilisés uniquement pour la mise en page
	 * @param gestErreur Une instance de GestionnaireErreur
	 * @throws ParserConfigurationException erreur de parsage
	 * @throws TransformerException erreur lors de la transformation
	 */
	private void createParamMEP(GestionnaireErreur gestErreur) throws ParserConfigurationException, TransformerException
	{
		DocumentBuilderFactory fabrique = DocumentBuilderFactory.newInstance();
		DocumentBuilder constructeur= fabrique.newDocumentBuilder();
	    Document docParams = constructeur.newDocument();
	    // Propriétés de docParam
	    docParams.setXmlVersion("1.1");
	    docParams.setXmlStandalone(true);
	    
	    //racine
	    Element racine = docParams.createElement("xsl:stylesheet");
	    racine.setAttribute("version", "2.0");
	    racine.setAttribute("xmlns:xsl", "http://www.w3.org/1999/XSL/Transform");
	    racine.setAttribute("xmlns:xs","http://www.w3.org/2001/XMLSchema");
	    racine.appendChild(docParams.createComment("Auto-generated file; see Transcodeur.java"));
	    racine.appendChild(docParams.createComment(Nat.getLicence("", "")));
	    //paramètres
	    ArrayList<Element> params = new ArrayList<Element>();
	    params.add(fabriqueParam(docParams,"numerosDePage",ConfigNat.getCurrentConfig().getNumerotation(),"xs:string"));
	    params.add(fabriqueParam(docParams,"numberFirstPage",ConfigNat.getCurrentConfig().getNumeroteFirst()+"()","xs:boolean"));
	    params.add(fabriqueParam(docParams,"couplit",ConfigNat.getCurrentConfig().getCoupureLit()+"()","xs:boolean"));
	    params.add(fabriqueParam(docParams,"sagouin",ConfigNat.getCurrentConfig().getModeCoupureSagouin()+"()","xs:boolean"));
		params.add(fabriqueParam(docParams,"modeLigneVide",ConfigNat.getCurrentConfig().getMepModelignes()+"","xs:integer"));
		params.add(fabriqueParam(docParams,"min1ligne",ConfigNat.getCurrentConfig().getMepMinLigne1()+"","xs:integer"));
		params.add(fabriqueParam(docParams,"min2ligne",ConfigNat.getCurrentConfig().getMepMinLigne2()+"","xs:integer"));
		params.add(fabriqueParam(docParams,"min3ligne",ConfigNat.getCurrentConfig().getMepMinLigne3()+"","xs:integer"));
		params.add(fabriqueParam(docParams,"minPageBreak",ConfigNat.getCurrentConfig().getMepMinLignePB()+"","xs:integer"));
		params.add(fabriqueParam(docParams,"lignesParPage",ConfigNat.getCurrentConfig().getNbLigne()+"","xs:integer"));
		params.add(fabriqueParam(docParams,"formFeedEnd",ConfigNat.getCurrentConfig().getSautPageFin()+"()","xs:boolean"));
		params.add(fabriqueParam(docParams,"generatePageBreak",ConfigNat.getCurrentConfig().getGeneratePB()+"()","xs:boolean"));
		//ajout des parametres
	    for(int i=0; i< params.size();i++){racine.appendChild(params.get(i));}		    
	    docParams.appendChild(racine);		    
	    /* Sauvegarde de document dans un fichier */
        Source source = new DOMSource(docParams);
        
        // Création du fichier de sortie
        File f = new File(fic_paramsMEP);
        Result resultat = new StreamResult(f);
        
        // Configuration du transformer
        TransformerFactory tfabrique = TransformerFactory.newInstance();
        Transformer transformer = tfabrique.newTransformer();
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");  
        transformer.setOutputProperty(OutputKeys.VERSION, "1.1");
        transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, ConfigNat.getCurrentConfig().getDTD());
        // Transformation
        transformer.transform(source, resultat);
	}
	
	/**
	 * Fabrique le fichier paramsTrans.xsl contenant les valeurs des éléments de configuration et de paramétrage
	 * utilisés pour la première passe de la transcription
	 * @param gestErreur Une instance de GestionnaireErreur
	 * @throws ParserConfigurationException erreur de parsage
	 * @throws TransformerException erreur lors de la transformation
	 */
	private void createParamTrans(GestionnaireErreur gestErreur) throws ParserConfigurationException, TransformerException
	{
		DocumentBuilderFactory fabrique = DocumentBuilderFactory.newInstance();
		DocumentBuilder constructeur= fabrique.newDocumentBuilder();
	    Document docParams = constructeur.newDocument();
	    // Propriétés de docParam
	    docParams.setXmlVersion("1.1");
	    docParams.setXmlStandalone(true);
	    
	    //racine
	    Element racine = docParams.createElement("xsl:stylesheet");
	    racine.setAttribute("version", "2.0");
	    racine.setAttribute("xmlns:xsl", "http://www.w3.org/1999/XSL/Transform");
	    racine.setAttribute("xmlns:xs","http://www.w3.org/2001/XMLSchema");
	    racine.appendChild(docParams.createComment("Auto-generated file; see Transcodeur.java"));
	    racine.appendChild(docParams.createComment(Nat.getLicence("", "")));
	    //paramètres
	    ArrayList<Element> params = new ArrayList<Element>();
	    params.add(fabriqueParam(docParams,"abrege",ConfigNat.getCurrentConfig().getAbreger()+"()","xs:boolean"));
	    params.add(fabriqueParam(docParams,"trigoSpecif",ConfigNat.getCurrentConfig().getMathTrigoSpec()+"()","xs:boolean"));
	    params.add(fabriqueParam(docParams,"cp_2",ConfigNat.getCurrentConfig().getLitMajDouble()+"()","xs:boolean"));
	    params.add(fabriqueParam(docParams,"cp_part",ConfigNat.getCurrentConfig().getLitMajPassage()+"()","xs:boolean"));
	    params.add(fabriqueParam(docParams,"cp_mix",ConfigNat.getCurrentConfig().getLitMajMelange()+"()","xs:boolean"));
	    params.add(fabriqueParam(docParams,"emph_w",ConfigNat.getCurrentConfig().getLitEvidenceMot()+"()","xs:boolean"));
	    params.add(fabriqueParam(docParams,"emph_mix",ConfigNat.getCurrentConfig().getLitEvidenceDansMot()+"()","xs:boolean"));
	    params.add(fabriqueParam(docParams,"emph_part",ConfigNat.getCurrentConfig().getLitEvidencePassage()+"()","xs:boolean"));
	    params.add(fabriqueParam(docParams,"min_cell_lin",ConfigNat.getCurrentConfig().getMinCellLin()+"","xs:integer"));
		params.add(fabriqueParam(docParams,"linearise_table",ConfigNat.getCurrentConfig().getLineariseTable()+"()","xs:boolean"));
		params.add(fabriqueParam(docParams,"forceMathPrefix",ConfigNat.getCurrentConfig().getMathPrefixAlways()+"()","xs:boolean"));
		params.add(fabriqueParam(docParams,"minTitleAbr",""+ConfigNat.getCurrentConfig().getNiveauTitreAbrege(),"xs:integer"));
		/*
		 * TODO on les mets où ces rajouts finalement?
		 */
		/*
		//les comptes des rajouts
		Element rajCpt = fabriqueVariable(docParams,"compteRajouts","xs:boolean*");
		//la séquence pour les comptes des rajouts
		Element seqRajCpt = docParams.createElement("xsl:sequence");
		String seqRajString = ConfigNat.getCurrentConfig().getRajoutCompte();
		seqRajString = seqRajString.replaceAll(",", "(),")+"()";//pour avoir les booléens xsl
		seqRajCpt.setAttribute("select", "("+seqRajString+")");
		rajCpt.appendChild(seqRajCpt);
		params.add(rajCpt);
		
		//les rajouts
		Element raj = fabriqueVariable(docParams,"rajouts","xs:string*");
		//la séquence pour les rajouts
		Element seqRaj = docParams.createElement("xsl:sequence");
		// TODO prévoir de formater la séquence (&apos et le reste)
		//On double ici les apostrophes et les & pour pas que ça plante la séquence xsl
		//Il n'est pas possible d'avoir une chaine ajout contenant des champs vides car les string.split ne fonctionnent pas sinon
		//On est donc obligé d'encadrer dès maintenant les champs par des ''
		//ex: ajouts="'','','','','','a','b','c','d'" et pas ajouts=",,,,,,a,b,c,d"
		*/

		/*
		//		String [] tabSeqRaj =  ConfigNat.getCurrentConfig().getRajout().split(",");

		
		/// ---------> 
		String[] tabSeqRaj = ConfigNat.intelliSplit(ConfigNat.getCurrentConfig().getRajout(),",");

		String strSeqRaj="";
		for(int i=0;i<tabSeqRaj.length;i++)
		{
			strSeqRaj = strSeqRaj + "'" +tabSeqRaj[i].substring(1,tabSeqRaj[i].length()-1 ).replaceAll("'", "''") +"',";
		}
		seqRaj.setAttribute("select", "("+strSeqRaj.substring(0,strSeqRaj.length()-1)+")");
		raj.appendChild(seqRaj);
		params.add(raj);
		*/
		
		/*
		 * variables
		 */
		//les titres
		Element titre = fabriqueVariable(docParams,"listeTitres","xs:integer*");
		//la séquence pour les titres
		Element sequence = docParams.createElement("xsl:sequence");
		sequence.setAttribute("select", "("+ConfigNat.getCurrentConfig().getNiveauxTitres()+")");
		titre.appendChild(sequence);
		params.add(titre);
		
		//ajout des parametres
	    for(int i=0; i< params.size();i++){racine.appendChild(params.get(i));}		    
	    docParams.appendChild(racine);		    
	    /* Sauvegarde de document dans un fichier */
        Source source = new DOMSource(docParams);
        
        // Création du fichier de sortie
        File f = new File(fic_paramsTrans);
        Result resultat = new StreamResult(f);
        
        // Configuration du transformer
        TransformerFactory tfabrique = TransformerFactory.newInstance();
        Transformer transformer = tfabrique.newTransformer();
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");  
        transformer.setOutputProperty(OutputKeys.VERSION, "1.1");
        transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, ConfigNat.getCurrentConfig().getDTD());
        // Transformation
        transformer.transform(source, resultat);
	}

	/**
	 * Fabrique une variable de nom nom et de type type pour le document doc
	 * @param doc le document xml
	 * @param nom le nom de la variable
	 * @param type le type de la variable
	 * @return l'element variable
	 */
	private Element fabriqueVariable(Document doc, String nom, String type)
	{
		Element e = doc.createElement("xsl:variable");
	    e.setAttribute("name", nom);
	    e.setAttribute("as", type);
		return e;
	}
	/**
	 * Fabrique une variable de nom nom et de type type pour le document doc contenant la valeur valeur
	 * @param doc le document xml
	 * @param nom le nom de la variable
	 * @param valeur valeur de la variable
	 * @param type le type de la variable
	 * @return l'element variable
	 */
	private Element fabriqueVariable(Document doc, String nom, String valeur, String type)
	{
		Element e = doc.createElement("xsl:variable");
	    e.setAttribute("name", nom);
	    e.setAttribute("as", type);
	    e.setAttribute("select", valeur);
		return e;
	}

	/**
	 * Fabrique un paramètre de nom nom et de type type pour le document doc contenant la valeur valeur
	 * @param doc le document xml
	 * @param nom le nom de la paramètre
	 * @param valeur valeur de la paramètre
	 * @param type le type de la paramètre
	 * @return l'element paramètre
	 */
	private Element fabriqueParam(Document doc, String nom, String valeur, String type)
	{
		Element e = doc.createElement("xsl:param");
	    e.setAttribute("name", nom);
	    e.setAttribute("as", type);
	    e.setAttribute("select", valeur);
		return e;
	}

	/**
	 * Réalise la transcription du fichier d'entrée vers le fichier de sortie en utilisant
	 * le filtre xsl
	 * @param	gestErreur	Un objet <code>GestionnaireErreur</code> pour l'affichage et la gestion
	 * des improbables erreurs.
	 * @return true si la transcription s'est bien passée
	 */
	@Override 
	public boolean transcrire(GestionnaireErreur gestErreur)
	{
		boolean retour = true;
		tempsExecution = System.currentTimeMillis();
		//Exception exception = null;
		gestErreur.afficheMessage("\nDébut du transcodage ... ok\n",Nat.LOG_SILENCIEUX);
		gestErreur.afficheMessage("** Fichiers :\n Fichier d'entree:" + entree + "\n Filtre :" + filtre,Nat.LOG_VERBEUX);
		gestErreur.afficheMessage("\n** Mise en place du scénario de transcription...",Nat.LOG_VERBEUX);
		creerFiltres(gestErreur);
		gestErreur.afficheMessage("ok\n** Création de la fabrique (DocumentBuilderFactory) ...",Nat.LOG_VERBEUX);
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		//configuration de la fabrique
		factory.setNamespaceAware(true);
		//factory.setValidating(true);
		factory.setValidating(ConfigNat.getCurrentConfig().getNiveauLog()==Nat.LOG_DEBUG);
		factory.setIgnoringElementContentWhitespace(true);
		factory.setIgnoringComments(true);
		factory.setIgnoringElementContentWhitespace(false);
		try 
		{
			//sinon, génère parfois des null pointer exp au parsage (problème avec les simples quote)
			factory.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", false);
			DocumentBuilder builder = factory.newDocumentBuilder();
			gestErreur.afficheMessage("ok\n** Parsage du document d'entrée avec SAX ...",Nat.LOG_VERBEUX);
			builder.setErrorHandler(gestErreur);
			gest.afficheMessage("\nEntree :"+entree+";filtre :"+filtre+";",Nat.LOG_VERBEUX);
			Document doc = builder.parse(new File(entree));//FileInputStream(entree));//,"UTF-8")); //(new File(entree));
			doc.setStrictErrorChecking(true);
			gestErreur.afficheMessage("ok\n** Initialisation et lecture de la feuille de style ...",Nat.LOG_VERBEUX);
			TransformerFactory transformFactory = new TransformerFactoryImpl();//TransformerFactory.newInstance();
			StreamSource styleSource = new StreamSource(new File(filtre));
			// lire le style
			
			Transformer transform = transformFactory.newTransformer(styleSource);
			//transform.setOutputProperty(name, value)
			// conformer le transformeur au style
			DOMSource in = new DOMSource(doc);
			gestErreur.afficheMessage("ok\n** Création du fichier de sortie ...",Nat.LOG_VERBEUX);
			// Création du fichier de sortie
			File file = new File(cible);
			///Result resultat = new StreamResult(fichier);
			StreamResult out = new StreamResult(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file),"UTF-8")));
			gestErreur.afficheMessage("ok\n** Transformation du document ...",Nat.LOG_VERBEUX);
			//transform.setParameter("abrege",abrege);
			transform.transform(in, out);

			/*
			 * Transcription des images
			 */
			if(ConfigNat.getCurrentConfig().getTranscrireImages())
			{
				//lecture des images contenues dans le dossier d'images
				gestErreur.afficheMessage("ok\n** Récupération des images ...",Nat.LOG_VERBEUX);
				File repertoire =new File(ConfigNat.getUserTempFolder()+"tmp.xhtml-img");
				if(repertoire.isDirectory())
				{
					
					File[] listImages = repertoire.listFiles();
					for(File f : listImages)
					{
						try
						{
							//conversion du fichier en brf
							IMOperation op = new IMOperation();
							String from = f.getAbsolutePath();
							String to = from+".brf";
							String fichOut = to;
							//System.out.println(System.getProperty("os.name"));
							/*if(System.getProperty("os.name").startsWith("Windows"))
							{
								from = "\""+from+"\"";
								to = "\""+to+"\"";
							}*/
						    op.addImage(from);
						    op.resize(ConfigNat.getCurrentConfig().getLongueurLigne()*2,(ConfigNat.getCurrentConfig().getNbLigne()-1)*3);
						    op.encoding("UTF-8");
						    op.addImage(to);
						    //op.addImage("myimage-small.brf");
						    ConvertCmd convert = new ConvertCmd();
						    convert.run(op);
						    //remplacement des & et des < par des entités
						    FileToolKit.saveStrToFile(FileToolKit.loadFileToStr(to).replaceAll("&", "&amp;").replaceAll("<", "&lt;"),to);
						    //conversion de la table US vers la table utf8
						    String tablePath = ConfigNat.getInstallFolder()+"xsl/tablesEmbosseuse/brailleUTF8.ent";
						    
						    FileToolKit.convertBrailleFile(fichOut, fichOut, ConfigNat.getInstallFolder()+"xsl/tablesBraille/CodeUS.ent",
						    		tablePath, gest);
						}
						catch (CommandException ce)
						{
							String message = "Avez-vous installé Image Magick?";
							if(ConfigNat.getCurrentConfig().getImageMagickDir().equals("")&&System.getProperty("os.name").startsWith("Windows"))
							{
								message = "Indiquez dans les options de transcription ou dans la variable d'environnement IMAGEMAGICK_HOME " +
										"le chemin du répertoire d'installation d'Image Magick";
							}
							gest.afficheMessage("\n** nOK: Impossible de convertir l'image " + f.getName() +
									"\n" + message, Nat.LOG_SILENCIEUX);
							ce.printStackTrace();
						}
					}
				}
			}
			tempsExecution = System.currentTimeMillis() - tempsExecution;
		}
		catch (Exception e)  
		{
			gestErreur.setException(e);
			gestErreur.gestionErreur();
			retour = false;
		}
		return retour;
	}
	/** 
	 * <p>Depuis 2.0, commence à partir la recherche à partir de \u2D30 
	 * (alphabet berbère, http://fr.wikipedia.org/wiki/Alphabet_berb%C3%A8re)</p>
	 * <p>Avant, cherchait quels étaient les nb premiers caractères non utilisés dans la table braille pour s'en servir
	 * comme caractères spéciaux;
	 * @param	debut	le code à partir duquel on commence à chercher
	 * @param 	nb nombre de caractères à rechercher 
	 * @param	gestErreur	Un objet <code>GestionnaireErreur</code> pour l'affichage et la gestion
	 * des improbables erreurs.
	 * @return les nb premiers caractères disponibles, rendus sous forme de String[]
	 */
	private String[] donneCharNonUtilise(int debut, int nb, GestionnaireErreur gestErreur)
	{
		String[] retour = new String[nb];
		gestErreur.afficheMessage("\n** Recherche de " + nb +" caractères non utilisés...",Nat.LOG_VERBEUX);
		/*ArrayList<String> donnees = new ArrayList<String>();
		try
		{
	      RandomAccessFile raf = new RandomAccessFile("./xsl/tablesBraille/Brltab.", "r");
	      String ligne;
	      String[] enregistrement;
	      int i=1;
	      
	      ligne = raf.readLine();
	      //on cherche le début des entitées
	      while(!ligne.startsWith("<!ENTITY") && ligne!=null){ ligne = raf.readLine();}
	      if (ligne==null){gestErreur.afficheMessage("\n*** Erreur: Table Braille non valide\n",Nat.LOG_SILENCIEUX);}
	      else
	      {
	    	  enregistrement = ligne.split(" ");
	
	    	  /*if(!enregistrement[2].startsWith("\"&#"))
	    	  {
	    		  if (enregistrement[2].startsWith("\"&apos;")){donnees.add("39");}
	    		  else if (enregistrement[2].startsWith("\"&quot;")){donnees.add("34");}
	    		  else if (enregistrement[2].startsWith("\"&lt;")){donnees.add("60");}
	    		  else if (enregistrement[2].startsWith("\"&gt;")){donnees.add("62");}
	    		  else{donnees.add("38");}
	    	  }
	    	  else{donnees.add(enregistrement[2].substring(3, enregistrement[2].length()-3));}
	    	  *
	    	  if(enregistrement[2].startsWith("\"&#")){donnees.add(enregistrement[2].substring(3, enregistrement[2].length()-3));}
		      while ( (ligne = raf.readLine()) != null)
			  	{
		    	  enregistrement = ligne.split(" ");
		    		
		    	  /*if(!enregistrement[2].startsWith("\"&#"))
		    	  {
		    		  if (enregistrement[2].startsWith("\"&apos;")){donnees.add("39");}
		    		  else if (enregistrement[2].startsWith("\"&quot;")){donnees.add("34");}
		    		  else if (enregistrement[2].startsWith("\"&lt;")){donnees.add("60");}
		    		  else if (enregistrement[2].startsWith("\"&gt;")){donnees.add("62");}
		    		  else{donnees.add("38");}
		    	  }
		    	  else{donnees.add(enregistrement[2].substring(3, enregistrement[2].length()-3));}
		    	  *
		    	  if(enregistrement[2].startsWith("\"&#"))
		    	  {
		    		  donnees.add(enregistrement[2].substring(3, enregistrement[2].length()-3));
		    	  }
		    	  i++;
		  	    }
	      }
	      raf.close();
	      //ajout des caractères interdits
	      donnees.add("34");//"
	      donnees.add("39");//'
	      donnees.add("38");//&
	      donnees.add("60");//<
	      donnees.add("63");//
		  donnees.add("36");//$ des regex
		  donnees.add("46");//. des regex
		  donnees.add("94");//^ des regex
	      i=debut;
	      int j=0;
	      while(j<nb)
	      {
	    	  retour[j]=Integer.toString(i);
	    	  if(!donnees.contains(retour[j]))
	    	  {
	    		  retour[j] = "'" + (char)(i)+"'";
	    		  gestErreur.afficheMessage("\n    trouvé: '"+ retour[j] +"'("+i+") ",Nat.LOG_VERBEUX);
	    		  j++;
	    	  }
	    	  i++;
	      }
		}
		catch (IOException e){gestErreur.afficheMessage("\n *** Erreur d'entrée/sortie lors du chargement de la table braille", Nat.LOG_SILENCIEUX);}
		catch (NumberFormatException e){gestErreur.afficheMessage("\n *** La table Braille n'est pas valide: " + e, Nat.LOG_SILENCIEUX);}
		*/
		int j=0;
		while(j<nb)
		{
			retour[j]="'"+(char)('\u2D30'+j)+"'";
			gestErreur.afficheMessage("\n    trouvé: '"+ retour[j] +"'("+j+") ",Nat.LOG_VERBEUX);
  		  	j++;
		}
		return retour;
	}
}