/*
Jaxe - Editeur XML en Java

Copyright (C) 2005 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 pluginsjaxe;

import java.awt.*;
import java.io.File;
import javax.swing.*;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;

import jaxe.DialogueChamps;
import jaxe.JaxeDocument;
import jaxe.Fonction;

import org.w3c.dom.Element;

import com.cqs.ftp.FTP;
import com.cqs.ftp.RemoteFile;


/**
 * Envoi de tout le dossier de la contribution (où se trouve le fichier XML) sur un serveur FTP
 * Paramètres: "serveur" = nom du serveur; "dossier" = répertoire sur le serveur.
 * Demandé à l'utilisateur: login, mot de passe.
 * Utilise la bibliothèque FTP JavaFTP.
 * compilation:
 * javac -encoding ISO-8859-1 -source 1.5 -target 1.5 -classpath .:Jaxe.jar:javaftpapi.jar pluginsjaxe/EnvoiContrib.java
 */
public class EnvoiContrib implements Fonction {

    static String[] fichiers_ignores = {".DS_Store", "Thumbs.db"};
    Element fctdef = null;
    String serveur = null;
    String dossier = null;
    DialogueLog dlglog = null;
    FTP ftp = null;
    
    public EnvoiContrib(Element fctdef) {
        this.fctdef = fctdef;
    }
    
    public boolean appliquer(JaxeDocument doc, int start, int end) {
        
        serveur = doc.cfg.valeurParametreFonction(fctdef, "serveur", serveur);
        dossier = doc.cfg.valeurParametreFonction(fctdef, "dossier", dossier);
        
        if (doc.fsave == null) {
            JOptionPane.showMessageDialog(doc.jframe,
                "Erreur: le fichier doit être sauvegardé.",
                "Erreur", JOptionPane.ERROR_MESSAGE);
            return(false);
        }
        
        File dossierContrib = doc.fsave.getParentFile();
        if (!doc.fsave.getName().equals(dossierContrib.getName() + ".xml")) {
            JOptionPane.showMessageDialog(doc.jframe,
                "Erreur: le fichier XML doit avoir le même nom que le dossier de la contribution.",
                "Erreur", JOptionPane.ERROR_MESSAGE);
            return(false);
        }
        
        String[] titres = {"login", "mot de passe"};
        JTextComponent[] champs = new JTextComponent[2];
        champs[0] = new JTextField(10);
        champs[1] = new JPasswordField(20);
        DialogueChamps dlg = new DialogueChamps(doc.jframe, "Authentification", titres, champs);
        if (!dlg.afficher())
            return(false);
        String login = champs[0].getText();
        String password = champs[1].getText();
        
        (new ThreadUpload(doc, dossierContrib, login, password)).start();
        
        return(true);
    }
    
    protected void logEtTestErreur(String operation, int code) throws FTPException {
        dlglog.ajouterString(operation + "...\n");
        if (ftp.lastCode() != code)
            throw new FTPException("Erreur de l'opération FTP '" + operation + "'");
    }
    
    protected void cd(String nomDossier) throws FTPException {
        ftp.cd(nomDossier);
        logEtTestErreur("changement vers le répertoire '" + nomDossier + "'", FTP.CODE_CD_OK);
    }
    
    protected void mkdir(String nomDossier) throws FTPException {
        ftp.makedir(nomDossier);
        logEtTestErreur("création du répertoire '" + nomDossier + "'", FTP.CODE_MKDIR_OK);
    }
    
    protected void delete(String nomFichier) throws FTPException {
        ftp.delete(nomFichier);
        logEtTestErreur("effacement du fichier '" + nomFichier + "'", FTP.CODE_DELETE_FILE_OK);
    }
    
    protected void removedir(String nomDossier) throws FTPException {
        ftp.removedir(nomDossier);
        logEtTestErreur("effacement du dossier '" + nomDossier + "'", FTP.CODE_RMDIR_OK);
    }
    
    protected void upload(File fichier) throws FTPException {
        for (int i=0; i<fichiers_ignores.length; i++)
            if (fichier.getName().equals(fichiers_ignores[i]))
                return;
        ftp.upload(fichier.getAbsolutePath(), fichier.getName());
        logEtTestErreur("envoi du fichier '" + fichier.getName() + "' sur le serveur", FTP.CODE_TRANSFER_OK);
    }
    
    protected void uploadRecursif(File fdossier) throws FTPException {
        mkdir(fdossier.getName());
        cd(fdossier.getName());
        File[] fichiers = fdossier.listFiles();
        for (int i=0; i<fichiers.length; i++) {
            if (fichiers[i].isDirectory())
                uploadRecursif(fichiers[i]);
            else
                upload(fichiers[i]);
        }
        cd("..");
    }
    
    protected void effacementRecursif(String nomDossier) throws FTPException {
        cd(nomDossier);
        ftp.list();
        logEtTestErreur("listing repertoire", FTP.CODE_TRANSFER_OK);
        RemoteFile[] fichiers = ftp.getDirectoryList();
        for (int i=0; i<fichiers.length; i++) {
            if (fichiers[i].isDirectory)
                effacementRecursif(fichiers[i].name);
            else
                delete(fichiers[i].name);
        }
        cd("..");
        removedir(nomDossier);
    }
    
    class FTPException extends Exception {
        public FTPException(String s) {
            super(s);
        }
    }
    
    class ThreadUpload extends Thread {
        JaxeDocument doc;
        File dossierContrib;
        String login;
        String password;
        public ThreadUpload(JaxeDocument doc, File dossierContrib, String login, String password) {
            this.dossierContrib = dossierContrib;
            this.doc = doc;
            this.login = login;
            this.password = password;
        }
        
        public void run() {
            dlglog = new DialogueLog(doc.jframe);
            
            ftp = null;
            try {
                ftp = new FTP(serveur);
                
                ftp.connect();
                logEtTestErreur("connexion au serveur " + serveur, FTP.CODE_CONNECT_OK);
                
                ftp.login(login, password);
                logEtTestErreur("authentification (login/mot de passe)", FTP.CODE_LOGGEDIN);
                
                //ftp.setTransfer(FTP.TRANSFER_PASV); // à tester
                ftp.setMode(FTP.MODE_BINARY);
                
                cd(dossier);
                
                ftp.list();
                logEtTestErreur("listing repertoire", FTP.CODE_TRANSFER_OK);
                RemoteFile[] fichiers = ftp.getDirectoryList();
                
                boolean trouve = false;
                for (int i=0; i<fichiers.length; i++)
                    if (dossierContrib.getName().equals(fichiers[i].name)) {
                        trouve = true;
                        break;
                    }
                if (trouve) {
                    int reponse = JOptionPane.showConfirmDialog(doc.jframe,
                        "Le dossier existe déjà sur le serveur. Mettre à jour la contribution ?",
                        "Ecrasement", JOptionPane.OK_CANCEL_OPTION);
                    if (reponse == JOptionPane.CANCEL_OPTION)
                        throw new FTPException("Copie annulée.");
                    effacementRecursif(dossierContrib.getName());
                }
                
                uploadRecursif(dossierContrib);
                
                ftp.disconnect();
                logEtTestErreur("déconnexion", FTP.CODE_DISCONNECT_OK);
            } catch (FTPException ex) {
                if (ftp != null && ftp.isConnected())
                    ftp.disconnect();
                JOptionPane.showMessageDialog(doc.jframe, ex.getMessage(), "Erreur", JOptionPane.ERROR_MESSAGE);
                dlglog.setVisible(false);
                dlglog = null;
                return;
            }
            JOptionPane.showMessageDialog(doc.jframe, "La copie s'est effectuée avec succès.", "Succès", JOptionPane.INFORMATION_MESSAGE);
            dlglog.setVisible(false);
            dlglog = null;
        }
    }
    
    class DialogueLog extends JDialog {
        JTextArea tarea;
        public DialogueLog(Frame frame) {
            super(frame, "log", false);
            JPanel cpane = new JPanel(new BorderLayout());
            setContentPane(cpane);
            tarea = new JTextArea(null, 15, 60);
            tarea.setEditable(false);
            JScrollPane scrollPane = new JScrollPane(tarea,
                JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
            cpane.add(scrollPane, BorderLayout.CENTER);
            cpane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
            pack();
            if (frame != null) {
                Rectangle r = frame.getBounds();
                setLocation(r.x + r.width/4, r.y + r.height/4);
            } else {
                Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
                setLocation((screen.width - getSize().width)/3,(screen.height - getSize().height)/3);
            }
            setVisible(true);
        }
        public void ajouterString(String s) {
            tarea.append(s);
            try {
                tarea.scrollRectToVisible(tarea.modelToView(tarea.getDocument().getLength()));
            } catch (BadLocationException ex) {
            }
        }
    }
}
