/*
 * 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 ui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.File;
import java.io.StringWriter;
import java.util.ArrayList;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
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 org.w3c.dom.Document;
import org.w3c.dom.Element;

import nat.ConfigNat;
import nat.Transcription;
import net.sf.saxon.Controller;
import net.sf.saxon.event.Emitter;
import net.sf.saxon.event.MessageEmitter;

import outils.HyphenationToolkit;
/**
 * Fenêtre d'édition et de visualisation des règles de coupure.
 * <p>Propose essentiellement une interface utilisateurs pour utiliser les fonctionnalités
 * de {@link outils.HyphenationToolkit}</p>
 * @author bruno
 * @since 2.0
 * @see outils.HyphenationToolkit
 */
public class ConfDictCoup extends JFrame implements ActionListener,ItemListener
{
	/** Pour la sérialisation (non utilisé) */
	private static final long serialVersionUID = 1L;
	/** JTable contenant les règles */ 
	private JTable table;
	/** Modèle pour la table */
	private TableModeleCoup tm;
	/** ScrollPane de la table*/
	JScrollPane jsp;
	/** Label contenant l'adresse et la description du dictionnaire */
	private JLabel lDico;
	/** adresse du dictionnaire */
	private String dicoName;
	/** bouton pour charger un nouveau dictionnaire */
	private JButton btOuvrir = new JButton("<html><center><u>C</u>harger un autre<br>dictionnaire</center></html>",new ImageIcon("ui/icon/document-open.png"));
	/** bouton pour créer un nouveau dictionnaire vierge*/
	private JButton btNouveau = new JButton("<html><center>Créer un nouveau<br>dicyionnaire <u>v</u>ierge</center></html>",new ImageIcon("ui/icon/document-new.png"));
	/** bouton lançant la vérification le test de coupure sur le contenu de {@link #jtfTest}*/
	private JButton btVerif = new JButton("Tester", new ImageIcon("ui/icon/applications-development.png"));
	/** bouton enregistrant le dictionnaire*/
	private JButton btEnregistrer = new JButton("Enregistrer",new ImageIcon("ui/icon/document-save.png"));
	/** bouton enregistrant le dictionnaire sous un nouveau nom*/
	private JButton btEnregistrerSous = new JButton("Enregistrer sous...",new ImageIcon("ui/icon/document-save-as.png"));
	/** bouton annulant les changements et fermant la fenêtre*/
	private JButton btAnnuler = new JButton("Quitter",new ImageIcon("ui/icon/exit.png"));
	/** bouton supprimant les règles sélectionnées*/
	private JButton btSupprRegle = new JButton("<html><center>Su<u>p</u>primer les règles<br>sélectionnées</center></html>",new ImageIcon("ui/icon/list-remove.png"));
	/** bouton ajoutant une règle en fin de table*/
	private JButton btAjoutRegle = new JButton("<html><center><u>A</u>jouter<br>une règle</center></html>", new ImageIcon("ui/icon/list-add.png"));
	/** bouton enregistrant le dictionnaire*/
	
	/** JTextField contenant la chaine à tester */
	private JTextField jtfTest = new JTextField(17);
	/** JTextArea contenant le déroulement du test de coupure */
	private JTextArea jtaReponse = new JTextArea(10,35);
	/** Label pour {@link #jtaReponse}*/
	private JLabel lJtaReponse = new JLabel("Détails du test:");
	/** JTextArea contenant le résultat du test de coupure */
	private JTextField jtfReponse = new JTextField(17);
	/** JLabel aide à la saisie*/
	private JLabel lAide = new JLabel("<html><b>Rappels sur les règles (consultez l'aide):</b>" +
			"<ul><li>1 ou 3 indique une césure possible;</li>" +
			"<li>2 ou 4 indique une césure interdite;</li>" +
			"<li>à la fin, seul le nombre le plus élevé est retenu</li>" +
			"<li>l'apostrophe est automatiquement doublée.</li>" +
			"<li>sel. sélectionne les lignes pour suppression</li></ul></html>");
	/** JCheckBox affichant les détails du test de coupure */
	private JCheckBox jcbDetailCoup = new JCheckBox("détails");
	/** indique si des modifications n'ont pas été enregistrées*/
	private boolean modif = false;
	/** 
	 * Constructeur 
	 * <p>Initialise les éléments d'interface graphique et construit la page</p>
	 * <p>Récupère notamment les règles de coupure en utilisant {@link outils.HyphenationToolkit#getRules(String)}
	 */
	public ConfDictCoup()
	{
		super("Edition du dictionnaire des règles de coupure");
		//setResizable(false);
		
		Object[][] donnees;
		if(!(new File(ConfigNat.getCurrentConfig().getDicoCoup()).exists()))
		{
			JOptionPane.showMessageDialog(this,"<html><b>Dictionnaire introuvable</b><br>" +
					"Le dictionnaire <i>" + ConfigNat.getCurrentConfig().getDicoCoup() +
					" </i><br>est introuvable.<br>Utilisation du dictionnaire par défaut<br>" +
					"<b>Pensez à enregistrer ce nouveau dictionnaire si vous souhaitez l'utiliser.</b></html>",
					"Dictionnaire introuvable",JOptionPane.ERROR_MESSAGE);
			donnees = creerDonneesTable(ConfigNat.getDicoCoupDefaut());
		}
		else{donnees = creerDonneesTable(ConfigNat.getCurrentConfig().getDicoCoup());}
		//table = new JTable(donnees, lesColonnes);
		tm = new TableModeleCoup(donnees);
		table = new JTable(tm);
		table.setAutoCreateRowSorter(true);
		//bug de sun pour la maj de la table
		table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
		
		//taille des colonnes
		TableColumnModel modelesColonnes = table.getColumnModel();
        TableColumn modelColonne = modelesColonnes.getColumn(0);
        modelColonne.setMaxWidth(50);
        modelColonne.setMinWidth(50);
        modelColonne =  modelesColonnes.getColumn(1);
        modelColonne.setMaxWidth(100);
        modelColonne.setMinWidth(50);
        modelColonne =  modelesColonnes.getColumn(2);
        modelColonne.setMinWidth(100);
        modelColonne =  modelesColonnes.getColumn(3);
        modelColonne.setMaxWidth(100);
        modelColonne.setMinWidth(50);
        modelColonne =  modelesColonnes.getColumn(4);
        modelColonne.setMaxWidth(50);
        modelColonne.setMinWidth(50);
        
        table.setToolTipText("Tableau des règles de coupures");
        table.getAccessibleContext().setAccessibleName("Tableau des règles de coupures");
        table.getAccessibleContext().setAccessibleDescription("Cette table est composée de 5 colonnes: " +
        	"numéro de la règle (non éditable), case à cocher indiquant si la règle s'applique en début de mot," +
        	" motif de la règle, case à cocher indiquant si la règle s'applique en fin de mot, " +
        	"case à cocher sélectionner la règle.");
        /*AccessibleTable at = table.getAccessibleContext().getAccessibleTable();
        at.getAccessibleCaption().getAccessibleContext().setAccessibleName("Table des règles de coupure");
        at.getAccessibleCaption().getAccessibleContext().setAccessibleDescription("Cette table est composée de 5 colonnes: " +
        	"numéro de la règle (non éditable), case à cocher indiquant si la règle s'applique en début de mot," +
        	" motif de la règle, case à cocher indiquant si la règle s'applique en fin de mot, " +
        	"case à cocher sélectionner la règle.");*/
        /*
        at.getAccessibleColumnDescription(0).getAccessibleContext().setAccessibleName("Numéro de la règle");
        at.getAccessibleColumnDescription(0).getAccessibleContext().setAccessibleDescription("Numéro de la règle, non éditable, correspond à la ligne dans le fichier de règles");
        at.getAccessibleColumnDescription(1).getAccessibleContext().setAccessibleName("Règle en début");
        at.getAccessibleColumnDescription(1).getAccessibleContext().setAccessibleDescription("Cocher la case pour indiquer que la règle s'applique en début de mot");
        at.getAccessibleColumnDescription(2).getAccessibleContext().setAccessibleName("Motif de la règle");
        at.getAccessibleColumnDescription(2).getAccessibleContext().setAccessibleDescription("Le motif de la règle, avec les coupures possibles ou interdites");
        at.getAccessibleColumnDescription(3).getAccessibleContext().setAccessibleName("Règle en fin");
        at.getAccessibleColumnDescription(3).getAccessibleContext().setAccessibleDescription("Cocher la case pour indiquer que la règle s'applique en fin de mot");
        at.getAccessibleColumnDescription(4).getAccessibleContext().setAccessibleName("Sélectionner la règle");
        at.getAccessibleColumnDescription(4).getAccessibleContext().setAccessibleDescription("Coher la case pour sélectionner la règle (en vue d'une suppression)");
        */
        // srollpane pour la table
		jsp = new JScrollPane (table);
		jsp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		jsp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
		jsp.setMinimumSize(new Dimension(300,400));
		
		/* Labels de la fenêtre *************/
		dicoName=ConfigNat.getCurrentConfig().getDicoCoup();
		String commentaire = "";
		if(ConfigNat.getCurrentConfig().getIsSysConfig()){commentaire=" (<font color=\"red\">non éditable avec cette configuration système</font>)";}
		lDico =  new JLabel("<html>Dictionnaire utilisé:<h3><i>"+ dicoName+
				"</i>" + commentaire +"</h3></html>");
		
		//JLabel lRegles = new JLabel(table.getRowCount() + " règles");
		
		/* panneau de test*********/
		JLabel lJtfTest = new JLabel("Mot:");
		lJtfTest.setLabelFor(jtfTest);
		lJtfTest.setDisplayedMnemonic('m');
		lJtfTest.setDisplayedMnemonicIndex(0);
		
		jtfTest.getAccessibleContext().setAccessibleName("Mot à tester");
		jtfTest.getAccessibleContext().setAccessibleDescription("Entrez le mot à tester");
		jtfTest.setToolTipText("Mot à tester (alt+m)");
		
		JLabel lReponse = new JLabel("Résultat:");
		lReponse.setLabelFor(jtfReponse);
		lReponse.setDisplayedMnemonic('r');
		lJtfTest.setDisplayedMnemonicIndex(0);
		
		jtfReponse.getAccessibleContext().setAccessibleName("Résultat du test");
		jtfReponse.getAccessibleContext().setAccessibleDescription("Zone non éditable, les tirets représentent les coupures possibles");
		jtfReponse.setToolTipText("Résultat du test (alt+r)");
		
		JScrollPane jsPres = new JScrollPane (jtaReponse);
		jsPres.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		jsPres.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
		
		jcbDetailCoup.addItemListener(this);
		jcbDetailCoup.setMnemonic('d');
		jcbDetailCoup.getAccessibleContext().setAccessibleName("Détail sur le test de coupure");
		jcbDetailCoup.getAccessibleContext().setAccessibleDescription("Pour afficher les détails sur le test de coupure");
		jcbDetailCoup.setToolTipText("Pour afficher les détails du test (alt+d)");
		
		btVerif.addActionListener(this);
		btVerif.getAccessibleContext().setAccessibleName("Lancer le test");
		btVerif.getAccessibleContext().setAccessibleDescription("Test de coupure sur un ou plusieurs mots");
		btVerif.setMnemonic('t');
		btVerif.setToolTipText("Lance le test de coupure");
		
		lJtaReponse.setDisplayedMnemonic('l');
		lJtaReponse.setLabelFor(jtaReponse);
		
		jtaReponse.getAccessibleContext().setAccessibleName("détails du test de coupure");
		jtaReponse.getAccessibleContext().setAccessibleDescription("zone de texte contenant les détails du test; " +
				"pour chaque règle utilisée sont donnés le numéro et le résultat obtenu sur le mot");
		jtaReponse.setToolTipText("détails du test; " +
				"pour chaque règle utilisée sont donnés le numéro et le résultat obtenu sur le mot (alt+l)");
		
		jtaReponse.setEditable(false);
		jtfReponse.setEditable(false);
		lJtaReponse.setEnabled(false);
		
		/* Panneau des boutons ******************/
		btOuvrir.addActionListener(this);
		btOuvrir.getAccessibleContext().setAccessibleName("Charger un nouveau dictionnaire");
		btOuvrir.getAccessibleContext().setAccessibleDescription("Charge un autre dictionnaire dans la table de coupure");
		btOuvrir.setMnemonic('c');
		btOuvrir.setToolTipText("Charge un autre dictionnaire dans la table de coupure (alt+c)");
		
		btNouveau.addActionListener(this);
		btNouveau.getAccessibleContext().setAccessibleName("Charger un dictionnaire vierge");
		btNouveau.getAccessibleContext().setAccessibleDescription("Charge un dictionnaire vierge dans la table de coupure");
		btNouveau.setMnemonic('v');
		btNouveau.setToolTipText("Charge un dictionnaire vierge dans la table de coupure (alt+v)");
		
		btEnregistrer.addActionListener(this);
		btEnregistrer.getAccessibleContext().setAccessibleName("Enregistrer les modifications");
		btEnregistrer.getAccessibleContext().setAccessibleDescription("Sauve les modifications et charge le nouveau dictionnaire dans la configuration");
		btEnregistrer.setMnemonic('s');
		btEnregistrer.setToolTipText("Sauve les modifications et charge le nouveau dictionnaire dans la configuration (alt+s)");
		
		if(ConfigNat.getCurrentConfig().getIsSysConfig())
		{
			btEnregistrer.setEnabled(false);
			btEnregistrerSous.setEnabled(false);
		}
		btEnregistrerSous.addActionListener(this);
		btEnregistrerSous.getAccessibleContext().setAccessibleName("Enregistrer les modifications dans un autre dictionnaire");
		btEnregistrerSous.getAccessibleContext().setAccessibleDescription("Sauve les modifications dans un autre dictionnaire et le charge dans la configuration");
		btEnregistrerSous.setMnemonic('n');
		btEnregistrerSous.setToolTipText("Sauve les modifications dans un autre dictionnaire et le charge dans la configuration (alt+n)");
		
		btAnnuler.addActionListener(this);
		btAnnuler.getAccessibleContext().setAccessibleName("Quitter l'interface");
		btAnnuler.getAccessibleContext().setAccessibleDescription("Ferme la fenêtre de coupure");
		btAnnuler.setMnemonic('q');
		btAnnuler.setDisplayedMnemonicIndex(0);
		btAnnuler.setToolTipText("Ferme la fenêtre de coupure (alt+q)");
		
		btAjoutRegle.addActionListener(this);
		btAjoutRegle.getAccessibleContext().setAccessibleName("Ajouter une règle");
		btAjoutRegle.getAccessibleContext().setAccessibleDescription("Ajoute une règle (une ligne) en fin de table");
		btAjoutRegle.setMnemonic('a');
		btAjoutRegle.setDisplayedMnemonicIndex(0);
		btAjoutRegle.setToolTipText("Ajoute une règle (une ligne) en fin de table (alt+a)");
		
		btSupprRegle.addActionListener(this);
		btSupprRegle.getAccessibleContext().setAccessibleName("Bouton supprimer des règles");
		btSupprRegle.getAccessibleContext().setAccessibleDescription("Supprime les règles (les lignes) sélectionnées dans la table");
		btSupprRegle.setMnemonic('p');
		btSupprRegle.setToolTipText("Supprime les règles (les lignes) sélectionnées dans la table (alt+p)");
		
		/*
		 * Mise en forme
		 */
		GridBagConstraints gbc = new GridBagConstraints();
		gbc.anchor = GridBagConstraints.LINE_START;
		gbc.fill = GridBagConstraints.HORIZONTAL;
		gbc.insets = new Insets(3,3,3,3);
		
		/* panneau de test	 */
		GridBagLayout gblTest = new GridBagLayout();
		JPanel pTest = new JPanel(gblTest);
		pTest.setBorder(BorderFactory.createLineBorder(Color.gray));
		
		gbc.gridx = 0;
		gbc.gridy = 0;
		gbc.gridwidth=1;
		gblTest.setConstraints(lJtfTest, gbc);
		pTest.add(lJtfTest);
		
		gbc.gridx++;
		gblTest.setConstraints(jtfTest, gbc);
		pTest.add(jtfTest);
		
		gbc.gridx++;
		gblTest.setConstraints(btVerif, gbc);
		pTest.add(btVerif);
		
		gbc.gridx++;
		gbc.insets=new Insets(3,30,3,3);
		gblTest.setConstraints(lJtaReponse, gbc);
		pTest.add(lJtaReponse);
		
		gbc.gridy++;
		gbc.insets=new Insets(3,3,3,3);
		gbc.gridheight=2;
		gblTest.setConstraints(jsPres, gbc);
		pTest.add(jsPres);
		
		gbc.gridx = 0;
		gbc.gridheight=1;
		gblTest.setConstraints(lReponse, gbc);
		pTest.add(lReponse);
		
		gbc.gridx++;
		gblTest.setConstraints(jtfReponse, gbc);
		pTest.add(jtfReponse);
		
		gbc.gridx++;
		gblTest.setConstraints(jcbDetailCoup, gbc);
		pTest.add(jcbDetailCoup);
		
		gbc.gridx=0;
		gbc.gridy++;
		gbc.gridwidth=3;
		gblTest.setConstraints(lAide, gbc);
		pTest.add(lAide);
		
		JPanel cp = new JPanel();
		GridBagLayout gbl = new GridBagLayout();
		cp.setLayout(gbl);

		gbc.anchor = GridBagConstraints.LINE_START;
		gbc.fill = GridBagConstraints.HORIZONTAL;
		gbc.gridx = 0;
		gbc.gridy = 0;
		gbc.gridwidth=4;
		gbc.gridheight=1;
		
		gbl.setConstraints(lDico, gbc);
		
		gbc.gridwidth=3;
		gbc.gridy++;
		gbl.setConstraints(pTest, gbc);
		
		gbc.gridy++;
		gbc.gridwidth=2;
		gbl.setConstraints(jsp, gbc);
		
		gbc.gridwidth=1;
		gbc.gridx=2;
		JPanel pBoutons = new JPanel();
		GridBagLayout gblBt = new GridBagLayout();
		pBoutons.setLayout(gblBt);
		gbl.setConstraints(pBoutons, gbc);

		gbc.gridy=0;
		gbc.gridx=0;
		gbc.insets=new Insets(10,3,3,3);
		gblBt.setConstraints(btOuvrir, gbc);
		gbc.gridx++;
		gblBt.setConstraints(btNouveau, gbc);
		gbc.gridy++;
		gbc.gridx=0;
		gbc.insets=new Insets(30,3,3,3);
		gblBt.setConstraints(btAjoutRegle, gbc);
		gbc.gridx++;
		gblBt.setConstraints(btSupprRegle, gbc);
		gbc.gridy++;
		gbc.gridx=0;
		gblBt.setConstraints(btEnregistrer, gbc);
		gbc.gridx++;
		gblBt.setConstraints(btEnregistrerSous, gbc);
		gbc.gridy++;
		gbc.gridx=0;
		gbc.insets=new Insets(5,3,3,3);
		gblBt.setConstraints(btAnnuler, gbc);
			
		//add(lRegles);
		cp.add(lDico);
		cp.add(pTest);
		pBoutons.add(btOuvrir);
		pBoutons.add(btNouveau);
		pBoutons.add(btAjoutRegle);
		pBoutons.add(btSupprRegle);
		pBoutons.add(btEnregistrer);
		pBoutons.add(btEnregistrerSous);
		pBoutons.add(btAnnuler);
		cp.add(pBoutons);
		cp.add(jsp);
		
		//ajout d'un scrollpane aux onglets pour éviter les pb de résolution sur petites résolutions d'écran
		JScrollPane scrollRes = new JScrollPane (cp);
		scrollRes.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
		scrollRes.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
		
		add(scrollRes);
		pack();
		
		//en cas de problèmes avec une résolution trop petite pour la fenêtre
		Dimension dimEcran = Toolkit.getDefaultToolkit().getScreenSize();
		setSize(Math.min(getWidth(), dimEcran.width), Math.min(getHeight(), dimEcran.height));
	}
	/**
	 * Crée les données pour la JTable {@link #table} contenues dans le 
	 * fichier dictionnaire <code>dico</code> 
	 * @param dico adresse du dictionnaire à charger
	 * @return les données pour la table {@link #table}
	 * @see outils.HyphenationToolkit#getRules(String)
	 */
	private Object[][] creerDonneesTable(String dico)
	{
		/* Création de la table *****************/
		ArrayList<String> liste = HyphenationToolkit.getRules(dico);
		Object[][] donnees = new Object[liste.size()][5];
		for(int i=0;i<liste.size();i++)
		{
			Integer indice = new Integer(i+1);
			Boolean deb = new Boolean(false);
			Boolean fin = new Boolean(false);
			String regle = liste.get(i);
			if(regle.startsWith("^"))
			{
				regle = regle.substring(1);
				deb= new Boolean(true);
			}
			if(regle.endsWith("$"))
			{
				regle = regle.substring(0,regle.length()-1);
				fin = new Boolean(true);
			}
			donnees[i][0]=indice;
			donnees[i][1]=deb;
			donnees[i][2]=regle;
			donnees[i][3]=fin;
			donnees[i][4]=new Boolean(false);
		}
		return donnees;
		
	}
	/**
	 * Réalise la coupure de la chaine <code>mot</code> en utilisant
	 * la feuille de style de coupure de nat
	 * @param mot la chaine à couper
	 */
	private void verifie(String mot)
	{
		boolean ok=true;
		if(modif)//il ya des modifications non sauvées
		{
			ok=JOptionPane.showConfirmDialog(this,"<html><b>Attention!</b><br>" +
					"Les modifications n'ont pas été enregistrées!<br>" +
					"Continuer le test?","Modifications non chargées",
					JOptionPane.YES_NO_OPTION)==JOptionPane.OK_OPTION;
		}
		if(ok)
		{
			try 
			{
				//Création du document source
				DocumentBuilderFactory fabrique = DocumentBuilderFactory.newInstance();
				DocumentBuilder constructeur= fabrique.newDocumentBuilder();
			    Document doc = constructeur.newDocument();
			    doc.setXmlVersion("1.1");
			    doc.setXmlStandalone(true);
			    
				Element elem = doc.createElement("word");
				elem.setTextContent(mot);
				doc.appendChild(elem);
				
				//Création du transformeur
				TransformerFactory transformFactory = TransformerFactory.newInstance();
				StreamSource styleSource = new StreamSource(new File(Transcription.xslHyphen));
				// lire le style
				Transformer transform = transformFactory.newTransformer(styleSource);
				transform.setParameter("debug", jcbDetailCoup.isSelected());
				transform.setParameter("brailleHyphen", false);
				
				//configuration de la transformation
				DOMSource in = new DOMSource(doc);
				StringWriter swResu = new StringWriter();
				StreamResult out = new StreamResult(swResu);
				
				//pour récupérer les xsl:message
				Controller control = (Controller)transform;
				control.setMessageEmitter(new MessageEmitter());
				Emitter mesgEm = (Emitter) control.getMessageEmitter();
				
				StringWriter swMesg = new StringWriter();
				mesgEm.setWriter(swMesg);
				
				//transformation
				transform.transform(in, out);
				
				//affichage des résultats
				if(jcbDetailCoup.isSelected()){jtaReponse.setText(swMesg.getBuffer().toString());}
				jtfReponse.setText(swResu.getBuffer().toString());
			}
			catch (NullPointerException e)  
			{
				e.printStackTrace();
			} catch (ParserConfigurationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (TransformerConfigurationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (TransformerException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	/**
	 * Supprime de la JTable <code>table</code>les règles sélectionnées 
	 * <p>Attention: ne met pas à jour le dictionnaire sur le disque!</p>
	 */
	private void supprReglesSel()
	{
		for(int i=0;i<table.getRowCount();i++)
		{
			if(((Boolean)(table.getValueAt(i, 4))).booleanValue())
			{
				tm.removeRow(i);
				i--;//car la ligne vient d'être supprimée!
			}
		}
		
	}
	/**
	 * Ajoute une nouvelle ligne à la table
	 * <p>Attention: ne met pas à jour le dictionnaire sur le disque!</p>
	 */
	private void ajouteRegle()
	{
		Object [] o = {new Integer(table.getRowCount()+1),new Boolean(false),"règle",new Boolean(false),new Boolean(false)};
		tm.addRow(o);
		jsp.validate();
		jsp.getVerticalScrollBar().setValue(jsp.getVerticalScrollBar().getMaximum());
	}
	/**
	 * ferme la fenêtre
	 * <p>Réalise des tests et intéragit avec l'utilisateur 
	 * pour valider les modifs/changements de dico</p> 
	 */
	private void quitter()
	{
		if(modif)//le dico a pas été enregistré
		{
			boolean sauv=JOptionPane.showConfirmDialog(this,
					"Voulez-vous sauvegarder les modifications?",
					"Modifications non sauvées",
					JOptionPane.YES_NO_OPTION)==JOptionPane.OK_OPTION;
			if(sauv)
			{
				if(dicoName.equals("")){enregistrerSous();}
				else{enregistrer();}
			}
		}
		if(!modif && !dicoName.equals(ConfigNat.getCurrentConfig().getDicoCoup()))
			//le dictionnaire a changé
		{
			boolean change=JOptionPane.showConfirmDialog(this,
					"Voulez-vous utiliser ce dictionnaire comme dictionnaire de coupure?",
					"Dictionnaire différent",
					JOptionPane.YES_NO_OPTION)==JOptionPane.OK_OPTION;
			if(change)
			{
				HyphenationToolkit.fabriqueDicoNat(dicoName, Transcription.xslHyphen, "UTF-8");
				ConfigNat.getCurrentConfig().setDicoCoup(dicoName);
			}
		}
		dispose();
	}
	/**
	 * Charge un nouveau dictionnaire
	 *
	 */
	private void chargerDico()
	{
		/* paramétrage du file chooser*/
		JFileChooser jfc = new JFileChooser();
		FiltreFichier ff = new FiltreFichier(new String [] {"dic"},"Dictionnaires de règles (*.dic)");
		jfc.addChoosableFileFilter(ff);
		jfc.setAcceptAllFileFilterUsed(true);
		jfc.setFileFilter(ff);
		File f = new File("./xsl/dicts/");
		jfc.setCurrentDirectory(f);
		jfc.setApproveButtonText("Choisir ce dictionnaire"); //intitulé du bouton
		
		/* selection du dico */
		jfc.setDialogTitle("Sélection du dictionnaire à charger");
		if (jfc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION)
		{
			tm.setDataVector(creerDonneesTable(jfc.getSelectedFile().getAbsolutePath()), null);
			tm.fireTableStructureChanged();
			lDico.setText("<html>Dictionnaire utilisé:<h3>"+
				jfc.getSelectedFile().getAbsolutePath()+
				" <i>(pas de description)</i></h3></html>");
			dicoName=jfc.getSelectedFile().getAbsolutePath();
			HyphenationToolkit.fabriqueDicoNat(dicoName, Transcription.xslHyphen, "UTF-8");
			setModif(false);
		}
	}

	/**
	 * Enregistre le dictionnaire à une nouvelle adresse et le charge dans NAT
	 */
	private void enregistrerSous() 
	{
		/* paramétrage du file chooser*/
		JFileChooser jfc = new JFileChooser();
		FiltreFichier ff = new FiltreFichier(new String [] {"dic"},"Dictionnaires de règles (*.dic)");
		jfc.addChoosableFileFilter(ff);
		jfc.setAcceptAllFileFilterUsed(true);
		jfc.setFileFilter(ff);
		File f = new File("./xsl/dicts/");
		jfc.setCurrentDirectory(f);
		jfc.setApproveButtonText("Choisir ce dictionnaire"); //intitulé du bouton
		
		/* selection du dico */
		jfc.setDialogTitle("Sélection du dictionnaire à charger");
		if (jfc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION)
		{
			lDico.setText("<html>Dictionnaire utilisé:<h3>"+
				jfc.getSelectedFile().getAbsolutePath()+
				" <i>(pas de description)</i></h3></html>");
			dicoName=jfc.getSelectedFile().getAbsolutePath();
			enregistrer();
			btEnregistrer.setEnabled(true);
		}
	}
	/**
	 * Enregistre le dictionnaire et le charge dans NAT
	 */
	private void enregistrer() 
	{
		ArrayList<ArrayList<Object>> data = tm.getArrayListOfData();
		ArrayList<String> rules = new ArrayList<String>();
		for(int i=0;i<data.size();i++)
		{
			String rule = data.get(i).get(2).toString();
			if(data.get(i).get(1).toString().equals("true")){rule = "^" + rule;}
			if(data.get(i).get(3).toString().equals("true")){rule = rule + "$";}
			rules.add(rule);
		}
		HyphenationToolkit.writeRules(rules, dicoName,"UTF-8");
		ConfigNat.getCurrentConfig().setDicoCoup(dicoName);
		HyphenationToolkit.fabriqueDicoNat(dicoName, Transcription.xslHyphen, "UTF-8");
		setModif(false);
	}
	/**
	 * Charge un dictionnaire vierge
	 */
	private void nouveauDico()
	{
		Object[][] data = new Object[1][5];
		data[0] = new Object[]{new Integer(1),new Boolean(false),"règle",new Boolean(false),new Boolean(false)};
		tm.setDataVector(data, null);
		tm.fireTableStructureChanged();
		lDico.setText("<html>Dictionnaire utilisé:<h3>"+
			"Nouveau dictionnaire"+
			" <i>(pas de description)</i></h3></html>");
		dicoName="";
		btEnregistrer.setEnabled(false);
		setModif(true);
	}
	/**
	 * Méthode redéfinie de ActionListener
	 * <p>Gère les actions sur les boutons</p>
	 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
	 */
	public void actionPerformed(ActionEvent ae)
	{
		if(ae.getSource()==btVerif){verifie(jtfTest.getText());}
		else if (ae.getSource()==btOuvrir){chargerDico();}
		else if (ae.getSource()==btNouveau){nouveauDico();}
		else if (ae.getSource()==btAjoutRegle){ajouteRegle();}
		else if (ae.getSource()==btSupprRegle){supprReglesSel();}
		else if (ae.getSource()==btEnregistrer){enregistrer();}
		else if (ae.getSource()==btEnregistrerSous){enregistrerSous();}
		else if (ae.getSource()==btAnnuler){quitter();}
	}
	/**
	 * Rédéfinie de ItemListener 
	 * <p>efface le panneau de détail si {@link #jcbDetailCoup} est dessélectionné 
	 * et désactive {@link #lJtaReponse}</p>
	 * @see java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent)
	 */
	public void itemStateChanged(ItemEvent arg0)
	{
		if(!jcbDetailCoup.isSelected()){jtaReponse.setText("");lJtaReponse.setEnabled(false);}
		else{lJtaReponse.setEnabled(true);}
	}
	/**
	 * Méthode d'accès en écriture à {@link #modif}
	 * @param m valeur pour modif
	 */
	public void setModif(boolean m) {modif = m;}
	/**
	 * Classe interne décrivant le modèle de JTable utilisé pour {@link ConfDictCoup}
	 * @author bruno
	 *
	 */
	private class TableModeleCoup extends DefaultTableModel
	{
		/** Pour la sérialisation, non utilisé */
		private static final long serialVersionUID = 1L;
		/** Les données de la table */
		private ArrayList<ArrayList<Object>> data = new ArrayList<ArrayList<Object>>();
		/** Tableau contenant les classes des colonnes d'objets*/
		private Class<?>[] colClass = new Class<?>[]{Integer.class,Boolean.class,String.class,Boolean.class,Boolean.class};
		/** Tableau conteannt les noms des colonnes */
		private String[] columnNames = new String[]{"n°","en début", "règle", "en fin","sel."};
		/** 
		 * Constructeur
		 * @param o les données de la table
		 */
		public TableModeleCoup(Object[][] o)
		{
			super();
			for(int i=0;i<o.length;i++)
			{
				ArrayList<Object> al = new ArrayList<Object>();
				for (int j=0;j<o[0].length;j++){al.add(o[i][j]);}
				data.add(al);
			}
		}
		/**
		 * Retourne les données sous forme d'ArrayList double
		 * @return {@link #data}
		 */
		public ArrayList<ArrayList<Object>> getArrayListOfData() {return data;}
		/**
		 * Stocke les données passées en paramètre dans la structure {@link #data}
		 * @see javax.swing.table.DefaultTableModel#setDataVector(java.lang.Object[][], java.lang.Object[])
		 */
		@Override
		public void setDataVector(Object[][] o, Object[] name)
		{
			if (name!=null)
			{
				for(int i=0;i<columnNames.length;i++){columnNames[i]=name[i].toString();}
			}
			data = new ArrayList<ArrayList<Object>>();
			for(int i=0;i<o.length;i++)
			{
				ArrayList<Object> al = new ArrayList<Object>();
				for (int j=0;j<o[0].length;j++){al.add(o[i][j]);}
				data.add(al);
			}
			
		}
		/**
		 * Ajoute une ligne à {@link #data}
		 * @see javax.swing.table.DefaultTableModel#addRow(java.lang.Object[])
		 */
		@Override
		public void addRow(Object[] o)
		{
			ArrayList<Object> al = new ArrayList<Object>();
			for(int i=0;i<o.length;i++){al.add(o[i]);}
			data.add(al);
			this.fireTableRowsInserted(data.size()-1,data.size()-1);
			setModif(true);
		}
		/**
		 * Renvoie le nom de la colonne <code>col</code>
		 * @see javax.swing.table.AbstractTableModel#getColumnName(int)
		 */
		@Override
		public String getColumnName(int col) {return columnNames[col].toString();}
		/**
		 * Affecte <code>value</code> à cellule (<code>row</code>,<code>col</code>) de {@link #data}
		 * @see javax.swing.table.AbstractTableModel#setValueAt(java.lang.Object, int, int)
		 */
		@Override
		public void setValueAt(Object value, int row, int col)
		{
	        if(col==2)
	        {
	        	String v= value.toString();
	        	value = v.replaceAll("([a-z]|^)'([a-z]|$)","$1''$2");
	        }
			data.get(row).set(col, value);
	        fireTableCellUpdated(row, col);
	        setModif(true);
	    }
		/**
		 * Supprime la ligne <code>row</code>
		 * @see javax.swing.table.DefaultTableModel#removeRow(int)
		 */
		@Override
		public void removeRow(int row)
		{
			data.remove(row);
			this.fireTableRowsDeleted(row,row);
			setModif(true);
		}
		/**
		 * Renvoie le nombre de colonnes de {@link #data}
		 * @see javax.swing.table.TableModel#getColumnCount()
		 */
		@Override
		public int getColumnCount() {return data.get(0).size();}
		/**
		 * Renvoie le nombre de lignes de {@link #data}
		 * @see javax.swing.table.TableModel#getRowCount()
		 */
		@Override
		public int getRowCount()
		{
			int retour=0;
			if(data!=null){retour= data.size();}
			return retour;
		}
		/**
		 * Renvoie l'objet de la cellule (<code>row</code>,<code>col</code>) de {@link #data}
		 * @see javax.swing.table.TableModel#getValueAt(int, int)
		 */
		@Override
		public Object getValueAt(int row, int col) {return data.get(row).get(col);}
		/**
		 * Redéfinition indiquant que toutes les cellules, sauf celles de la
		 * première colonne (n°), sont éditables
		 * @see javax.swing.table.AbstractTableModel#isCellEditable(int, int)
		 */
		@Override
		public boolean isCellEditable(int i, int j)
		{
			boolean retour = true;
			if(j==0){retour=false;}
			return retour;
		}
		/**
		 * Renvoie la classe des objets de la colonne <code>col</code>
		 * @see javax.swing.table.AbstractTableModel#getColumnClass(int)
		 */
		@Override
		public Class<?> getColumnClass(int col) {return colClass[col];}
	}
}