/*
 * iReport - Visual Designer for JasperReports.
 * Copyright (C) 2002 - 2009 Jaspersoft Corporation. All rights reserved.
 * http://www.jaspersoft.com
 *
 * Unless you have purchased a commercial license agreement from Jaspersoft,
 * the following license terms apply:
 *
 * This program is part of iReport.
 *
 * iReport is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * iReport 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with iReport. If not, see <http://www.gnu.org/licenses/>.
 */
package com.jaspersoft.ireport.designer.data.fieldsproviders.xml;

import com.jaspersoft.ireport.locale.I18n;
import com.jaspersoft.ireport.designer.FieldsProviderEditor;
import com.jaspersoft.ireport.designer.IReportConnection;
import com.jaspersoft.ireport.designer.IReportManager;
import com.jaspersoft.ireport.designer.data.ReportQueryDialog;
import com.jaspersoft.ireport.designer.utils.Misc;
import java.util.Enumeration;
import java.util.List;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.xml.transform.TransformerException;
import net.sf.jasperreports.engine.design.JRDesignField;
import com.sun.org.apache.xpath.internal.CachedXPathAPI;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.util.xml.JRXPathExecuter;
import net.sf.jasperreports.engine.util.xml.JRXPathExecuterUtils;
import org.openide.util.Exceptions;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 *
 * @author  gtoffoli
 */
public class XMLFieldMappingEditor extends javax.swing.JPanel  implements FieldsProviderEditor {
    
    private String xpathExpression = null;
    private Document document = null;
    //private CachedXPathAPI xpathAPI = new CachedXPathAPI();

    private JRXPathExecuter xpathExecuter = null;
    private ReportQueryDialog reportQueryDialog = null;

    public ReportQueryDialog getReportQueryDialog() {
        return reportQueryDialog;
    }

    public void setReportQueryDialog(ReportQueryDialog reportQueryDialog) {
        this.reportQueryDialog = reportQueryDialog;
    }
    private List recordNodes = new java.util.ArrayList();

    public List getRecordNodes() {
        return recordNodes;
    }

    public void setRecordNodes(List recordNodes) {
        this.recordNodes = recordNodes;
    }

   
    public Document getDocument() {
        return document;
    }

    public void setDocument(Document document) {
        this.document = document;
    }

    public String getXpathExpression() {
        return xpathExpression;
    }

    public void setXpathExpression(String xpathExpression) {
        this.xpathExpression = xpathExpression;
    }


    
    
    /** Creates new form XMLFieldMappingEditor 
     * @param rqd 
     */
    public XMLFieldMappingEditor(ReportQueryDialog rqd) {
        initComponents();
        try {
            Thread.currentThread().setContextClassLoader( IReportManager.getReportClassLoader());
            xpathExecuter = JRXPathExecuterUtils.getXPathExecuter();
        } catch (JRException ex) {
           ex.printStackTrace();
        }
        this.reportQueryDialog = rqd;
        jTree1.setCellRenderer(new XMLDocumentTreeCellRenderer(this));
        jTree1.setTransferHandler( new XMLTreeTransfertHandler( this ));
        setXpathExpression( rqd.getQueryEditorPane().getText() );
        updateView();
        
        //applyI18n();
    }
    
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        jPopupMenuFields = new javax.swing.JPopupMenu();
        jMenuItemSetRecordNode = new javax.swing.JMenuItem();
        jMenuItemChangeRoot = new javax.swing.JMenuItem();
        jSeparator2 = new javax.swing.JSeparator();
        jMenuItemAddField = new javax.swing.JMenuItem();
        jMenuItemAddAbsoluteField = new javax.swing.JMenuItem();
        jSeparator1 = new javax.swing.JSeparator();
        jMenuItemExpandAll = new javax.swing.JMenuItem();
        jMenuItemCollapseAll = new javax.swing.JMenuItem();
        jMenuItemRefresh = new javax.swing.JMenuItem();
        jScrollPane1 = new javax.swing.JScrollPane();
        jTree1 = new javax.swing.JTree();
        jPanel1 = new javax.swing.JPanel();
        jLabelHelp = new javax.swing.JLabel();

        jPopupMenuFields.addPopupMenuListener(new javax.swing.event.PopupMenuListener() {
            public void popupMenuCanceled(javax.swing.event.PopupMenuEvent evt) {
            }
            public void popupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent evt) {
            }
            public void popupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {
                jPopupMenuFieldsPopupMenuWillBecomeVisible(evt);
            }
        });

        jMenuItemSetRecordNode.setText(I18n.getString("XMLFieldMappingEditor.Menu.RecordNode")); // NOI18N
        jMenuItemSetRecordNode.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItemSetRecordNodeActionPerformed(evt);
            }
        });
        jPopupMenuFields.add(jMenuItemSetRecordNode);

        jMenuItemChangeRoot.setText(I18n.getString("XMLFieldMappingEditor.Menu.DocRoot")); // NOI18N
        jMenuItemChangeRoot.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItemChangeRootActionPerformed(evt);
            }
        });
        jPopupMenuFields.add(jMenuItemChangeRoot);
        jPopupMenuFields.add(jSeparator2);

        jMenuItemAddField.setText(I18n.getString("XMLFieldMappingEditor.Menu.AddNode")); // NOI18N
        jMenuItemAddField.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItemAddFieldActionPerformed(evt);
            }
        });
        jPopupMenuFields.add(jMenuItemAddField);

        jMenuItemAddAbsoluteField.setText(I18n.getString("XMLFieldMappingEditor.Menu.AddNode2")); // NOI18N
        jMenuItemAddAbsoluteField.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItemAddAbsoluteFieldActionPerformed(evt);
            }
        });
        jPopupMenuFields.add(jMenuItemAddAbsoluteField);
        jPopupMenuFields.add(jSeparator1);

        jMenuItemExpandAll.setText(I18n.getString("XMLFieldMappingEditor.Menu.Expand")); // NOI18N
        jMenuItemExpandAll.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItemExpandAllActionPerformed(evt);
            }
        });
        jPopupMenuFields.add(jMenuItemExpandAll);

        jMenuItemCollapseAll.setText(I18n.getString("XMLFieldMappingEditor.Menu.Collapse")); // NOI18N
        jMenuItemCollapseAll.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItemCollapseAllActionPerformed(evt);
            }
        });
        jPopupMenuFields.add(jMenuItemCollapseAll);

        jMenuItemRefresh.setText(I18n.getString("XMLFieldMappingEditor.Menu.ResRefDoc")); // NOI18N
        jMenuItemRefresh.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItemRefreshActionPerformed(evt);
            }
        });
        jPopupMenuFields.add(jMenuItemRefresh);

        setMinimumSize(new java.awt.Dimension(250, 23));
        setPreferredSize(new java.awt.Dimension(280, 322));
        setLayout(new java.awt.BorderLayout());

        jScrollPane1.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jScrollPane1MouseClicked(evt);
            }
        });

        jTree1.setDragEnabled(true);
        jTree1.setMinimumSize(new java.awt.Dimension(73, 64));
        jTree1.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jTree1MouseClicked(evt);
            }
            public void mousePressed(java.awt.event.MouseEvent evt) {
                jTree1MousePressed(evt);
            }
        });
        jScrollPane1.setViewportView(jTree1);

        add(jScrollPane1, java.awt.BorderLayout.CENTER);

        jPanel1.setBackground(new java.awt.Color(255, 255, 204));
        jPanel1.setLayout(new java.awt.GridBagLayout());

        jLabelHelp.setBackground(new java.awt.Color(255, 255, 204));
        jLabelHelp.setText(I18n.getString("XMLFieldMappingEditor.Label.Info")); // NOI18N
        jLabelHelp.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4);
        jPanel1.add(jLabelHelp, gridBagConstraints);

        add(jPanel1, java.awt.BorderLayout.NORTH);
    }// </editor-fold>//GEN-END:initComponents

    private void jMenuItemCollapseAllActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemCollapseAllActionPerformed
    expandAll(jTree1, false);
}//GEN-LAST:event_jMenuItemCollapseAllActionPerformed

private void jMenuItemExpandAllActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemExpandAllActionPerformed
    expandAll(jTree1, true);
}//GEN-LAST:event_jMenuItemExpandAllActionPerformed

public void expandAll(JTree tree, boolean expand) {
        TreeNode root = (TreeNode)tree.getModel().getRoot();
        // Traverse tree from root
        expandAll(tree, new TreePath(root), expand);
    }

private void expandAll(JTree tree, TreePath parent, boolean expand) {
    // Traverse children
    TreeNode node = (TreeNode)parent.getLastPathComponent();
    if (node.getChildCount() >= 0) {
        for (Enumeration e=node.children(); e.hasMoreElements(); ) {
            TreeNode n = (TreeNode)e.nextElement();
            TreePath path = parent.pathByAddingChild(n);
            expandAll(tree, path, expand);
        }
    }
    // Expansion or collapse must be done bottom-up
    if (expand) {
        tree.expandPath(parent);
    } else {
        tree.collapsePath(parent);
    }
}



private void jMenuItemAddAbsoluteFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemAddAbsoluteFieldActionPerformed
    TreePath tp = jTree1.getSelectionPath();
    
    if (tp == null) return;
    
    JRDesignField field = createField(tp, false);
    if (field != null)
    {
        getReportQueryDialog().addField(field);
    }
}//GEN-LAST:event_jMenuItemAddAbsoluteFieldActionPerformed

private void jMenuItemAddFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemAddFieldActionPerformed
    TreePath tp = jTree1.getSelectionPath();
    
    if (tp == null) return;
    
    JRDesignField field = createField(tp, true);
    if (field != null)
    {
        getReportQueryDialog().addField(field);
    }
}//GEN-LAST:event_jMenuItemAddFieldActionPerformed

private void jMenuItemChangeRootActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemChangeRootActionPerformed
    
    TreePath tp = jTree1.getSelectionPath();
    
    if (tp == null) return;
    
    Node newRoot = (Node)((DefaultMutableTreeNode)tp.getLastPathComponent()).getUserObject();
    
    jTree1.setModel(new DefaultTreeModel( this.addTreeDocument(newRoot)  ));
    
}//GEN-LAST:event_jMenuItemChangeRootActionPerformed

private void jTree1MouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jTree1MouseClicked
    if (SwingUtilities.isRightMouseButton(evt) && evt.getClickCount() == 1)
    {
        Misc.ensurePathIsSelected(jTree1.getPathForLocation(evt.getX(), evt.getY() ), jTree1);
        jPopupMenuFields.show(jTree1, evt.getX(), evt.getY());
     
    }
}//GEN-LAST:event_jTree1MouseClicked

private void jScrollPane1MouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jScrollPane1MouseClicked
    /*
    evt.setSource( jTree1 );
    Point p2 = SwingUtilities.convertPoint(jScrollPane1, evt.getPoint(), jTree1);
    evt.translatePoint(p2.x - evt.getX() , p2.y - evt.getY());
    jTree1MouseClicked(evt);
    */
}//GEN-LAST:event_jScrollPane1MouseClicked

private void jMenuItemSetRecordNodeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemSetRecordNodeActionPerformed
    
    TreePath tp = jTree1.getSelectionPath();
    
    if (tp == null) return;
    
    String expression = generateXpathExpression(tp, false);
    
    if (reportQueryDialog != null)
    {
        reportQueryDialog.getQueryEditorPane().setText(expression);
    }
    
}//GEN-LAST:event_jMenuItemSetRecordNodeActionPerformed

private void jTree1MousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jTree1MousePressed
    
}//GEN-LAST:event_jTree1MousePressed

private void jMenuItemRefreshActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemRefreshActionPerformed
    updateView();
}//GEN-LAST:event_jMenuItemRefreshActionPerformed

private void jPopupMenuFieldsPopupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {//GEN-FIRST:event_jPopupMenuFieldsPopupMenuWillBecomeVisible
   
    TreePath tp = jTree1.getSelectionPath();
    
    jMenuItemSetRecordNode.setEnabled(false);
    jMenuItemChangeRoot.setEnabled(false);
    jMenuItemAddField.setEnabled(false);
    jMenuItemAddAbsoluteField.setEnabled(false);
    
    if (tp == null) 
    {   
        return;
    }
    
    if (((((DefaultMutableTreeNode)tp.getLastPathComponent()).getUserObject()) instanceof Node) )
    {
        Node node = (Node)((DefaultMutableTreeNode)tp.getLastPathComponent()).getUserObject();
        if (node.getNodeType() == Node.ELEMENT_NODE)
        {
            jMenuItemSetRecordNode.setEnabled(true);
            jMenuItemChangeRoot.setEnabled(true);
        } 
        
        jMenuItemAddField.setEnabled(true);
        jMenuItemAddAbsoluteField.setEnabled(true);
    }
    
}//GEN-LAST:event_jPopupMenuFieldsPopupMenuWillBecomeVisible
    
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLabel jLabelHelp;
    private javax.swing.JMenuItem jMenuItemAddAbsoluteField;
    private javax.swing.JMenuItem jMenuItemAddField;
    private javax.swing.JMenuItem jMenuItemChangeRoot;
    private javax.swing.JMenuItem jMenuItemCollapseAll;
    private javax.swing.JMenuItem jMenuItemExpandAll;
    private javax.swing.JMenuItem jMenuItemRefresh;
    private javax.swing.JMenuItem jMenuItemSetRecordNode;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPopupMenu jPopupMenuFields;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JSeparator jSeparator1;
    private javax.swing.JSeparator jSeparator2;
    private javax.swing.JTree jTree1;
    // End of variables declaration//GEN-END:variables
    
    
    public void updateView()
    {

        IReportConnection conn = IReportManager.getInstance().getDefaultConnection();

        InputStream inputStream = getInputStream(conn);

        if (inputStream == null)
        {
            jTree1.setModel(new DefaultTreeModel(new DefaultMutableTreeNode(I18n.getString("XMLFieldMappingEditor.Node.Warning"))));
        }
        else
        {
                try {
                    // Create a document builder Namespace aware...


                    document = createDocumentBuilder().parse(inputStream);
                    DefaultMutableTreeNode root = addTreeDocument(document.getDocumentElement());
                    jTree1.setModel(new DefaultTreeModel(root));

                } catch (Exception ex) {
                    ex.printStackTrace();
                    jTree1.setModel(new DefaultTreeModel(new DefaultMutableTreeNode("Error loading the XML file.")));
                }
        }

        updateXpathView();
        jTree1.updateUI();
        
        /*
        IReportConnection conn = IReportManager.getInstance().getDefaultConnection();
        
        String file = "";
        if (conn instanceof JRXMLDataSourceConnection)
        {
            file = ((JRXMLDataSourceConnection)conn).getFilename();
            
            try {
                document = JRXmlUtils.parse(new File(file) );
                
                DefaultMutableTreeNode root = addTreeDocument(document.getDocumentElement());
                jTree1.setModel(new DefaultTreeModel(root));
            
            } catch (Exception ex)
            {
                ex.printStackTrace();
            }
            
        }
        else
        {
            jTree1.setModel(new DefaultTreeModel(new DefaultMutableTreeNode(I18n.getString("XMLFieldMappingEditor.Node.Warning"))));
        }
        
        updateXpathView();
        jTree1.updateUI();

         */
    }
    
    public DefaultMutableTreeNode addTreeDocument(Node node)
    {
        
        if (node.getNodeType() != Node.ELEMENT_NODE &&
            node.getNodeType() != Node.ATTRIBUTE_NODE) return null;
        DefaultMutableTreeNode tnode = new DefaultMutableTreeNode(node);
        
        NamedNodeMap nm = node.getAttributes();
        for (int i=0; nm != null && i<nm.getLength(); ++i)
        {
            Node childNode = nm.item(i);
            DefaultMutableTreeNode cnode = addTreeDocument(childNode);
            if (cnode != null)
            {
                tnode.add(cnode);
            }
        }
        
        NodeList nl = node.getChildNodes();
        
        for (int i=0; nl != null && i<nl.getLength(); ++i)
        {
            Node childNode = nl.item(i);
            DefaultMutableTreeNode cnode = addTreeDocument(childNode);
            if (cnode != null)
            {
                tnode.add(cnode);
            }
        }
        
        return tnode;
    }
    
    /**
     * Ad hoc queryChanged method for EJBQL queries....
     * @param newQuery 
     */
    public void queryChanged(String newQuery) {
        
        setXpathExpression(newQuery);
        
         try {
                
                Runnable r = new Runnable() {
                        public void run() {
                            updateXpathView();
                        }
                    };
                    
                if (!SwingUtilities.isEventDispatchThread())
                {
                    SwingUtilities.invokeAndWait( r );
                }
                else
                {
                        r.run();
                }
                    
            } catch(Exception e) {
                // oh well we got interrupted.
            }
        
    }
    
    @SuppressWarnings("unchecked")
    public void updateXpathView()
    {
        if (document == null || getXpathExpression() == null || getXpathExpression().trim().length() == 0) return;
        try {

            NodeList nodeList = xpathExecuter.selectNodeList(document, getXpathExpression());
            
            getRecordNodes().clear();
            for (int i=0; nodeList != null && i<nodeList.getLength(); ++i)
            {
                getRecordNodes().add( nodeList.item(i));
            }
            
            if (reportQueryDialog != null)
            {
                reportQueryDialog.getJLabelStatusSQL().setText(I18n.getString("XMLFieldMappingEditor.Label.StatusSQL") + nodeList.getLength());
            }
            
            jTree1.updateUI();
            
        } catch (Exception ex)
        {
            if (reportQueryDialog != null)
            {
                reportQueryDialog.getJLabelStatusSQL().setText(I18n.getString("XMLFieldMappingEditor.Label.StatusSQL2") + ex.getMessage() + " (" + getXpathExpression() + ")");
                ex.printStackTrace();
            }
        }
    }
    
    /**
     *  Generates an xpath expression to arrive to that node from the root.
     *  The root considered is the tree root, that can be different from the XML Document root.
     * 
     *  @param tp The TreePath
     *  @param relative if the root is on the path, the xpath expression stops here....
     * @return the xpath representation of the path (like /root/node1/node2)
     */
    public String generateXpathExpression(TreePath tp, boolean relative)
    {
        String xpath = "";
        boolean rootFound = false;
        Object[] nodes = ((DefaultMutableTreeNode) tp.getLastPathComponent()).getUserObjectPath();
        
        if (relative)
        {
            // Look for a record root on the path to the root...
            for (int i=nodes.length-1; i>=0; --i)
            {
                Node node = (Node)nodes[i];
                if (getRecordNodes().contains(node))
                {
                    rootFound = true;
                    break;
                }
            }
            if (!rootFound)
            {
                String postfix = "";
                Node node = (Node)nodes[nodes.length-1];
                if (node.getNodeType() == Node.ATTRIBUTE_NODE)
                {
                    postfix = "/@" + node.getNodeName();
                    node = (Node)nodes[nodes.length-2];
                }
                
                // look if there is 
                String exp = "ancestor::" + node.getNodeName();
                for (int i=0; i<getRecordNodes().size(); ++i)
                {
                    try {
                        org.w3c.dom.Node currentNode = (org.w3c.dom.Node) getRecordNodes().get(i);
                        NodeList list = xpathExecuter.selectNodeList(currentNode, exp);
                        org.w3c.dom.Node foundNode = null;
                        if (list.getLength() > 0)
                        {
                            foundNode = list.item(0);
                        }
                        if (foundNode == node) {
                            return exp + postfix;
                        }
                    } catch (Exception ex) {
                        //ex.printStackTrace();
                    }
                }
            }
        }
        
        
        rootFound = false;
        for (int i=nodes.length-1; i>=0; --i)
        {
            Node node = (Node)nodes[i];
            if (relative)
            {
                if (getRecordNodes().contains(node))
                {
                    if (xpath.length() == 0)
                    {
                        xpath = "child::text()";
                    }
                    rootFound = true;
                    break;
                }
            }
            
            if (xpath.length() > 0) xpath = "/" + xpath;
                    
            if (node.getNodeType() == Node.ELEMENT_NODE)
            {
                xpath = node.getNodeName() + xpath;
            }
            else
            {
                xpath = "@" + node.getNodeName();
            }
        }
        
        if ((!rootFound || !relative) && !xpath.startsWith("/"))
        {
            xpath = "/" + xpath;
        }
        
        return xpath;
    }
    
    
    public JRDesignField createField(TreePath path, boolean mode)
    {
        JRDesignField jrField = null;
	DefaultMutableTreeNode dmtn = (DefaultMutableTreeNode)path.getLastPathComponent();
        if (dmtn.getUserObject() != null && dmtn.getUserObject() instanceof Node)
        {
            Node node = (Node)dmtn.getUserObject();
            jrField = new JRDesignField();
            jrField.setName(node.getNodeName());
            jrField.setValueClassName("java.lang.String");
            jrField.setDescription(  generateXpathExpression( path, mode ));
            boolean found = true;
            String name = node.getNodeName();
            
            for (int i=2; found; ++i)
            {
                found = false;
                DefaultTableModel dtm = (DefaultTableModel)getReportQueryDialog().getFieldsTable().getModel();
                for (int k=0; k<dtm.getRowCount(); ++k)
                {
                    JRDesignField tmpField = (JRDesignField)dtm.getValueAt(k, 0);
                    if (tmpField.getName().equals(name))
                    {
                        found = true;
                        break;
                    }
                }
                
                if (found)
                {
                    name = node.getNodeName() + i;
                }
            }
            
            jrField.setName(name);
        }
        
        return jrField;
    }
    
    /*
    public void applyI18n()
    {
        jMenuItemSetRecordNode.setText(I18n.getString("XMLFieldMappingEditor.menuItemSetRecordNode","Set record node (generate xPath)"));
        jMenuItemChangeRoot.setText(I18n.getString("XMLFieldMappingEditor.menuItemChangeRoot","Set document root"));
        jMenuItemAddField.setText(I18n.getString("XMLFieldMappingEditor.menuItemAddField","Add node as field"));
        jMenuItemAddAbsoluteField.setText(I18n.getString("XMLFieldMappingEditor.menuItemAddAbsoluteField","Add node as field (using absolute path)"));
        jMenuItemRefresh.setText(I18n.getString("XMLFieldMappingEditor.menuItemRefresh","Reset / Refresh document"));
        jLabelHelp.setText("<html>" + I18n.getString("XMLFieldMappingEditor.labelHelp","Drag a node into the fields table to map a new field."));
        
        jMenuItemExpandAll.setText(I18n.getString("XMLFieldMappingEditor.menuItemExpandAll","Expand All"));
        jMenuItemCollapseAll.setText(I18n.getString("XMLFieldMappingEditor.menuItemCollapseAll","Collapse All"));
    }
    */

    /**
     * This method look for a method called getFilename with a String as return to locate
     * the file pointed by this connection. The returned string can be an URL or an absolute path...
     * @param conn
     * @return
     */
    private InputStream getInputStream(IReportConnection conn) {

            String file = null;
            try {

                Method m = conn.getClass().getMethod("getFilename", new Class[]{});
                if (m!=null)
                {
                    file = (String)m.invoke(conn, new Object[]{});
                }
                

            } catch (Exception ex)
            {
                ex.printStackTrace();
            }
            if (file == null) return null;

            try {
                return  new FileInputStream(new File(file));
            } catch (Exception ex)
            {
                ex.printStackTrace();
            }

            try {
                    URL url = new URL(file);
                    return url.openStream();

                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            return null;
    }

    public static DocumentBuilder createDocumentBuilder() throws JRException
    {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            dbf.setValidating(false);
            dbf.setIgnoringComments(true);
            dbf.setNamespaceAware(true);

            try
            {
                    return dbf.newDocumentBuilder();
            }
            catch (ParserConfigurationException e)
            {
                    throw new JRException("Failed to create a document builder factory", e);
            }
    }
}
