/*
 * 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.Component;
import java.awt.Dimension;
import java.awt.Font;
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.JComboBox;
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.DefaultTableCellRenderer;
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 outils.regles.Regle;
import outils.regles.RegleEnsemble;
import outils.regles.RegleLocution;
import outils.regles.RegleSigne;
import outils.regles.RegleSymbole;
import outils.regles.RulesToolKit;

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

/**
 * Fenêtre de sélection et de visualisation des règles d'abrégé.
 * @author bruno
 * @since 2.0
 * @see outils.HyphenationToolkit
 */
public class ConfAbrege extends JFrame implements ActionListener,ItemListener
{
	/** Pour la sérialisation (non utilisé) */
	private static final long serialVersionUID = 1L;
	/** Le fichier à utiliser pour les règles */
	private static final String xslG2 = ConfigNat.getUserTempFolder()+"g2-rules.xsl";
	/** JTable contenant les règles */ 
	private JTable table;
	/** Modèle pour la table */
	private TableModeleAbr tm;
	/** ScrollPane de la table*/
	private 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>fichier de règles</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>fichier de règles <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"));
	
	/** 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>Interface en construction!!!</b>" +
			"<br><i>Cette zone contiendra la description des règles affichées</i></html>");
	/** JLabel pour le */
	private JLabel lJcbRegles = new JLabel("Règles affichées:");
	/** JCombobox de filtre sur les règles */
	private JComboBox jcbRegles = new JComboBox(new String[]{"Tout","Locutions","Signes","Symboles","Règles sur les signes",
			"Règles sur les symboles", "Règles génériques (s'appliquent toujours)", "Règles du cas général"});
	/** 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;
	
	/**donnees des règles */
	private ArrayList<ArrayList<Object>> donnees = new ArrayList<ArrayList<Object>>();
	/** 
	 * Constructeur 
	 * <p>Initialise les éléments d'interface graphique et construit la page</p>
	 * <p>Récupère notamment les règles d'abrégé en utilisant {@link outils.regles.RulesToolKit#getRules(String)}
	 */
	public ConfAbrege()
	{
		super("Sélection des règles de l'abrégé à utiliser");
		//setResizable(false);
		if(!(new File(ConfigNat.getCurrentConfig().getRulesFrG2()).exists()))
		{
			JOptionPane.showMessageDialog(this,"<html><b>Fichier de règles introuvable</b><br>" +
					"Le fichier <i>" + ConfigNat.getCurrentConfig().getDicoCoup() +
					" </i><br>est introuvable.<br>Utilisation du dictionnaire par défaut<br>" +
					"<b>Pensez à enregistrer ce nouveau fichier si vous souhaitez l'utiliser.</b></html>",
					"Dictionnaire introuvable",JOptionPane.ERROR_MESSAGE);
			donnees = creerDonneesTable(new File(ConfigNat.getCurrentConfig().getRulesFrG2Perso()).toURI().toString());
		}
		else{donnees = creerDonneesTable(new File(ConfigNat.getCurrentConfig().getRulesFrG2Perso()).toURI().toString());}
		
		//table = new JTable(donnees, lesColonnes);
		tm = new TableModeleAbr(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(150);
		modelColonne.setMinWidth(200);
		modelColonne =  modelesColonnes.getColumn(1);
		modelColonne.setMaxWidth(50);
		modelColonne.setMinWidth(50);
		
		//rendu pour la table
		table.setDefaultRenderer(Regle.class, new BrailleTableCellRenderer());
		
	    table.setToolTipText("Tableau des règles d'abréviation");
	    table.getAccessibleContext().setAccessibleName("Tableau des règles d'abréviation");
	    table.getAccessibleContext().setAccessibleDescription("Cette table est composée de 2 ou 3 colonnes: " +
	    	"intitulé de la règle (non éditable), " +
	    	"référence de la règle (optionnel), case à cocher indiquant si la règle doit être appliquée");
	    
	    // 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().getRulesFrG2Perso();
		String commentaire = "";
		if(ConfigNat.getCurrentConfig().getIsSysConfig()){commentaire=" (<font color=\"red\">non éditable avec cette configuration système</font>)";}
		lDico =  new JLabel("<html>Fichier de règles 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("Champ de saisie du 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("Champ texte résultat du test");
		jtfReponse.getAccessibleContext().setAccessibleDescription("Résultat du test, non éditable");
		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 d'abréviation");
		jcbDetailCoup.getAccessibleContext().setAccessibleDescription("Afficher les détails sur le test d'abréviation");
		jcbDetailCoup.setToolTipText("Cocher la case pour afficher les détails du test d'abréviation (alt+d)");
		
		btVerif.addActionListener(this);
		btVerif.getAccessibleContext().setAccessibleName("Lancer le test");
		btVerif.getAccessibleContext().setAccessibleDescription("Activer pour lancer le test d'abréviation");
		btVerif.setMnemonic('t');
		btVerif.setToolTipText("Lance le test d'abréviation");
		
		lJtaReponse.setDisplayedMnemonic('l');
		lJtaReponse.setLabelFor(jtaReponse);
		
		jtaReponse.getAccessibleContext().setAccessibleName("détails du test d'abréviation");
		jtaReponse.getAccessibleContext().setAccessibleDescription("zone de texte contenant les détails du test; " +
				"pour chaque règle utilisée sont l'intitulé et la référence de la règle");
		jtaReponse.setToolTipText("détails du test; " +
				"pour chaque règle utilisée sont l'intitulé et la référence de la règle (alt+l)");
		
		jtaReponse.setEditable(false);
		jtfReponse.setEditable(false);
		lJtaReponse.setEnabled(false);
		
		/* Panneau des boutons ******************/
		btOuvrir.addActionListener(this);
		btOuvrir.getAccessibleContext().setAccessibleName("Charger un nouveau fichier de règles");
		btOuvrir.getAccessibleContext().setAccessibleDescription("Charge un autre fichier de règles dans le tableau");
		btOuvrir.setMnemonic('c');
		btOuvrir.setToolTipText("Charge un autre fichier de règles dans la table (alt+c)");
		
		btNouveau.addActionListener(this);
		btNouveau.getAccessibleContext().setAccessibleName("Générer un fichier vierge");
		btNouveau.getAccessibleContext().setAccessibleDescription("Génère un nouveau fichier de règle où tout est activé");
		btNouveau.setMnemonic('v');
		btNouveau.setToolTipText("Charge un fichier de règles où tout est activé (alt+v)");
		
		btEnregistrer.addActionListener(this);
		btEnregistrer.getAccessibleContext().setAccessibleName("Enregistrer les modifications");
		btEnregistrer.getAccessibleContext().setAccessibleDescription("Sauve les modifications et charge le nouveau fichier dans la configuration");
		btEnregistrer.setMnemonic('s');
		btEnregistrer.setToolTipText("Sauve les modifications et charge le nouveau fichier dans la configuration (alt+s)");
		
		if(ConfigNat.getCurrentConfig().getIsSysConfig())
		{
			btEnregistrer.setEnabled(false);
			btEnregistrerSous.setEnabled(false);
		}
		if(new File(dicoName).equals(new File(ConfigNat.getCurrentConfig().getRulesFrG2())))
		{
			btEnregistrer.setEnabled(false);
		}
		btEnregistrerSous.addActionListener(this);
		btEnregistrerSous.getAccessibleContext().setAccessibleName("Enregistrer les modifications dans un autre fichier");
		btEnregistrerSous.getAccessibleContext().setAccessibleDescription("Sauve les modifications dans un autre fichier et le charge dans la configuration");
		btEnregistrerSous.setMnemonic('n');
		btEnregistrerSous.setToolTipText("Sauve les modifications dans un autre fichier et le charge dans la configuration (alt+n)");
		
		btAnnuler.addActionListener(this);
		btAnnuler.getAccessibleContext().setAccessibleName("Quitter l'interface");
		btAnnuler.getAccessibleContext().setAccessibleDescription("Ferme la fenêtre d'abréviation");
		btAnnuler.setMnemonic('q');
		btAnnuler.setDisplayedMnemonicIndex(0);
		btAnnuler.setToolTipText("Ferme la fenêtre d'abréviation (alt+q)");
		
		lJcbRegles.setDisplayedMnemonic('g');
		lJcbRegles.setLabelFor(jcbRegles);
		jcbRegles.addItemListener(this);
		/*
		 * 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=3;
		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);
		
		gbc.gridy++;
		gbc.gridwidth=1;
		gblTest.setConstraints(lJcbRegles, gbc);
		pTest.add(lJcbRegles);
		
		gbc.gridx++;
		gbc.gridwidth=2;
		gblTest.setConstraints(jcbRegles, gbc);
		pTest.add(jcbRegles);
		
		
		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=4;
		gbl.setConstraints(jsp, gbc);
		
		gbc.gridwidth=1;
		gbc.gridx=1;
		gbc.gridy++;
		JPanel pBoutons = new JPanel();
		GridBagLayout gblBt = new GridBagLayout();
		pBoutons.setLayout(gblBt);
		gbl.setConstraints(pBoutons, gbc);
	
		gbc.gridy=0;
		gbc.gridx=0;
		gbc.fill = GridBagConstraints.VERTICAL;
		gbc.insets=new Insets(10,3,3,3);
		gblBt.setConstraints(btOuvrir, gbc);
		gbc.gridx++;
		gblBt.setConstraints(btNouveau, gbc);
		gbc.gridx++;
		gbc.insets=new Insets(10,50,3,3);
		gblBt.setConstraints(btEnregistrer, gbc);
		gbc.insets=new Insets(10,3,3,3);
		gbc.gridx++;
		gblBt.setConstraints(btEnregistrerSous, gbc);
		gbc.insets=new Insets(10,50,3,3);
		gbc.gridx++;
		gblBt.setConstraints(btAnnuler, gbc);
			
		//add(lRegles);
		cp.add(lDico);
		cp.add(pTest);
		pBoutons.add(btOuvrir);
		pBoutons.add(btNouveau);
		pBoutons.add(btEnregistrer);
		pBoutons.add(btEnregistrerSous);
		pBoutons.add(btAnnuler);
		cp.add(jsp);
		cp.add(pBoutons);
		
		//ajout d'un scrollpane 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));
		setVisible(true);
		
		/*btOuvrir.setEnabled(false);
		btEnregistrer.setEnabled(false);
		btEnregistrerSous.setEnabled(false);
		btNouveau.setEnabled(false);*/
		btVerif.setEnabled(false);
		jcbDetailCoup.setEnabled(false);
	}
	/**
	 * Crée les données pour la JTable {@link #table} contenues dans le 
	 * fichier dictionnaire de règles <code>dico</code> à partir du fichier de règles de référence
	 * @param dico adresse du dictionnaire de règle à charger
	 * @return les données pour la table {@link #table}
	 * @see outils.HyphenationToolkit#getRules(String)
	 */
	private ArrayList<ArrayList<Object>> creerDonneesTable(String dico)
	{
		/* Création de la table *****************/
		ArrayList<Regle> liste = RulesToolKit.getRules(dico);
		ArrayList<Regle> listeRef = RulesToolKit.getRules(ConfigNat.getCurrentConfig().getRulesFrG2());
		ArrayList<ArrayList<Object>> d = new ArrayList<ArrayList<Object>>();
		for(int i=0;i<listeRef.size();i++)
		{
			Regle regle = listeRef.get(i);
			Boolean actif = new Boolean(liste.contains(regle));
			ArrayList<Object> a = new ArrayList<Object>();
			
			a.add(regle);
			a.add(actif);
			
			d.add(a);
		}
		return d;
		
	}
	/**
	 * 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(xslG2));
				// 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();
			}
		}
	}
	/**
	 * ferme la fenêtre
	 * <p>Réalise des tests et intéragit avec l'utilisateur 
	 * pour valider les modifs/changements de fichier</p> 
	 */
	private void quitter()
	{
		if(modif)//le fichier 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().getRulesFrG2Perso()))
			//le dictionnaire a changé
		{
			boolean change=JOptionPane.showConfirmDialog(this,
					"Voulez-vous utiliser ce fichier comme fichier de règles d'abréviation?",
					"Fichier différent",
					JOptionPane.YES_NO_OPTION)==JOptionPane.OK_OPTION;
			if(change)
			{
				//RulesToolKit.writeRules(donnees);
				ConfigNat.getCurrentConfig().setRulesFrG2Perso(dicoName);
			}
			ConfigNat.getCurrentConfig().setRulesFrG2Perso(ConfigNat.getCurrentConfig().getRulesFrG2Perso());
		}
		//écriture du xsl quoiqu'il arrive; inutile si il n'y a pas d'enregistrement mais bon...:
		RulesToolKit.writeRules(RulesToolKit.getRules(new File(ConfigNat.getCurrentConfig().getRulesFrG2Perso()).toURI().toString()));
		dispose();
	}
	/**
	 * Charge un nouveau dictionnaire
	 *
	 */
	private void chargerDico()
	{
		/* paramétrage du file chooser*/
		JFileChooser jfc = new JFileChooser();
		FiltreFichier ff = new FiltreFichier(new String [] {"xml"},"Fichier de règles (*.xml)");
		jfc.addChoosableFileFilter(ff);
		jfc.setAcceptAllFileFilterUsed(true);
		jfc.setFileFilter(ff);
		File f = new File("./xsl/dicts/");
		jfc.setCurrentDirectory(f);
		jfc.setApproveButtonText("Choisir ce fichier"); //intitulé du bouton
		
		/* selection du dico */
		jfc.setDialogTitle("Sélection du fichier à charger");
		if (jfc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION)
		{
			donnees = creerDonneesTable(jfc.getSelectedFile().toURI().toString());
			tm.setDataVector(donnees);
			//tm.fireTableStructureChanged();
			
			majTable();
			lDico.setText("<html>Fichier de règles utilisé:<h3>"+
				jfc.getSelectedFile().getAbsolutePath()+
				" <i>(pas de description)</i></h3></html>");
			dicoName=jfc.getSelectedFile().getAbsolutePath();
			setModif(false);
		}
		if(new File(dicoName).equals(new File(ConfigNat.getCurrentConfig().getRulesFrG2()))
				|| ConfigNat.getCurrentConfig().getIsSysConfig())
		{
			btEnregistrer.setEnabled(false);
		}
		else{btEnregistrer.setEnabled(true);}
	}
	
	/**
	 * Enregistre le fichier de règles à une nouvelle adresse et le charge dans NAT
	 * @return faux si pb lors de l'enregistrement
	 */
	private boolean enregistrerSous() 
	{
		boolean retour = true;
		/* paramétrage du file chooser*/
		JFileChooser jfc = new JFileChooser();
		FiltreFichier ff = new FiltreFichier(new String [] {"xml"},"Fichier de règles (*.xml)");
		jfc.addChoosableFileFilter(ff);
		jfc.setAcceptAllFileFilterUsed(true);
		jfc.setFileFilter(ff);
		File f = new File(ConfigNat.getUserTempFolder()+"regles");
		jfc.setCurrentDirectory(f);
		jfc.setApproveButtonText("Choisir ce fichier"); //intitulé du bouton
		
		/* selection du dico */
		jfc.setDialogTitle("Sélection du fichier à charger");
		if (jfc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION)
		{
			lDico.setText("<html>Fichier utilisé:<h3>"+
				jfc.getSelectedFile().getAbsolutePath()+
				" <i>(pas de description)</i></h3></html>");
			dicoName=jfc.getSelectedFile().getAbsolutePath();
			retour = enregistrer();
			if(retour){btEnregistrer.setEnabled(true);}
		}
		return retour;
	}
	/**
	 * Enregistre le dictionnaire et le charge dans NAT
	 * @return faux si pb lors de l'enregistrement
	 */
	private boolean enregistrer() 
	{
		boolean retour = true;
		ArrayList<Regle> liste = new ArrayList<Regle>();
		for(int i = 0; i< donnees.size();i++)
		{
			if(((Boolean)(donnees.get(i).get(1))).booleanValue())
			{
				liste.add((Regle)donnees.get(i).get(0));
			}
		}
		//RulesToolKit.writeRules(liste); PAS ici: uniquement si confirmation
		if(!RulesToolKit.saveRuleFile(liste, dicoName))
		{
			JOptionPane.showMessageDialog(this,
					"Erreur lors de l'enregistrement; vous ne pouvez modifier ce fichier",
					"Impossible de sauver le fichier", JOptionPane.ERROR_MESSAGE);
			retour = false;
		}
		else{setModif(false);}
		return retour;
	}
	/**
	 * Charge un dictionnaire vierge
	 */
	private void nouveauDico()
	{
		donnees = creerDonneesTable(ConfigNat.getCurrentConfig().getRulesFrG2());
		tm.setDataVector(donnees);
		//tm.fireTableStructureChanged();
		lDico.setText("<html>Fichier utilisé:<h3>"+
			"Nouveau fichier de règles"+
			" <i>(pas de description)</i></h3></html>");
		dicoName="";
		majTable();
		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()==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 ie)
	{
		if(ie.getSource()==jcbDetailCoup)
		{
			if(!jcbDetailCoup.isSelected()){jtaReponse.setText("");lJtaReponse.setEnabled(false);}
			else{lJtaReponse.setEnabled(true);}
		}
		else if(ie.getSource()==jcbRegles)
		{
			majTable();
		}
	}
	
	/**
	 * Mets à jour la table en filtrant les données
	 */
	private void majTable()
	{
		ArrayList<ArrayList<Object>> liste = new ArrayList<ArrayList<Object>>();
		for (int i=0;i<donnees.size();i++)
		{
			ArrayList<Object> ligne = donnees.get(i);
			if(jcbRegles.getSelectedItem().equals("Tout"))
			{
				liste.add(ligne);
			}
			else if(ligne.get(0) instanceof RegleLocution && jcbRegles.getSelectedItem().equals("Locutions"))
			{
				liste.add(ligne);
			}
			else if(ligne.get(0) instanceof RegleSigne && jcbRegles.getSelectedItem().equals("Signes"))
			{
				liste.add(ligne);
			}
			else if(ligne.get(0) instanceof RegleSymbole && jcbRegles.getSelectedItem().equals("Symboles"))
			{
				liste.add(ligne);
			}
			else if(ligne.get(0) instanceof RegleEnsemble)
			{
				RegleEnsemble r = (RegleEnsemble) ligne.get(0); 
				if (jcbRegles.getSelectedItem().equals("Règles sur les signes") && r.isFor(RulesToolKit.SIGNE) ||
						jcbRegles.getSelectedItem().equals("Règles sur les symboles") && r.isFor(RulesToolKit.SYMBOLE) ||
						jcbRegles.getSelectedItem().equals("Règles génériques (s'appliquent toujours)") && r.isFor(RulesToolKit.ALL)||
						jcbRegles.getSelectedItem().equals("Règles du cas général") && r.isFor(RulesToolKit.GENERAL))
				{
					liste.add(ligne);
				}
			}
		}
		tm.setArrayListOfData(liste);
		table.updateUI();
	}
	/**
	 * 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 TableModeleAbr 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<?>[]{Regle.class,Boolean.class};
		/** Tableau conteannt les noms des colonnes */
		private String[] columnNames = new String[]{"règle", "sel."};
		/** 
		 * Constructeur
		 * @param d les données de la table
		 */
		public TableModeleAbr(ArrayList<ArrayList<Object>> d)
		{
			super();
			data = d;
		}
		/**
		 * Retourne les données sous forme d'ArrayList double
		 * @return {@link #data}
		 */
		public ArrayList<ArrayList<Object>> getArrayListOfData() {return data;}
		/**
		 * MAJ des données sous forme d'ArrayList double
		 * @param d l'arraylist avec les nouvelles données
		 */
		public void setArrayListOfData(ArrayList<ArrayList<Object>> d) {data = d;}
		/**
		 * Stocke les données passées en paramètre dans la structure {@link #data}
		 * @param d liste
		 * @see javax.swing.table.DefaultTableModel#setDataVector(java.lang.Object[][], java.lang.Object[])
		 */
		public void setDataVector(ArrayList<ArrayList<Object>> d)
		{
			data = d;
		}
		/**
		 * 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)
		{
			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];}
	 }
	
	/**
	 * Classe permettant de faire le rendu de la table
	 * @author bruno
	 *
	 */
	private class BrailleTableCellRenderer extends DefaultTableCellRenderer 
	{
	    /** pour la sérialisation (non utilisé)*/
		private static final long serialVersionUID = 1L;
		
		/**
		 * Constructeur
		 */
		public BrailleTableCellRenderer(){super();}

		/** 
		 * Fait afficher la colonne 1 de la table avec la police de la ligne secondaire de l'éditeur
		 * TODO: éventuellement, ajouter une option pour cette police
		 * @see javax.swing.table.DefaultTableCellRenderer#getTableCellRendererComponent(javax.swing.JTable, java.lang.Object, boolean, boolean, int, int)
		 */
		@Override
		public Component getTableCellRendererComponent(JTable tbl, Object value, boolean isSelected,
	       boolean hasFocus, int row, int column) 
	    {
	        Component cell = super.getTableCellRendererComponent(tbl, value, isSelected, hasFocus, row, column);
	        if( column == 0 )
	        {
	        	Font t; 
	        	try
	        	{
					t = Font.createFont(Font.PLAIN, new File("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"));
					t = t.deriveFont(Font.PLAIN, 12);
				}
	        	catch (Exception e)
	        	{
	        		System.err.println("Police inconnue; utilisation de la police par défaut");
	        		t = new Font("DejaVu Sans",Font.PLAIN,12);
	    	        	
	        	}
	            cell.setFont(t);
	        }
	        return cell;
	    }
	}

}
