/*
editeurconfig - Editeur de Fichiers de Config de Jaxe

Copyright (C) 2011 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 editeurconfig;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;
import javax.swing.border.*;
import java.util.*;
import org.w3c.dom.*;

/**
* Classe qui affiche dans un JPanel la liste des éléments du schéma, et un arbre JTree pour les Menus, les Menus d'insertion et les Menus de fonction
*/
public class EditeurDeMenusH extends JPanel {
	
    private InfosNoeud monInfosNoeud;
    private Node monNoeud;
    private DefaultMutableTreeNode monNoeudSelectionne;
	private ListeElements listeElements;
    private Document doc;
    private Element menus;
    
    private DefaultMutableTreeNode root;
    private DefaultTreeModel treemodel;
    private JTree arbre;
    
    private DefaultListModel maListeModele;
    private JList maListe;
    private JList listeRestante = new JList();
    private DefaultListModel listeModeleRestant;
    
    private ArrayList<String> elementsExistants = new ArrayList<String>();
    private ArrayList<String> elementsRestants = new ArrayList<String>();
    
    private JButton boutonAjouter;
    private JButton boutonRetirer;
    
    private Object selectionCourante;
    
    private JButton bNouveauMenu;
    private JButton bSupprimerMenu;
    private JButton bNouveauMenuF;

    public EditeurDeMenusH(final ListeElements listeElements, final Document doc, final Element menus) {
        this.listeElements = listeElements;
        this.doc = doc;
        this.menus = menus;
        
        listeElements.JListeDesElements();
        maListeModele = listeElements.getListModel();
        
        retirerElementsExistants(menus); 
        if (elementsRestants != null) {
            maListe = listeRestante;
            maListeModele = listeModeleRestant;
        }
        else 
            maListe = listeElements.JListeDesElements();
        
        maListe.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        
        root = new DefaultMutableTreeNode(new InfosNoeud(menus));
        
        if (menus.hasChildNodes())
            domTree(menus, root);
        
        treemodel = new DefaultTreeModel(root);
        arbre = new JTree(treemodel);
        arbre.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
        arbre.setShowsRootHandles(true);
        arbre.setEditable(false);
        //arbre.setRootVisible(false);
        arbre.setSelectionRow(0);
        selectionCourante = arbre.getLastSelectedPathComponent();
        monNoeudSelectionne = (DefaultMutableTreeNode) selectionCourante;
        monInfosNoeud = (InfosNoeud)monNoeudSelectionne.getUserObject();
        monNoeud = monInfosNoeud.getNoeud();
        arbre.putClientProperty("JTree.lineStyle", "Angled"); //une ligne à angle droit relie chaque noeud fils à son noeud père
        
        afficher();
    }
    
    
    /**
    * Affiche l'arbre JTree des Menus, et la liste des éléments
    */
    private void afficher() {
        
        // écouteur JTree
        arbre.addTreeSelectionListener(new TreeSelectionListener() {
            public void valueChanged(TreeSelectionEvent e) {
                selectionCourante = arbre.getLastSelectedPathComponent(); 
                if (selectionCourante != null) {
                    monNoeudSelectionne = (DefaultMutableTreeNode) selectionCourante;
                    if (monNoeudSelectionne.getUserObject() instanceof InfosNoeud) {
                        monInfosNoeud = (InfosNoeud)monNoeudSelectionne.getUserObject();
                        monNoeud = monInfosNoeud.getNoeud();
                        if (!monNoeudSelectionne.isRoot()) {
                        
                            // si la sélection est un menu
                            if ("MENU".equals(monNoeud.getNodeName())) {
                                bNouveauMenu.setEnabled(true);
                                bSupprimerMenu.setEnabled(true);
                                bNouveauMenuF.setEnabled(true);
                                boutonRetirer.setEnabled(false);
                                if (maListe.getSelectedValue() != null)
                                    boutonAjouter.setEnabled(true);
                                else
                                    boutonAjouter.setEnabled(false);
                            }
                            // si la sélection est un menu d'insertion
                            if ("MENU_INSERTION".equals(monNoeud.getNodeName())) {
                                bNouveauMenu.setEnabled(false);
                                bSupprimerMenu.setEnabled(false);
                                bNouveauMenuF.setEnabled(false);
                                boutonAjouter.setEnabled(false);
                                boutonRetirer.setEnabled(true); 
                            }
                            
                            // si la sélection est un menu fonction
                            if ("MENU_FONCTION".equals(monNoeud.getNodeName())) {
                                bNouveauMenu.setEnabled(false);
                                bSupprimerMenu.setEnabled(true);
                                bNouveauMenuF.setEnabled(false);
                                boutonAjouter.setEnabled(false);
                                boutonRetirer.setEnabled(false);  
                            }
                        }
                        // si root
                        else {
                            bNouveauMenu.setEnabled(true);
                            bSupprimerMenu.setEnabled(false);
                            bNouveauMenuF.setEnabled(false);
                            boutonAjouter.setEnabled(false);
                            boutonRetirer.setEnabled(false);  
                        }
                    }
                }
                // si pas de séléction
                else { 
                    bNouveauMenu.setEnabled(false);
                    bSupprimerMenu.setEnabled(false);
                    bNouveauMenuF.setEnabled(false);
                    boutonAjouter.setEnabled(false);
                    boutonRetirer.setEnabled(false); 
                }
            }
        });// fin écouteur JTree
        
        
        // écouteur JList
        maListe.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent evt) { 
                if (selectionCourante != null) {
                    if ( !selectionCourante.equals(treemodel.getRoot()) ) {
                        if ("MENU".equals(monNoeud.getNodeName())) {
                            boutonRetirer.setEnabled(false);
                            if (maListe.getSelectedValue() != null)
                                boutonAjouter.setEnabled(true);
                            else 
                                boutonAjouter.setEnabled(false);
                        }
                        else if ("MENU_FONCTION".equals(monNoeud.getNodeName())) {
                            boutonAjouter.setEnabled(false);
                            boutonRetirer.setEnabled(false);  
                        }
                        else if ("MENU_INSERTION".equals(monNoeud.getNodeName())) {
                            boutonAjouter.setEnabled(false);
                            boutonRetirer.setEnabled(true); 
                        }    
                    }
                    else {
                        boutonAjouter.setEnabled(false);
                        boutonRetirer.setEnabled(false);
                    }
                }
                else {
                    boutonAjouter.setEnabled(false);
                    boutonRetirer.setEnabled(false);
                }
            }
        });// fin écouteur JList
        
        setLayout(new BorderLayout());
        JPanel panelHaut = new JPanel(new FlowLayout());
        add(panelHaut,BorderLayout.NORTH);
        
        // panel Arbre
        final JScrollPane defilementArbre = new JScrollPane(arbre);
        defilementArbre.setPreferredSize(new Dimension(250, 300));
        panelHaut.add(defilementArbre);
        
        // boutons Ajouter Retirer
        final JPanel panelB = new JPanel();
        panelB.setLayout(new BoxLayout(panelB, BoxLayout.Y_AXIS));
        panelHaut.add(panelB);
        
        boutonAjouter = new JButton(new AbstractAction("<- "+Strings.get("bouton.Ajouter")) {
            public void actionPerformed(ActionEvent e) {
                ajouter();
            }
        });
        boutonAjouter.setEnabled(false);
        panelB.add(boutonAjouter);
        
        panelB.add(Box.createVerticalStrut(10));
        
        boutonRetirer = new JButton(new AbstractAction(Strings.get("bouton.Retirer")+" ->") {
            public void actionPerformed(ActionEvent e) {
                retirer();
            }
        });
        boutonRetirer.setEnabled(false);
        panelB.add(boutonRetirer); 
        
        
        // panel liste des éléments
        JPanel panelL = new JPanel(new BorderLayout());
        panelHaut.add(panelL);
        
        maListe.setModel(maListeModele);
        final JScrollPane defilementListe = new JScrollPane(maListe);
        defilementListe.setPreferredSize(new Dimension(90, 300));
        
        JTextField texteRecherche = listeElements.getJTexteRecherche();
        texteRecherche.setText("");
        panelL.add(texteRecherche, BorderLayout.NORTH);
        panelL.add(defilementListe, BorderLayout.CENTER);
        
        // panel boutons du bas
        creerPanelBoutonsBas();
        
        //new DragTreeList(arbre, JListeDesElements);
    }
    
    private void creerPanelBoutonsBas() {
        JPanel panelBoutonsBas = new JPanel(new FlowLayout(FlowLayout.LEFT));
        add(panelBoutonsBas,BorderLayout.SOUTH);
        
        bNouveauMenu = new JButton(new AbstractAction(Strings.get("bouton.NouveauMenu")) {
            public void actionPerformed(ActionEvent e) {
                nouveauMenu();
            }
        });
        bNouveauMenu.setEnabled(true);
        panelBoutonsBas.add(bNouveauMenu);
        
        bSupprimerMenu = new JButton(new AbstractAction(Strings.get("bouton.Supprimer")) {
            public void actionPerformed(ActionEvent e) {
                supprimerMenu();
            }
        });
        bSupprimerMenu.setEnabled(false);
        panelBoutonsBas.add(bSupprimerMenu);
        
        bNouveauMenuF = new JButton(new AbstractAction(Strings.get("bouton.NouveauMenuF")) {
            public void actionPerformed(ActionEvent e) {
                nouveauMenuFonction();
            }
        });
        bNouveauMenuF.setEnabled(false);
        panelBoutonsBas.add(bNouveauMenuF);
    }
    
    
    /**
    * Retire les éléments existants dans un schéma 
    */
    private void retirerElementsExistants(final Node nodeParent) {      
        for (Node n = nodeParent.getFirstChild(); n != null; n = n.getNextSibling())
            if (n instanceof Element && "MENU".equals(n.getNodeName())) {
                retirerElementsExistants(n);
                for (Node nd = n.getFirstChild(); nd != null; nd = nd.getNextSibling())
                   if (nd instanceof Element && "MENU_INSERTION".equals(nd.getNodeName()))
                        elementsExistants.add(((Element)nd).getAttribute("nom"));
            }
        
        
        Object[] elts = elementsExistants.toArray(); 
        
        listeModeleRestant = new DefaultListModel();
        Object[] eltsListe = maListeModele.toArray();
        
        // remplir le nouveau modele
        for (int j = 0; j < eltsListe.length; j++) {
            listeModeleRestant.addElement(eltsListe[j]);
        }
        
        // retirer les éléments existants
        for (int i = 0; i< elts.length; i++) {
            listeModeleRestant.removeElement(elts[i]);
        }
        
        Object[] eltsR = listeModeleRestant.toArray();
        for (int j = 0; j < eltsR.length; j++)
            elementsRestants.add(eltsR[j].toString());
        
        listeRestante.setModel(listeModeleRestant);
    }
    
    
    /**
    * Retourne le modèle de l'arbre
    * @return le DefaultTreeModel
    */
    public DefaultTreeModel getTreeModel() {
        return treemodel;
    }
    
    
    /**
    * Retourne l'arbre
    * @return l'arbre JTree
    */
    public JTree getArbre() {
        return arbre;
    }
    
    
    
    /**
    * Ajouter un élément de la liste à l'arbre JTree
    */
    private void ajouter() {
        Object elementSelectionne = maListe.getSelectedValue();
        
        if (selectionCourante != null) {
            DefaultMutableTreeNode menuSelectionne = (DefaultMutableTreeNode) selectionCourante;
            if (!menuSelectionne.isRoot()) {
                if (elementSelectionne != null) {
                    //ajouter l'élément sélectionné au JTree
                    final Element menu_insertion = enregistrerMenuInsertion(monNoeud, elementSelectionne.toString());
                    
                    DefaultMutableTreeNode nouveauNoeud = new DefaultMutableTreeNode(new InfosNoeud(menu_insertion));
                    treemodel.insertNodeInto(nouveauNoeud, menuSelectionne, menuSelectionne.getChildCount());
                    TreeNode[] nodes = treemodel.getPathToRoot(nouveauNoeud);
                    TreePath path = new TreePath(nodes);
                    arbre.scrollPathToVisible(path);
                    
                    //et le retirer de la JList
                    maListeModele.removeElement(elementSelectionne);
                    //maListe.getSelectionModel().clearSelection();
                    
                    EditeurFichierConfig.setModif(true);
                }
            }
        }
    }
    
    
    /**
    * Retire un élément de l'arbre JTree et le restaurer dans la JList
    */
    private void retirer() {
        //retirer l'élément du JTree
        TreePath currentSelection = arbre.getSelectionPath();
        if (currentSelection != null) {
            DefaultMutableTreeNode noeudCourant = (DefaultMutableTreeNode) (currentSelection.getLastPathComponent());
            MutableTreeNode parent = (MutableTreeNode) (noeudCourant.getParent());
            if (parent != null) {
                treemodel.removeNodeFromParent(noeudCourant);
                
                // supprimer l'élément du DOM
                Element menu_insertion = (Element)monNoeud;
                menu_insertion.getParentNode().removeChild(menu_insertion);
            }
        
            //et l'ajouter dans la JList dans le meme ordre
            maListeModele.addElement(noeudCourant.getUserObject().toString());
            trierListe(maListeModele);
            
            EditeurFichierConfig.setModif(true);
        }
    }
    
    
    /**
    * Restaure les enfants d'un Menu dans la JList
    */
    private void restaurerLesElements(final DefaultMutableTreeNode noeudSelectionne) {
        
        for (DefaultMutableTreeNode n = (DefaultMutableTreeNode)noeudSelectionne.getFirstChild(); n != null; n = n.getNextSibling()) {
            if (!n.isLeaf())
                restaurerLesElements(n);
            else {
                if (n.getUserObject() instanceof InfosNoeud) {
                    InfosNoeud infosNoeud = (InfosNoeud)n.getUserObject();
                    Node noeud = infosNoeud.getNoeud();
                    if ("MENU_INSERTION".equals(noeud.getNodeName()))
                        maListeModele.addElement(n.getUserObject().toString());
                }
            }
        }
        
        trierListe(maListeModele);
    }
    
    /**
    * Trie la liste des nom des éléments par nom croissant
    */
    private void trierListe(final DefaultListModel maListeModele) {
        Object[] contenu = maListeModele.toArray();  
        Arrays.sort(contenu);
        maListeModele.removeAllElements();
        for (int i = 0; i< contenu.length;i++)
            maListeModele.addElement(contenu[i]);
    }
    
    
    /**
    * Crée un nouveau Menu
    */
    private void nouveauMenu() {
        if (monNoeudSelectionne != null) {
            final Element menu = enregistrerMenu(monNoeud, Strings.get("texte.Nouveau"));
        
            DefaultMutableTreeNode nouveauNoeud = new DefaultMutableTreeNode(new InfosNoeud(menu));
            treemodel.insertNodeInto(nouveauNoeud, monNoeudSelectionne, monNoeudSelectionne.getChildCount());
            TreeNode[] nodes = treemodel.getPathToRoot(nouveauNoeud);
            TreePath path = new TreePath(nodes);
            arbre.setEditable(false);
            arbre.scrollPathToVisible(path);
            arbre.setSelectionPath(path);
            //arbre.startEditingAtPath(path);
            
            EditeurFichierConfig.setModif(true);
        }
    }
    
    /**
    * Supprime un Menu ou un Menu fonction
    */
    private void supprimerMenu() {
        if (JOptionPane.showConfirmDialog(this, Strings.get("message.SupprimerCeMenu"), "", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
            if (monNoeudSelectionne != null) {
                MutableTreeNode nparent = (MutableTreeNode) (monNoeudSelectionne.getParent());
                if (nparent != null) {
                    treemodel.removeNodeFromParent(monNoeudSelectionne);
                    
                    //retirer le menu du DOM
                    if (monNoeud != null)
                        monNoeud.getParentNode().removeChild(monNoeud);
                    
                    // restaurer les éléments du menu
                    if (!monNoeudSelectionne.isLeaf())
                        restaurerLesElements(monNoeudSelectionne);
                        
                    EditeurFichierConfig.setModif(true);
                }
            }
        }
    }
    
    
    /**
    * Crée un nouveau Menu Fonction
    */
    private void nouveauMenuFonction() {
        if (monNoeudSelectionne != null) {
            final Element menu_fonction = enregistrerMenuFonction(monNoeud, Strings.get("texte.Nouveau"), null, null);
        
            DefaultMutableTreeNode nouveauNoeud = new DefaultMutableTreeNode(new InfosNoeud(menu_fonction));
            treemodel.insertNodeInto(nouveauNoeud, monNoeudSelectionne, monNoeudSelectionne.getChildCount());
            TreeNode[] nodes = treemodel.getPathToRoot(nouveauNoeud);
            TreePath path = new TreePath(nodes);
            arbre.scrollPathToVisible(path);
            arbre.setSelectionPath(path);
            //arbre.startEditingAtPath(path);
            
            EditeurFichierConfig.setModif(true);
        }
        //panelAffichage.revalidate();
    }
    
    
    
    /**
    * Crée un arbre JTree à partir du DOM
    */
    private void domTree(final Node nodeParent, final DefaultMutableTreeNode noeudRacine) {
        for (Node n = nodeParent.getFirstChild(); n != null; n = n.getNextSibling()) {
            if ("MENU".equals(n.getNodeName())) {
                DefaultMutableTreeNode noeudMenu = new DefaultMutableTreeNode(new InfosNoeud(n));
                noeudRacine.add(noeudMenu);
                domTree(n, noeudMenu);
                
                for (Node nd = n.getFirstChild(); nd != null; nd = nd.getNextSibling()) {
                    if ("MENU_INSERTION".equals(nd.getNodeName())) {
                        DefaultMutableTreeNode noeudMenuInsertion = new DefaultMutableTreeNode(new InfosNoeud(nd));
                        noeudMenu.add(noeudMenuInsertion);
                    }
                    if ("MENU_FONCTION".equals(nd.getNodeName())) {
                        DefaultMutableTreeNode noeudMenuFonction = new DefaultMutableTreeNode(new InfosNoeud(nd));
                        noeudMenu.add(noeudMenuFonction);
                    }
                }
            }
        }
    }
    
    /********************* Operation DOM ************************************/
    // MENU
    private Element enregistrerMenu(final Node elementParent, final String nomM) {
        Element menu = doc.createElement("MENU");
        elementParent.appendChild(menu);
        menu.setAttribute("nom", nomM);
        return menu;
    }
    
    // MENU_FONCTION
    private Element enregistrerMenuFonction(final Node menu, final String nom, final String classe, final String raccourci) {
        Element menu_fonction = doc.createElement("MENU_FONCTION");
        menu.appendChild(menu_fonction);
        menu_fonction.setAttribute("nom", nom);
        if (classe != null)
            menu_fonction.setAttribute("classe", classe);
        if (raccourci != null)
            menu_fonction.setAttribute("raccourci", raccourci);
        
        return menu_fonction;
    }
    
    // MENU_INSERTION
    private Element enregistrerMenuInsertion(final Node menu, final String nom) {
        Element menu_insertion = doc.createElement("MENU_INSERTION");
        menu.appendChild(menu_insertion);
        menu_insertion.setAttribute("nom", nom);
        return menu_insertion;
    }
    
    
    // STRINGS_MENU
    private Element enregistrerStringsMenu(final Element stringsM, final String titre) {
        Element strings_menu = Outils.getElementSelectionne(stringsM, "STRINGS_MENU", titre, "menu");
        if (strings_menu == null) {
            strings_menu = doc.createElement("STRINGS_MENU");
            stringsM.appendChild(strings_menu);
            strings_menu.setAttribute("menu", titre);   
            
            EditeurFichierConfig.setModif(true);
        }
        return strings_menu;
    }
    
}
