/*
 * Copyright
 *   2005 axYus - www.axyus.com
 *   2005 C.Marchand - christophe.marchand@axyus.com
 *   2008 JP.Tessier - jean-philippe.tessier@axyus.com
 *
 * This file is part of XEMELIOS.
 *
 * XEMELIOS 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, or
 * (at your option) any later version.
 *
 * XEMELIOS 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 XEMELIOS; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package fr.gouv.finances.cp.xemelios.ui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.TreeSet;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
import javax.swing.event.InternalFrameAdapter;
import javax.swing.event.InternalFrameEvent;
import javax.swing.event.InternalFrameListener;
import javax.swing.filechooser.FileFilter;
import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.apache.log4j.Logger;
import org.jdesktop.swingx.JXTable;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;

import com.jgoodies.forms.builder.PanelBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;

import fr.gouv.finances.dgfip.utils.Pair;
import fr.gouv.finances.cp.utils.ui.DisplayExceptionDlg;
import fr.gouv.finances.cp.utils.ui.IhmFactory;
import fr.gouv.finances.cp.utils.ui.VerticalFlowLayout;
import fr.gouv.finances.cp.xemelios.ui.collectivites.DlgSelectCollectivite;
import fr.gouv.finances.dgfip.xemelios.auth.XemeliosUser;
import fr.gouv.finances.dgfip.xemelios.common.Constants;
import fr.gouv.finances.dgfip.xemelios.common.DematTransform;
import fr.gouv.finances.dgfip.xemelios.common.ToolException;
import fr.gouv.finances.dgfip.xemelios.common.config.CritereModel;
import fr.gouv.finances.dgfip.xemelios.common.config.CritereRefModel;
import fr.gouv.finances.dgfip.xemelios.common.config.DocumentModel;
import fr.gouv.finances.dgfip.xemelios.common.config.DocumentsModel;
import fr.gouv.finances.dgfip.xemelios.common.config.ElementModel;
import fr.gouv.finances.dgfip.xemelios.common.config.EnvironmentDomain;
import fr.gouv.finances.dgfip.xemelios.common.config.EtatModel;
import fr.gouv.finances.dgfip.xemelios.common.config.PluginModel;
import fr.gouv.finances.dgfip.xemelios.common.config.RechercheModel;
import fr.gouv.finances.dgfip.xemelios.common.config.SavedRequestsModel;
import fr.gouv.finances.dgfip.xemelios.data.DataLayerManager;
import fr.gouv.finances.cp.xemelios.ui.export.DlgSearchConfig;
import fr.gouv.finances.cp.xemelios.ui.resulttable.EtatResultTableModel;
import fr.gouv.finances.cp.xemelios.ui.resulttable.PageSeeker;
import fr.gouv.finances.cp.xemelios.ui.search.SearchThread;
import fr.gouv.finances.cp.xemelios.ui.searchParams.DlgSearchParams;
import fr.gouv.finances.dgfip.utils.IoUtils;
import fr.gouv.finances.dgfip.xemelios.ui.ImageResources;
import fr.gouv.finances.dgfip.xemelios.ui.ListDisplayable;


/**
 * Fenetre de recherche
 * @author Christophe MARCHAND
 */
public class SearchWindow extends JInternalFrame {
    /**
     * Comment for <code>serialVersionUID</code>
     */
    private static final long serialVersionUID = 3257002159676469814L;
    private static Logger logger = Logger.getLogger(SearchWindow.class);
    
    // visual objects
    private JPanel scroller;
    private JScrollPane sc;
    private JPanel mainPane = null;
    private JComboBox colls, budgets;
    private JTextField dfCollectivite;
    private JTable table = null;
    private JSplitPane splitter=null;
    private JButton pbSearch, pbValidateHeader, pbSearchBackground;
    private JButton pbClear, pbSaveRequest;
    private PageSeeker ps = null;
    private JTextField bottomField;
    public MainWindow parentFrame;
    
    // others
    private ElementModel em;
//    private Vector<Pair> collectivites = null;
    private Pair currentBudget, currentCollectivite;
    private String title;
    private ActionListener lineAdder;
    private Vector<CriteriaViewer> criterias;
    private boolean canExport = false;
    private static int frameCount = 1;
    private int rank = 0;
    private PluginModel plugin;
    private boolean pluginSearchEnabled = false;
    private Vector<CritereModel>criteresOp;
    
    private DocumentModel dm = null;
    
    private XemeliosUser user;
    
    
    public SearchWindow(MainWindow pf, DocumentModel dm, ElementModel em,XemeliosUser user) throws ToolException {
        super("Recherche - "+em.getTitre()+" <"+frameCount +">",true,true,true);
        this.parentFrame = pf;
        this.user=user;
        rank = frameCount;
        title = "Recherche - "+em.getTitre()+" <"+frameCount++ +">";
        this.em = em;
        this.dm = dm;
        initComponents();
        em.addPropertyChangeListener(new PropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent evt) {
                if("mode".equals(evt.getPropertyName())) {
                    clearAll();
                }
            }
        });
    }
    
    protected void initComponents() throws ToolException {
        
        mainPane = new JPanel(new BorderLayout());
        IhmFactory iF=IhmFactory.newInstance();
        
        pbValidateHeader = new JButton(IhmFactory.getIconFromResource(ImageResources.ADD));
        pbValidateHeader.setToolTipText("Ajouter un critère de recherche");
        lineAdder = new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                addLine();
            }
        };
        pbValidateHeader.addActionListener(lineAdder);
        pbSearch = new JButton(IhmFactory.getIconFromResource(ImageResources.SEARCH)) {
            private static final long serialVersionUID = 1L;
            @Override
            public void fireActionPerformed(ActionEvent event) {
                parentFrame.startWaiter();
                super.fireActionPerformed(event);
            }
        };
        pbSearch.setToolTipText("Chercher");
        pbSearch.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                search();
            }
        });
        pbSearch.setEnabled(false);
        budgets = new JComboBox();
        
        int collCount = 0;
        try {
            collCount = DataLayerManager.getImplementation().getCollectivitesCount(dm, user);
        } catch(Exception ex) {
            logger.error("while getting collectivites count:",ex);
        }

        if(dm.getCollectivitePath().getParentsCount()==0 || collCount<Constants.MAX_DISPLAYED_COLLECTIVITES) {
            try {
                Vector<Pair> collectivites = DataLayerManager.getImplementation().getCollectivites(dm,null,user);
                colls = new JComboBox(collectivites);
                colls.setSelectedIndex(0);
                colls.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent evt) {
                        Pair bd = (Pair)colls.getSelectedItem();
                        currentCollectivite = bd;
                        Vector<Pair> data = new Vector<Pair>();
                        try {
                            data = DataLayerManager.getImplementation().getBudgets(dm,currentCollectivite,user);
                        } catch(Exception ex) {
                            Component comp2 = SearchWindow.this;
                            while(comp2!=null && !(comp2 instanceof JFrame))
                                comp2 = comp2.getParent();
                            if(comp2!=null)
                                new DisplayExceptionDlg((JFrame)comp2,ex);
                            else
                                ex.printStackTrace();
                        }
                        budgets.removeAllItems();
                        for(Pair c:data) budgets.addItem(c);
                        if(data.size()>0) budgets.setSelectedIndex(0);
                        clearAll();
                        pluginSearchEnabled=false;
                        addLine();
                        pbSaveRequest.setEnabled(true);
                    }
                });
                currentCollectivite=(Pair)colls.getItemAt(0);
            } catch(Exception ex) {
                Component comp2 = this;
                while(comp2!=null && !(comp2 instanceof JFrame))
                    comp2 = comp2.getParent();
                if(comp2!=null)
                    new DisplayExceptionDlg((JFrame)comp2,ex);
                else
                    ex.printStackTrace();
                throw new ToolException(ToolException.ERROR_NO_DATA);
            }
        } else {
            // more than Constants.MAX_DISPLAYED_COLLECTIVITES collectivites
            dfCollectivite = new JTextField();
            dfCollectivite.setColumns(15);
            dfCollectivite.setEditable(false);
            pbValidateHeader.setEnabled(false);
        }
        criterias = new Vector<CriteriaViewer>();
        pbSaveRequest = new JButton(IhmFactory.getIconFromResource(ImageResources.SAVE));
        pbSaveRequest.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                saveRequest();
            }
        });
        pbSaveRequest.setToolTipText("Enregistrer les critères de recherche");
        JButton pbOpenRequest = new JButton(IhmFactory.getIconFromResource(ImageResources.OPEN_REQUEST));
        pbOpenRequest.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                openRequest();
            }
        });
        pbOpenRequest.setToolTipText("Ouvrir une recherche pré-enregistrée");
        pbSearchBackground = new JButton(IhmFactory.getIconFromResource(ImageResources.SEARCH_BG));
        pbSearchBackground.setToolTipText("Rechercher en tâche de fond");
        pbSearchBackground.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                searchBackground();
            }
        });
        pbSearchBackground.setEnabled(false);
        
        JToolBar tb = new JToolBar();
        tb.setRollover(true);
        tb.setFloatable(false);
        tb.add(iF.newLabel(em.getParent().getParent().getLibelleCollectivite(),"normal"));
        if(colls!=null) {
            tb.add(colls);
        } else {
            tb.add(dfCollectivite);
            JButton pbChooseCollectivite = new JButton("...");
            pbChooseCollectivite.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    DlgSelectCollectivite dlg = new DlgSelectCollectivite(dm, user, getParentFrame());
                    if(dlg.run()) {
                        currentCollectivite = dlg.getCollectivite();
                        dfCollectivite.setText(currentCollectivite.libelle);
                        Vector<Pair> data = new Vector<Pair>();
                        try {
                            data = DataLayerManager.getImplementation().getBudgets(dm,currentCollectivite,user);
                        } catch(Exception ex) {
                            Component comp2 = SearchWindow.this;
                            while(comp2!=null && !(comp2 instanceof JFrame))
                                comp2 = comp2.getParent();
                            if(comp2!=null)
                                new DisplayExceptionDlg((JFrame)comp2,ex);
                            else
                                ex.printStackTrace();
                        }
                        budgets.removeAllItems();
                        for(Pair c:data) budgets.addItem(c);
                        if(data.size()>0) budgets.setSelectedIndex(0);
                        clearAll();
                        pluginSearchEnabled=false;
                        addLine();
                        pbSaveRequest.setEnabled(true);
                        pbValidateHeader.setEnabled(true);
                    }
                }
            });
            tb.add(pbChooseCollectivite);
        }
        tb.addSeparator();
        tb.add(iF.newLabel("Code Budget ","normal"));
        tb.add(budgets);
        mainPane.add(tb,BorderLayout.PAGE_START);

        tb = new JToolBar(JToolBar.VERTICAL);
        tb.setRollover(true);
//        tb.addSeparator();
        tb.add(pbValidateHeader);
        tb.add(pbSearch);
        tb.add(pbSearchBackground);
        tb.add(pbClear = new JButton(IhmFactory.getIconFromResource(ImageResources.CLEAR_ALL)));
        if(em.getParent()==null) throw new RuntimeException("elementModel.getParent() is null");
        if(em.getParent().getParent()==null) throw new RuntimeException("etatModel.getParent() is null");
        if(em.getParent().getParent().getReferentielXsltFile()!=null) {
            JButton pbShowReferentiel;
            tb.addSeparator();
            tb.add(pbShowReferentiel = new JButton(IhmFactory.getIconFromResource(ImageResources.REFERENTIEL)));
            pbShowReferentiel.setToolTipText("Afficher la nomenclature");
            pbShowReferentiel.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    showReferentiel();
                }
            });
        }
        tb.addSeparator();
        tb.add(pbSaveRequest);
        tb.add(pbOpenRequest);
        tb.addSeparator();
        JButton pbEnvironment = new JButton(IhmFactory.getIconFromResource(ImageResources.ENVIRONMENT));
        tb.add(pbEnvironment);
        
        pbEnvironment.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                DlgEditEnvironment dee = new DlgEditEnvironment(getParentFrame(),em,EnvironmentDomain.DOMAIN_ELEMENT);
                dee.setVisible(true);
            }
        });
        pbEnvironment.setToolTipText("Modifier les paramètres d'environnement de recherche.");

//        if("true".equals(System.getProperty(Constants.SYS_PROP_SORTFIELDS))) {
            JButton pbSortFields = new JButton(IhmFactory.getIconFromResource(ImageResources.SORT_FIELDS));
            pbSortFields.setToolTipText("Champs et tris");
            pbSortFields.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    DlgSearchParams dsp = new DlgSearchParams(MainWindow.instance, true, em.getListeResultat());
                    dsp.setVisible(true);
                }
            });
            tb.addSeparator();
            tb.add(pbSortFields);
//        }
        mainPane.add(tb,BorderLayout.BEFORE_LINE_BEGINS);
        
        pbClear.setEnabled(false);
        pbClear.setToolTipText("Supprimer tous les critères");
        pbClear.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                clearAll();
                pluginSearchEnabled=false;
                addLine();
                pbSaveRequest.setEnabled(true);
            }
        });
        
// ajout de la zone pour les criteres
        scroller = new JPanel(new VerticalFlowLayout(VerticalFlowLayout.TOP,0,0));
        sc = new JScrollPane(scroller);
        validateHeader();
        sc.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        
        splitter = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
        splitter.setLeftComponent(sc);
        splitter.setRightComponent(new JPanel());
        mainPane.add(splitter,BorderLayout.CENTER);
        
        JPanel bottomPane = new JPanel(new BorderLayout());
        bottomField = new JTextField();
        bottomField.setEditable(false);
        bottomField.setBackground(bottomPane.getBackground());
        bottomField.setBorder(BorderFactory.createEmptyBorder());
        bottomField.setColumns(50);
        bottomPane.add(bottomField,BorderLayout.WEST);
        
        ps = new PageSeeker(this);
        bottomPane.add(ps,BorderLayout.EAST);
        mainPane.add(bottomPane,BorderLayout.SOUTH);
        
        getRootPane().setDefaultButton(pbSearch);
        
        InternalFrameListener adapter = new InternalFrameAdapter() {
            @Override
            public void internalFrameClosing(InternalFrameEvent e) {
                clearResources();
                notifyParentStateChanged();
            }
            @Override
            public void internalFrameIconified(InternalFrameEvent e) {
                setTitle(em.getTitre()+" <"+rank+">");
                notifyParentStateChanged();
            }
            @Override
            public void internalFrameDeiconified(InternalFrameEvent e) {
                setTitle(title);
                notifyParentStateChanged();
            }
            @Override
            public void internalFrameActivated(InternalFrameEvent e) {
                moveToFront();
                notifyParentStateChanged();
            }
        };
        addInternalFrameListener(adapter);
        setContentPane(mainPane);
        setIconifiable(true);
        
        if(colls!=null) {
            Vector<Pair> data = new Vector<Pair>();
            try {
                data = DataLayerManager.getImplementation().getBudgets(dm,currentCollectivite,user);
            } catch(Exception ex) {
                Component comp2 = SearchWindow.this;
                while(comp2!=null && !(comp2 instanceof JFrame))
                    comp2 = comp2.getParent();
                if(comp2!=null)
                    new DisplayExceptionDlg((JFrame)comp2,ex);
                else
                    ex.printStackTrace();
            }
            budgets.removeAllItems();
            for(Pair c:data) budgets.addItem(c);
            if(data.size()>0) budgets.setSelectedIndex(0);
    //        tb.doLayout();
            validateHeader();
        }
        budgets.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                clearAll();
                validateHeader();
            }
        });
        
        pack();
        splitter.setDividerLocation(100);
    }
    protected void clearResources() {
        em = null;
        dm=null;
        if(table!=null) {
            JXTable latable = (JXTable)table;
            EtatResultTableModel etrm = (EtatResultTableModel)latable.getModel();
            etrm.getResultSet().clear();
            etrm.dispose();
        }
    }
    protected void validateHeader() {
        currentBudget = (Pair)budgets.getSelectedItem();
//        currentCollectivite = (Pair)colls.getSelectedItem();
        if(currentBudget!=null && currentCollectivite!=null) {
            pbSearch.setEnabled(true);
            pbSearchBackground.setEnabled(true);
            addLine();
        }
    }
    public void search() {
        SearchThread searcher = null;
        setSearchEnabled(false);
        try {        	
            setCursor(new Cursor(Cursor.WAIT_CURSOR));
            searcher = new SearchThread(this,em,currentCollectivite,currentBudget,criterias,plugin);
            SwingUtilities.invokeLater(searcher);        		
        } catch(OutOfMemoryError oomErr) {
            searcher.exceptionDuringProcess = oomErr;
        } finally {
        }
    }
    public void searchBackground() {
        SearchThread searcher = null;
        setSearchEnabled(false);
        try {
            searcher = new SearchThread(this,em,currentCollectivite,currentBudget,criterias,plugin,true);
            SwingUtilities.invokeLater(searcher);
        } catch(OutOfMemoryError oomErr) {
            searcher.exceptionDuringProcess = oomErr;
        } finally {
        }
    }
    public CriteriaViewer addLine() {
//logger.debug("addLine()");
    	CriteriaViewer cv = null;
    	if (pluginSearchEnabled) {
    		cv = new CriteriaViewer(this,em,currentCollectivite,currentBudget, (criterias.size()==0), criteresOp);
    	} else {
    		cv = new CriteriaViewer(this,em,currentCollectivite,currentBudget,(criterias.size()==0));
    	}
        criterias.add(cv);
        if(pbClear!=null) {
            pbClear.setEnabled(true);
            setSearchEnabled(true);
        }
        if(scroller!=null)
            scroller.add(cv);
        if(isVisible()) {
            cv.setVisible(true);
            scroller.validate();
            Rectangle rect = cv.getBounds();
            Point p = new Point(0,(int)((criterias.size())*rect.getHeight())-1);
            sc.getViewport().setViewPosition(p);
            repaintCriterias();
        }
        return cv;
    }
    protected CriteriaViewer addLineNoCriteria() {
        CriteriaViewer cv = new CriteriaViewer(this,em,currentCollectivite,currentBudget,true,true);
        CriteriaViewer lastCrit = (criterias.size()>0?criterias.get(criterias.size()-1):cv);
        criterias.add(cv);
        if(pbClear!=null) {
            pbClear.setEnabled(true);
            setSearchEnabled(true);
        }
        if(scroller!=null)
            scroller.add(cv);
        if(isVisible()) {
            cv.setVisible(true);
            scroller.validate();
            Rectangle rect = lastCrit.getBounds();
            Point p = new Point(0,(int)((criterias.size())*rect.getHeight())-1);
            sc.getViewport().setViewPosition(p);
            repaintCriterias();
        }
//        if(isVisible()) {
//            cv.setVisible(true);
//            splitter.setDividerLocation(-1);
//            repaintCriterias();
//        }
        return cv;
    }
    protected void removeLine(CriteriaViewer whichOne) {
        scroller.remove(whichOne);
        criterias.remove(whichOne);
        if(criterias.size()==0) {
            setSearchEnabled(false);
        }
        repaintCriterias();
    }
    protected void repaintCriterias() {
        if(!isVisible()) return;
        scroller.getSize();
        sc.setViewportView(scroller);
        getDesktopPane().getDesktopManager().beginResizingFrame(this,0);
        Rectangle r = getBounds();
        getDesktopPane().getDesktopManager().resizeFrame(this,r.x,r.y,r.width,r.height);
        getDesktopPane().getDesktopManager().endResizingFrame(this);
    }
    public void exportCSV() {
        if(!canExport()) return;
        EtatResultTableModel ertm  =(EtatResultTableModel)table.getModel();
        JFileChooser fc = new JFileChooser();
        fc.setFileFilter(new FileFilter(){
            @Override
            public boolean accept(File f) {
                return f.isDirectory() || f.getName().toUpperCase().endsWith(".CSV");
            }
            @Override
            public String getDescription() { return "Fichier CSV"; }
        });
        ExportOptionPane eop = new ExportOptionPane();
        fc.setAccessory(eop);
        if(fc.showSaveDialog(this)==JFileChooser.APPROVE_OPTION) {
            File f = fc.getSelectedFile();
            // verification de la presence d'une extension
            // on cherche un '.' aux positions len-1, len-2, len-3, len-4
            String fileName = f.getAbsolutePath();
            int len = fileName.length();
            if(fileName.substring(len-4).indexOf('.')<0) {
                fileName=fileName+".CSV";
                f = new File(fileName);
            }
            if(f.exists()) {
                if(JOptionPane.showConfirmDialog(getParentFrame(),fileName+"\nCe fichier existe déjà. Voulez-vous l'écraser ?","Ecrasement",JOptionPane.YES_NO_OPTION)==JOptionPane.NO_OPTION)
                    return;
            }
            MainWindow.fieldSeparator = eop.getSeparator();
            String out = null;
            int[] selectedRows = table.getSelectedRows();
            out = ertm.getCsvBuffer(MainWindow.fieldSeparator,eop.getExportAll(),selectedRows);
            try {
                FileWriter fw = new FileWriter(f);
                fw.write(out);
                fw.flush();
                fw.close();
            } catch(IOException ioEx) {
                Component comp = this;
                while(comp!=null && !(comp instanceof JFrame))
                    comp = comp.getParent();
                new DisplayExceptionDlg((JFrame)comp,ioEx);
            }
        }
    }

    public void exportXLS() {
        if(!canExport()) return;
        EtatResultTableModel ertm  =(EtatResultTableModel)table.getModel();

        DocumentsModel dmsTmp = new DocumentsModel (DocumentsModel.QN);
        DocumentModel dmTmp = dm.clone();
        
		// on ne garde dans dm que l'EtatModel qui a l'ElementModel em
		HashMap<String, EtatModel> hTmp = dmTmp.getHEtats();
		HashMap<String, EtatModel> hTmp2 = new HashMap<String, EtatModel> ();
		Vector<EtatModel> vTmp2 = new Vector<EtatModel>();
		for (String k:hTmp.keySet()) {
			EtatModel emTmp = (EtatModel)hTmp.get(k);
			if (emTmp.getElementById(em.getId()) != null) {
				hTmp2.put (emTmp.getId(), emTmp);
				vTmp2.add(emTmp);
				dmTmp.setVEtats(vTmp2);
				dmTmp.setHEtats(hTmp2);
				break;
			}
		}
		try { dmsTmp.addChild(dmTmp, DocumentModel.QN); } catch (Throwable t) {}
        
        DlgSearchConfig sc = new DlgSearchConfig (getParentFrame(), dmsTmp,DlgSearchConfig.EXEC_FROM_RECHERCHE,user);
        sc.setErtm(ertm);
        sc.setEm(em);
        sc.setDm(dm);
        sc.setVisible(true);
    }
    public boolean canExport() {
        return canExport && !(isIcon());
    }
    public void notifyParentStateChanged() {
        MainWindow mw = parentFrame;
        mw.innerWindowChanged();
        System.gc();
    }
    public void clearAll() {
        plugin=null;
        pbValidateHeader.setEnabled(true);
        if(criterias==null) return;
        while(criterias.size()>0) {
            removeLine(criterias.elementAt(criterias.size()-1));
        }
    }
    protected void showReferentiel() {
        try {
        	// TODO : fusion nomenclatures pour afficher le referentiel 
            Vector<Document> vXmlData = DataLayerManager.getImplementation().getRepositorysAsDom(dm,currentCollectivite,user);
            if(vXmlData.size()==0) {
                JOptionPane.showMessageDialog(parentFrame, "Pas de nomenclature disponible");
                return;
            }
            
			XPath xp = XPathFactory.newInstance().newXPath();
			xp.setNamespaceContext(new LocalNSCtx(em.getParent().getParent().getNamespaces().getNamespaceURI("n")));
            
			Vector<Node> vRepository=new Vector<Node>();
			Node repository;
			for(Document docXml:vXmlData){
            	repository = (Node)xp.evaluate("//n:"+em.getParent().getParent().getReferentiel(),docXml.getDocumentElement(),XPathConstants.NODE);
            	vRepository.add(repository);
			}
			Document docRoot = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
			
			Element el = docRoot.createElementNS(vXmlData.get(0).getDocumentElement().getNamespaceURI(),vXmlData.get(0).getDocumentElement().getNodeName());
			docRoot.appendChild(el);
			//docRoot.appendChild(docRoot.adoptNode(vXmlData.get(0).getDocumentElement()));
				
			for(int i=0;i<vXmlData.get(0).getDocumentElement().getChildNodes().getLength();i++){
				Node current = vXmlData.get(0).getDocumentElement().getChildNodes().item(i);
				if(!current.getNodeName().equals("Nomenclatures") && Node.TEXT_NODE!=current.getNodeType()){
					docRoot.adoptNode(current);
					docRoot.getDocumentElement().appendChild(current);
				}
			}
			
			if (vRepository != null && vRepository.size() > 0) {
				for (int i = 0; i < vRepository.size(); i++) {
					Node nomencl = vRepository.get(i);
                    if(nomencl!=null) {
                        docRoot.adoptNode(nomencl);
                        docRoot.getDocumentElement().appendChild(nomencl);
                    }
				}
			}
			
            File f = new File(new File(dm.getBaseDirectory()),dm.getReferentielXsltFile());
            InputStream is = IoUtils.getInputStream(f.getPath());
            //InputStream htmlStream = DematTransform.transform(new ByteArrayInputStream(sXmlData.getBytes(encoding)),is,encoding);
            InputStream htmlStream = DematTransform.transform(docRoot.getDocumentElement(),is,f.getParentFile().toURI().toURL().toExternalForm());
            parentFrame.displayHtmlStream(htmlStream,em.getParent(),getDesktopPane());
            
        } catch(Exception ex) {
            new DisplayExceptionDlg(parentFrame,ex);
        }
    }
    private void saveRequest() {
        String requestName = getRequestName();
        if(requestName==null || requestName.length()==0) return;
        RechercheModel rm = new RechercheModel(RechercheModel.QN,requestName);
        for(CriteriaViewer cv:criterias) {
            try {
                rm.addChild(cv.getXmlMarshallable(),CritereModel.QN);
            } catch(SAXException ignore) {
                // pour le moment, on la jette bien violement
                ignore.printStackTrace();
            }
        }
        parentFrame.getSavedRequest(em).add(rm);
        try {
            DataLayerManager.getImplementation().saveRequest(getELementModel(), rm, getUser());
        } catch(Exception ex) {
            logger.error(ex);
        }

    }
    private void openRequest() {
        String persistence = null;
        try {
            persistence = DataLayerManager.getImplementation().getLayerName();
        } catch(Throwable t) {}
        SavedRequestsModel srm = parentFrame.getSavedRequest(em);
        TreeSet<ListDisplayable> data = new TreeSet<ListDisplayable>();
        data.addAll(srm.getRecherches());
        Vector<PluginModel> plugins = em.getPlugins();
        for(PluginModel pm:plugins) {
            if((pm.getPluginType().equals(PluginModel.TYPE_SEARCH) || pm.getPluginType().equals(PluginModel.TYPE_EXPORT)) && pm.isAvailableFor(persistence)) {
                data.add(pm);
            }
        }
        Vector<ListDisplayable> vData = new Vector<ListDisplayable>();
        vData.addAll(data);
        DlgSelectRequest dsr = new DlgSelectRequest(parentFrame,vData,em);
        if(dsr.run()) {
            ListDisplayable xm = (ListDisplayable)dsr.getSelectedItem();
            if(xm instanceof RechercheModel) {
                pluginSearchEnabled = false;
                RechercheModel rm = (RechercheModel)xm;
                clearAll();
                for(CritereModel cm:rm.getCriteres()) {
                    CriteriaViewer cv = addLine();
                    cv.changeCritereModel(cm);
                }
                pbSaveRequest.setEnabled(true);
            } else if(xm instanceof PluginModel) {
                pluginSearchEnabled = true;
                PluginModel pm = (PluginModel)xm;
                clearAll();
                plugin = pm.clone();
                pbValidateHeader.setEnabled(false);
                for(CritereModel cm:pm.getCriteres()) {
                    CriteriaViewer cv = addLineNoCriteria();
                    cv.changeCritereModel(cm.clone());
                    criterias.add(cv);
                }
                // debug
                if (pm.getCriteresOp().size()>0) {
                	pbValidateHeader.setEnabled(true);                	
                }
                criteresOp = new Vector<CritereModel>();
                for (CritereRefModel cmr:pm.getCriteresOp()) {
                	CritereModel cm = em.getCritere(cmr.getIdRef());
                	criteresOp.add(cm);
                }
                // debug
                pbSaveRequest.setEnabled(false);
            }
        }
    }
    public void setSearchEnabled(boolean enableIt) {
        pbSearch.setEnabled(enableIt);
        pbSearchBackground.setEnabled(enableIt);
    }
    public String getRequestName() {
        return JOptionPane.showInputDialog(this,"Veuillez saisir un nom pour cette recherche :","Valeur par défaut");
    }
    public void redisplayTitle() {
        setTitle(title);
    }
    public void setBottomText(String txt) {
        bottomField.setText(txt);
    }
    public void setCanExport(boolean how) { canExport=how; }
    
    // petit thread pour reafficher la boite dans l'EDT
    public static class DisplayErrorSearchThread implements Runnable {
        private SearchWindow sw;
        private Object obj;
        private ToolException tEx;
        public DisplayErrorSearchThread(SearchWindow sw, ToolException tEx, Object objToFocus) {
            super();
            this.sw=sw;
            this.obj=objToFocus;
            this.tEx=tEx;
        }
        public void run() {
            JOptionPane.showMessageDialog(sw,tEx.getMessage(),"",JOptionPane.WARNING_MESSAGE);
            sw.setSearchEnabled(true);
            if(obj!=null) ((CriteriaViewer)(obj)).doFocusOnError();
        }
    };
    
    private class ExportOptionPane extends JPanel {
        /**
         * Comment for <code>serialVersionUID</code>
         */
        private static final long serialVersionUID = 1L;
        boolean allSelection = false;
        String separator = MainWindow.fieldSeparator;
        private JTextField fldSep;
        private JRadioButton rbAll, rbSelection;
        
        public ExportOptionPane() {
            super();
            initComponents();
        }
        private void initComponents() {
            FormLayout fl = new FormLayout("1dlu,pref,1dlu","1dlu,pref,1dlu,pref,4dlu,pref,1dlu,pref,1dlu");
            CellConstraints cc = new CellConstraints();
            PanelBuilder pb = new PanelBuilder(fl,this);
            IhmFactory iF=IhmFactory.newInstance();
            
            int col = 2;
            int start = 2;
            
            pb.add(iF.newLabel("Séparateur"),				cc.xy(col,0+start));
            pb.add(fldSep = new JTextField(separator),		cc.xy(col,2+start));
            pb.add(rbSelection = new JRadioButton("Séléction"), cc.xy(col,4+start));
            pb.add(rbAll = new JRadioButton("Tout"),		cc.xy(col,6+start));
            ButtonGroup bg = new ButtonGroup();
            bg.add(rbSelection); bg.add(rbAll);
            rbAll.setSelected(true);
            
            setVisible(true);
        }
        
        public String getSeparator() {
            String sep = fldSep.getText();
            if("\\t".equals(sep)) sep = "\t";
            return sep;
        }
        public boolean getExportAll() {
            return rbAll.isSelected();
        }
    }
    public static class ExportOptionPaneXLS extends JPanel {
        /**
         * Comment for <code>serialVersionUID</code>
         */
        private static final long serialVersionUID = 1L;
        boolean allSelection = false;
        private JRadioButton rbAll, rbSelection;
        
        public ExportOptionPaneXLS() {
            super();
            initComponents();
        }
        private void initComponents() {
            FormLayout fl = new FormLayout("1dlu,pref,1dlu","1dlu,pref,1dlu,pref,4dlu,pref,1dlu,pref,1dlu");
            CellConstraints cc = new CellConstraints();
            PanelBuilder pb = new PanelBuilder(fl,this);
            IhmFactory iF=IhmFactory.newInstance();
            
            int col = 2;
            int start = 2;
            
            pb.add(rbSelection = new JRadioButton("Séléction"), cc.xy(col,4+start));
            pb.add(rbAll = new JRadioButton("Tout"),		cc.xy(col,6+start));
            ButtonGroup bg = new ButtonGroup();
            bg.add(rbSelection); bg.add(rbAll);
            rbAll.setSelected(true);
            
            setVisible(true);
        }
        
        public boolean getExportAll() {
            return rbAll.isSelected();
        }
    }
    public MainWindow getParentFrame() {
        return parentFrame;
    }
    public void setTable(JTable table) { this.table=table; }
    public JTable getTable() { return table; }
    public JSplitPane getSplitter() { return splitter; }
    public PageSeeker getPageSeeker() { return ps; }
    public ElementModel getELementModel() { return em; }
    public Pair getCurrentCollectivite() { return currentCollectivite; }
    public Pair getCurrentBudget() { return currentBudget; }
    public PluginModel getPluginModel() {
        return this.plugin;
    }
    public DocumentModel getDocumentModel() {
        return this.dm;
    }
    
    @Override
    public void setVisible(boolean visible) {
        if(!visible && em!=null) {
            Iterator<PropertyChangeListener> it = em.getPropertyListeners();
            if(it!=null) {
                while(it.hasNext()) {
                    it.next();
                    it.remove();
                }
            }
        }
        super.setVisible(visible);
    }
    
    public void setCollectivite(Pair collectivite) {
        colls.setSelectedItem(collectivite);
    }
    public void setBudget(Pair budget) {
        budgets.setSelectedItem(budget);
    }
    
    public boolean isEtatExportable () {
    	if (dm==null) return false;
    	for (EtatModel etat:dm.getEtats()) {
   			ElementModel elem = etat.getElementById(em.getId());
   			if (elem!=null && etat.isExportable()) return true;
    	}
    	return false;
    }
    private static class LocalNSCtx implements NamespaceContext {
    	private static String URI;
    	
    	public LocalNSCtx(String uri){
    		URI=uri;
    	}
    	
        public String getNamespaceURI(String prefix) {
            if("".equals(prefix)) return XMLConstants.NULL_NS_URI;
            else if("n".equals(prefix)) return URI;
            else if(XMLConstants.XML_NS_PREFIX.equals(prefix)) return XMLConstants.XML_NS_URI;
            else if(XMLConstants.XMLNS_ATTRIBUTE.equals(prefix)) return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
            else return XMLConstants.NULL_NS_URI;
        }

        public String getPrefix(String namespaceURI) {
            if(URI.equals(namespaceURI)) return "n";
            else if(XMLConstants.XML_NS_URI.equals(namespaceURI)) return XMLConstants.XML_NS_PREFIX;
            else if(XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI)) return XMLConstants.XMLNS_ATTRIBUTE;
            else return XMLConstants.DEFAULT_NS_PREFIX;
        }

        public Iterator getPrefixes(String namespaceURI) {
            return new StringIterator(getPrefix(namespaceURI));
        }
    }
    private static class StringIterator<String> implements Iterator<String> {
        private String s;
        private boolean get = false;
        public StringIterator(String s) {
            super();
            this.s=s;
        }

        public boolean hasNext() {
            return !get;
        }

        public String next() {
            get = true;
            return s;
        }

        public void remove() {
            throw new UnsupportedOperationException("Not supported yet.");
        }
    }
    public XemeliosUser getUser() { return user; }
}
