/*
Applet Jaxe - Editeur XML en Java

Copyright (C) 2007 Observatoire de Paris-Meudon

Ce programme est un logiciel libre ; vous pouvez le redistribuer et/ou le modifier conformément aux dispositions de la Licence Publique Générale GNU, telle que publiée par la Free Software Foundation ; version 2 de la licence, ou encore (à votre choix) toute version ultérieure.

Ce programme est distribué dans l'espoir qu'il sera utile, mais SANS AUCUNE GARANTIE ; sans même la garantie implicite de COMMERCIALISATION ou D'ADAPTATION A UN OBJET PARTICULIER. Pour plus de détail, voir la Licence Publique Générale GNU .

Vous devez avoir reçu un exemplaire de la Licence Publique Générale GNU en même temps que ce programme ; si ce n'est pas le cas, écrivez à la Free Software Foundation Inc., 675 Mass Ave, Cambridge, MA 02139, Etats-Unis.
*/

package jaxeapplet;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.reflect.Constructor;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;

import javax.swing.*;

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

import org.xml.sax.InputSource;
import org.w3c.dom.Document;

import jaxe.Jaxe;


/**
 * Applet permettant d'éditer un fichier XML avec Jaxe.
 *
 * Paramètres :
 * - config : chemin vers la config Jaxe par rapport au document HTML
 * - fichier : URL du fichier XML
 * - nouveau : "oui" ou "non", pour savoir si c'est un nouveau fichier
 * - dictionnaire : chemin vers le fichier .dico par rapport au document HTML (optionnel)
 * - phonetique : chemin vers le fichier .phon par rapport au document HTML (optionnel)
 * - enregistrement : URL relative à l'adresse de la page web, où sera envoyée le contenu avec une requête POST (obligatoire si fichier est défini)
 *
 * Il y a 2 façons d'utiliser cette applet :
 * - avec les paramètres fichier et enregistrement, sans Javascript.
 * Dans ce cas, le fichier sera lu depuis l'URL fichier, et enregistré avec le script donné par le paramètre enregistrement
 * (requête POST, paramètres chemin et contenu).
 * - avec du Javascript en utilisant la méthode editer() pour définir le XML, getEditing() régulièrement pour attendre la fin de l'édition,
 * puis getTexte() pour récuréper le XML édité.
 */
public class JaxeApplet extends JApplet {
    
    protected String scriptEnregistrement;
    protected String cheminConfig;
    protected JaxeAppletFrame frame;
    protected boolean editing;
    protected String fichierAEditer;
    protected boolean nouveau;
    protected String cheminDictionnaire;
    protected String cheminPhonetique;
    
    public void init() {
        if ("1.6.0_22".equals(System.getProperty("java.version"))) {
            // workaround pour le bug 6995162 (ou 6993073)
            javax.swing.text.html.parser.ParserDelegator workaround = new javax.swing.text.html.parser.ParserDelegator();
        }
        cheminConfig = getParameter("config");
        fichierAEditer = getParameter("fichier");
        String sNouveau = getParameter("nouveau");
        cheminDictionnaire = getParameter("dictionnaire");
        cheminPhonetique = getParameter("phonetique");
        scriptEnregistrement = getParameter("enregistrement");
        nouveau = sNouveau != null && !"".equals(sNouveau) && "oui".equals(sNouveau);
        editing = false;
        
        // bug couleurs Safari sur Leopard
        if (System.getProperty("os.name").startsWith("Mac OS") &&
                System.getProperty("os.version").startsWith("10.5")) {
            UIManager.put("Panel.background", new Color(232,232,232));
            UIManager.put("Label.background", new Color(232,232,232));
            UIManager.put("SplitPane.background", new Color(232,232,232));
        }
        
        // Utilisation de CatalogResolver s'il est disponible
        try {
            final Class<?> catalogResolver = Class.forName("org.apache.xml.resolver.tools.CatalogResolver");
            final Constructor cons = catalogResolver.getConstructor((Class[])null);
            Jaxe.setResolver(cons.newInstance((Object[])null));
        } catch (Throwable th) { // Exception ne gère pas ClassFormatError lancé par les JDK 1.5 quand la classe n'est pas trouvée
            // java.security.AccessControlException : java.util.PropertyPermission xml.catalog.ignoreMissing read  :-(
            // le resolver fait un appel stupide de System.getProperty("xml.catalog.ignoreMissing") alors que c'est interdit pour une applet non signée...
            // il faudrait modifier org.apache.xml.resolver.CatalogManager...
        }
    }
    
    public void start() {
        if (fichierAEditer != null)
            editerFichier(fichierAEditer);
    }
    
    public void stop() {
        if (frame != null) {
            if (editing)
                frame.fermer();
            // pour limiter les fuites de mémoire de la JVM sur MacOS X 10.6
            frame.setActionFermeture(null);
            frame.dispose();
            frame = null;
        }
    }
    
    /**
     * Lance l'édition du XML donné en paramètre.
     */
    public void editer(String texte) {
        editing = true;
        SwingUtilities.invokeLater(new Edition(texte)); // pour éviter un bug de Safari/Mac (ContextClassLoader null)
    }
    
    class Edition implements Runnable {
        private String texte;
        public Edition(final String texte) {
            this.texte = texte;
        }
        public void run() {
            editer2(texte);
        }
    }
    
    protected void editer2(String texte) {
        Document ddoc = null;
        if (texte != null && !"".equals(texte)) {
            try {
                final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
                dbf.setNamespaceAware(true);
                final DocumentBuilder docbuilder = dbf.newDocumentBuilder();
                InputSource is = new InputSource(new StringReader(texte));
                ddoc = docbuilder.parse(is);
            } catch (final Exception ex) {
                String msg = "JaxeApplet : " + ex.getClass().getName() + " : " + ex.getMessage();
                JOptionPane.showMessageDialog(null, msg, "Lecture document", JOptionPane.ERROR_MESSAGE);
                return;
            }
        }
        try {
            URL urlCfg = new URL(getDocumentBase(), cheminConfig);
            frame = new JaxeAppletFrame(urlCfg, ddoc);
            frame.setActionFermeture(new AbstractAction() {
                public void actionPerformed(ActionEvent e) {
                    fermetureEdition();
                }
            });
            frame.setVisible(true);
        } catch (MalformedURLException ex) {
            String msg = ex.getClass().getName() + " : " + ex.getMessage();
            JOptionPane.showMessageDialog(null, msg, "Lecture config", JOptionPane.ERROR_MESSAGE);
        }
    }
    
    /**
     * Lance l'édition du fichier XML dont l'URL est donnée en paramètre sous forme de String.
     */
    public void editerFichier(String nomFichier) {
        editing = true;
        URL urlFichier, urlCfg, urlEnregistrement, urlDictionnaire=null, urlPhonetique=null;
        try {
            urlFichier = new URL(new URI(nomFichier).toASCIIString());
        } catch (Exception ex) {
            String msg = ex.getClass().getName() + " : " + ex.getMessage();
            msg += "\n (nomFichier:" + nomFichier + ")";
            JOptionPane.showMessageDialog(null, msg, "URL du fichier", JOptionPane.ERROR_MESSAGE);
            return;
        }
        try {
            urlCfg = new URL(getDocumentBase(), cheminConfig);
        } catch (MalformedURLException ex) {
            String msg = ex.getClass().getName() + " : " + ex.getMessage();
            msg += "\n (cheminConfig:" + cheminConfig + ")";
            JOptionPane.showMessageDialog(null, msg, "URL config de Jaxe", JOptionPane.ERROR_MESSAGE);
            return;
        }
        try {
            urlEnregistrement = new URL(getDocumentBase(), scriptEnregistrement);
        } catch (MalformedURLException ex) {
            String msg = ex.getClass().getName() + " : " + ex.getMessage();
            msg += "\n (scriptEnregistrement:" + scriptEnregistrement + ")";
            JOptionPane.showMessageDialog(null, msg, "URL du script d'enregistrement", JOptionPane.ERROR_MESSAGE);
            return;
        }
        if (cheminDictionnaire != null && !"".equals(cheminDictionnaire)) {
            try {
                urlDictionnaire = new URL(getDocumentBase(), cheminDictionnaire);
                if (cheminPhonetique != null && !"".equals(cheminPhonetique)) {
                    try {
                        urlPhonetique = new URL(getDocumentBase(), cheminPhonetique);
                    } catch (MalformedURLException ex) {
                        String msg = ex.getClass().getName() + " : " + ex.getMessage();
                        msg += "\n (cheminPhonetique:" + cheminPhonetique + ")";
                        JOptionPane.showMessageDialog(null, msg, "URL phonetique", JOptionPane.ERROR_MESSAGE);
                        return;
                    }
                }
            } catch (MalformedURLException ex) {
                String msg = ex.getClass().getName() + " : " + ex.getMessage();
                msg += "\n (cheminDictionnaire:" + cheminDictionnaire + ")";
                JOptionPane.showMessageDialog(null, msg, "URL dictionnaire", JOptionPane.ERROR_MESSAGE);
                return;
            }
        }
        frame = new JaxeAppletFrame(urlCfg, urlFichier, urlEnregistrement, urlDictionnaire, urlPhonetique, nouveau);
        frame.setActionFermeture(new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                fermetureEdition();
            }
        });
        frame.setVisible(true);
    }
    
    /**
     * Méthode appelée à la fermeture de la fenêtre d'édition.
     */
    public void fermetureEdition() {
        editing = false;
    }
    
    /**
     * Renvoit le texte complet du XML modifié par l'édition.
     */
    public String getTexte() {
        if (frame == null) {
            System.err.println("JaxeApplet.getTexte : frame est null");
            return(null);
        }
        StringWriter sw = new StringWriter();
        frame.sendToWriter(sw);
        return(sw.toString());
    }
    
    /**
     * Renvoit true si une édition est en cours (avec une fenêtre ouverte).
     */
    public boolean getEditing() {
        return(editing);
    }
    
}
