package org.autoplot.cdf;

import gov.nasa.gsfc.spdf.cdfj.CDFException;
import gov.nasa.gsfc.spdf.cdfj.CDFException.ReaderError;
import gov.nasa.gsfc.spdf.cdfj.CDFReader;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Array;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import org.autoplot.cdf.CdfUtil.CdfVariableDescription;
import org.autoplot.help.AutoplotHelpSystem;
import org.das2.util.DasExceptionHandler;
import org.das2.util.filesystem.FileSystem;
import org.das2.util.monitor.NullProgressMonitor;
import org.das2.util.monitor.ProgressMonitor;
import org.das2.qds.QDataSet;
import org.autoplot.datasource.DataSetSelector;
import org.autoplot.datasource.DataSetURI;
import org.autoplot.datasource.DataSourceEditorPanel;
import org.autoplot.datasource.URISplit;

/**
 * Editor panel for CDF files.  The "Java" part of the name comes from this is a
 * second implementation of the CDF reader, where the first was a native reader
 * interfaced to Autoplot via Java Native Interface.
 * @author jbf
 */
public final class CdfJavaDataSourceEditorPanel extends javax.swing.JPanel implements DataSourceEditorPanel {
    public static final String NO_PLOTTABLE_PARAMETERS_MSG = "<html><i>No plottable parameters</i></html>";

    /** the maximum number of DEPEND_1 channels where we should show option for depend_1. */
    private static final int MAX_SLICE1_OFFER = 32;

    private final static Logger logger= Logger.getLogger( "apdss.cdf" );

    private boolean isValidCDF= false;
    
    private boolean listening = true;
    
    /** Creates new form AggregatingDataSourceEditorPanel */
    public CdfJavaDataSourceEditorPanel() {
        initComponents();
        parameterTree.getSelectionModel().setSelectionMode( TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION );
        xParameterTree.getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION );
        yParameterTree.getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION );
        jPanel3.setVisible(false);
        if ( AutoplotHelpSystem.getHelpSystem()!=null ) { // to help with debugging, check for null so we needn't initialize all of Autoplot to debug.
            AutoplotHelpSystem.getHelpSystem().registerHelpID(this, "cdf_main");
        }
    }

    /** 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.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        bindingGroup = new org.jdesktop.beansbinding.BindingGroup();

        jPanel1 = new javax.swing.JPanel();
        jSplitPane2 = new javax.swing.JSplitPane();
        jSplitPane1 = new javax.swing.JSplitPane();
        jPanel3 = new javax.swing.JPanel();
        jLabel4 = new javax.swing.JLabel();
        subsetComboBox = new javax.swing.JComboBox();
        interpretMetadataLabel = new javax.swing.JLabel();
        noInterpMeta = new javax.swing.JCheckBox();
        noDep = new javax.swing.JCheckBox();
        showAllVarTypeCB = new javax.swing.JCheckBox();
        whereCB = new javax.swing.JCheckBox();
        whereParamList = new javax.swing.JComboBox();
        whereOp = new javax.swing.JComboBox();
        whereTF = new javax.swing.JTextField();
        filterComboBox = new org.autoplot.datasource.RecentComboBox();
        sortAlphaCheckBox = new javax.swing.JCheckBox();
        emptyVariablesCB = new javax.swing.JCheckBox();
        jTabbedPane1 = new javax.swing.JTabbedPane();
        jScrollPane3 = new javax.swing.JScrollPane();
        parameterTree = new javax.swing.JTree();
        jPanel2 = new javax.swing.JPanel();
        jScrollPane4 = new javax.swing.JScrollPane();
        xParameterTree = new javax.swing.JTree();
        xCheckBox = new javax.swing.JCheckBox();
        jPanel4 = new javax.swing.JPanel();
        jScrollPane5 = new javax.swing.JScrollPane();
        yParameterTree = new javax.swing.JTree();
        yCheckBox = new javax.swing.JCheckBox();
        jScrollPane2 = new javax.swing.JScrollPane();
        paramInfo = new javax.swing.JLabel();

        setName("cdfDataSourceEditorPanel"); // NOI18N
        setPreferredSize(new java.awt.Dimension(615, 452));

        jPanel1.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        jPanel1.setPreferredSize(new java.awt.Dimension(615, 452));

        jSplitPane2.setDividerLocation(230);
        jSplitPane2.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);

        jSplitPane1.setDividerLocation(320);
        jSplitPane1.setResizeWeight(1.0);

        jPanel3.setBorder(javax.swing.BorderFactory.createTitledBorder("Advanced"));
        jPanel3.setMaximumSize(new java.awt.Dimension(285, 32767));

        jLabel4.setText("Load subset of the data:");
        jLabel4.setToolTipText("<html>Load a subset of the data records, for example:<br>[0:100]  first 100 records<br> [-100:] last 100 records<br> [::10] every tenth record<br> </html>");

        subsetComboBox.setEditable(true);
        subsetComboBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "", "::10", "0:100", "-100:", "0:10000:5" }));
        subsetComboBox.setToolTipText("<html>Load a subset of the data records, for example:<br>[0:100]  first 100 records<br> [-100:] last 100 records<br> [::10] every tenth record<br> </html>");

        interpretMetadataLabel.setText("Interpret Metadata:");

        noInterpMeta.setText("no ISTP");
        noInterpMeta.setToolTipText("Don't interpret metadata to get titles and units.");

        noDep.setText("no dependencies");
        noDep.setToolTipText("Ignore connections between variables like \"DEPEND_0\"\n");

        showAllVarTypeCB.setText("show all");
        showAllVarTypeCB.setToolTipText("show all parameters, even if ISTP VAR_TYPE is not \"data\"");
        showAllVarTypeCB.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                showAllVarTypeCBActionPerformed(evt);
            }
        });

        whereCB.setText("Only load data where:");
        whereCB.setToolTipText("return only the records where the condition is true");

        whereParamList.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));

        org.jdesktop.beansbinding.Binding binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, whereCB, org.jdesktop.beansbinding.ELProperty.create("${selected}"), whereParamList, org.jdesktop.beansbinding.BeanProperty.create("enabled"));
        bindingGroup.addBinding(binding);

        whereOp.setModel(new javax.swing.DefaultComboBoxModel(new String[] { ".eq", ".gt", ".lt", ".ne", ".within" }));

        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, whereCB, org.jdesktop.beansbinding.ELProperty.create("${selected}"), whereOp, org.jdesktop.beansbinding.BeanProperty.create("enabled"));
        bindingGroup.addBinding(binding);

        whereTF.setText("0");
        whereTF.setToolTipText("enter the value, or \"mode\" for the most frequently occuring value.");

        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, whereCB, org.jdesktop.beansbinding.ELProperty.create("${selected}"), whereTF, org.jdesktop.beansbinding.BeanProperty.create("enabled"));
        bindingGroup.addBinding(binding);

        filterComboBox.setToolTipText("Pattern to match in variables names.  If this is a valid regular expression, it will be used as such, otherwise the variables containing the string are used.");
        filterComboBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                filterComboBoxActionPerformed(evt);
            }
        });

        sortAlphaCheckBox.setText("sort alpha");
        sortAlphaCheckBox.setToolTipText("Sort the names alphabetically.");
        sortAlphaCheckBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                sortAlphaCheckBoxActionPerformed(evt);
            }
        });

        emptyVariablesCB.setSelected(true);
        emptyVariablesCB.setText("empty variables");
        emptyVariablesCB.setToolTipText("show variables which have no records");
        emptyVariablesCB.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                emptyVariablesCBActionPerformed(evt);
            }
        });

        org.jdesktop.layout.GroupLayout jPanel3Layout = new org.jdesktop.layout.GroupLayout(jPanel3);
        jPanel3.setLayout(jPanel3Layout);
        jPanel3Layout.setHorizontalGroup(
            jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel3Layout.createSequentialGroup()
                .addContainerGap()
                .add(whereParamList, 0, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(whereOp, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 84, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(whereTF, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 53, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
            .add(jPanel3Layout.createSequentialGroup()
                .add(jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(jLabel4)
                    .add(whereCB)
                    .add(interpretMetadataLabel)
                    .add(jPanel3Layout.createSequentialGroup()
                        .add(12, 12, 12)
                        .add(jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                            .add(jPanel3Layout.createSequentialGroup()
                                .add(jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                                    .add(noInterpMeta)
                                    .add(showAllVarTypeCB)
                                    .add(sortAlphaCheckBox))
                                .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
                                .add(jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                                    .add(filterComboBox, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                                    .add(noDep)
                                    .add(emptyVariablesCB)))
                            .add(subsetComboBox, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 160, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))))
                .add(0, 0, Short.MAX_VALUE))
        );
        jPanel3Layout.setVerticalGroup(
            jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel3Layout.createSequentialGroup()
                .add(jLabel4)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(subsetComboBox, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(whereCB)
                .add(8, 8, 8)
                .add(jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(whereParamList, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(whereOp, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(whereTF, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(interpretMetadataLabel)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(noInterpMeta)
                    .add(noDep))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(showAllVarTypeCB)
                    .add(filterComboBox, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(sortAlphaCheckBox)
                    .add(emptyVariablesCB)))
        );

        jSplitPane1.setRightComponent(jPanel3);

        jTabbedPane1.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                jTabbedPane1StateChanged(evt);
            }
        });

        parameterTree.addTreeSelectionListener(new javax.swing.event.TreeSelectionListener() {
            public void valueChanged(javax.swing.event.TreeSelectionEvent evt) {
                parameterTreeValueChanged(evt);
            }
        });
        jScrollPane3.setViewportView(parameterTree);

        jTabbedPane1.addTab("Data", jScrollPane3);

        xParameterTree.addTreeSelectionListener(new javax.swing.event.TreeSelectionListener() {
            public void valueChanged(javax.swing.event.TreeSelectionEvent evt) {
                xParameterTreeValueChanged(evt);
            }
        });
        jScrollPane4.setViewportView(xParameterTree);

        xCheckBox.setText("Set Variable for X");
        xCheckBox.setToolTipText("Specify the parameter to use for the X tags, overriding any settings found in the file.");
        xCheckBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                xCheckBoxActionPerformed(evt);
            }
        });

        org.jdesktop.layout.GroupLayout jPanel2Layout = new org.jdesktop.layout.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(xCheckBox, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 401, Short.MAX_VALUE)
            .add(jScrollPane4)
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel2Layout.createSequentialGroup()
                .add(xCheckBox)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(jScrollPane4, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 169, Short.MAX_VALUE))
        );

        jTabbedPane1.addTab("X", jPanel2);

        yParameterTree.addTreeSelectionListener(new javax.swing.event.TreeSelectionListener() {
            public void valueChanged(javax.swing.event.TreeSelectionEvent evt) {
                yParameterTreeValueChanged(evt);
            }
        });
        jScrollPane5.setViewportView(yParameterTree);

        yCheckBox.setText("Set Variable for Y");
        yCheckBox.setToolTipText("Specify the parameter to use for the Y tags, overriding any settings found in the file.");

        org.jdesktop.layout.GroupLayout jPanel4Layout = new org.jdesktop.layout.GroupLayout(jPanel4);
        jPanel4.setLayout(jPanel4Layout);
        jPanel4Layout.setHorizontalGroup(
            jPanel4Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(yCheckBox, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 401, Short.MAX_VALUE)
            .add(jScrollPane5)
        );
        jPanel4Layout.setVerticalGroup(
            jPanel4Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel4Layout.createSequentialGroup()
                .add(yCheckBox)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(jScrollPane5, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 169, Short.MAX_VALUE))
        );

        jTabbedPane1.addTab("Y", jPanel4);

        jSplitPane1.setLeftComponent(jTabbedPane1);

        jSplitPane2.setTopComponent(jSplitPane1);

        jScrollPane2.setMaximumSize(new java.awt.Dimension(1000, 600));

        paramInfo.setText("Variable");
        paramInfo.setVerticalAlignment(javax.swing.SwingConstants.TOP);
        paramInfo.setMaximumSize(new java.awt.Dimension(1000, 4000));
        paramInfo.setPreferredSize(new java.awt.Dimension(600, 100));
        paramInfo.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
        jScrollPane2.setViewportView(paramInfo);

        jSplitPane2.setRightComponent(jScrollPane2);

        org.jdesktop.layout.GroupLayout jPanel1Layout = new org.jdesktop.layout.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(org.jdesktop.layout.GroupLayout.TRAILING, jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .add(jSplitPane2, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 675, Short.MAX_VALUE)
                .addContainerGap())
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .add(jSplitPane2, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 425, Short.MAX_VALUE)
                .addContainerGap())
        );

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(org.jdesktop.layout.GroupLayout.TRAILING, jPanel1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );

        bindingGroup.bind();
    }// </editor-fold>//GEN-END:initComponents

    private void showAllVarTypeCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showAllVarTypeCBActionPerformed
        org.das2.util.LoggerManager.logGuiEvent(evt);
        setURI( getURI() );
    }//GEN-LAST:event_showAllVarTypeCBActionPerformed

    private void jTabbedPane1StateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_jTabbedPane1StateChanged
        int tab= jTabbedPane1.getSelectedIndex();
        updateMetadata(tab);
    }//GEN-LAST:event_jTabbedPane1StateChanged

    private void yParameterTreeValueChanged(javax.swing.event.TreeSelectionEvent evt) {//GEN-FIRST:event_yParameterTreeValueChanged
        yCheckBox.setSelected(true);
        TreePath tp= evt.getPath();
        if ( isValidCDF ) {
            yparameter= String.valueOf(tp.getPathComponent(1));
            String longName= yparameterInfo.get(yparameter);
            paramInfo.setText( longName );
        }
    }//GEN-LAST:event_yParameterTreeValueChanged

    private void xCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_xCheckBoxActionPerformed
        // TODO add your handling code here:
    }//GEN-LAST:event_xCheckBoxActionPerformed

    private void xParameterTreeValueChanged(javax.swing.event.TreeSelectionEvent evt) {//GEN-FIRST:event_xParameterTreeValueChanged
        xCheckBox.setSelected(true);
        TreePath tp= evt.getPath();
        if ( isValidCDF ) {
            xparameter= String.valueOf(tp.getPathComponent(1));
            String longName= xparameterInfo.get(xparameter);
            paramInfo.setText( longName );
        }
    }//GEN-LAST:event_xParameterTreeValueChanged

    private void parameterTreeValueChanged(javax.swing.event.TreeSelectionEvent evt) {//GEN-FIRST:event_parameterTreeValueChanged
        TreePath tp= evt.getPath();
        if ( isValidCDF && listening ) {
            parameter= String.valueOf(tp.getPathComponent(1));
            String s;
            String slice1;
            slice1= "";
            s= getParamAndSubset(xParameterTree,"");
            if ( xparameter!=null && xparameter.length()<=s.length() ) {
                slice1= s.substring(xparameter.length());
            }
            LinkedHashMap<String,CdfVariableDescription> xx= getCompatible( cdfParameterInfo, parameter, X_PARAMETER );
            fillTree( xParameterTree, toDescriptions(xx), cdf, xparameter, slice1 );
            s= getParamAndSubset(yParameterTree,"");
            slice1= "";
            if ( yparameter!=null && yparameter.length()<=s.length() ) {
                slice1= s.substring(yparameter.length());
            }
            LinkedHashMap<String,CdfVariableDescription> yy= getCompatible( cdfParameterInfo, parameter, Y_PARAMETER );
            fillTree( yParameterTree, toDescriptions(yy), cdf, yparameter, slice1 );
            updateMetadata();
        }
    }//GEN-LAST:event_parameterTreeValueChanged

    /**
     * convert the CdfVariableDescription blocks into an html page describing the variables.
     * @param xx
     * @return 
     */
    private Map<String,String> toDescriptions( LinkedHashMap<String,CdfVariableDescription> xx ) {
        LinkedHashMap<String,String> result= new LinkedHashMap<>();
        for ( Entry<String,CdfVariableDescription> e: xx.entrySet() ) {
            CdfVariableDescription desc=e.getValue();
            result.put( e.getKey(), desc.htmlDescription );
        }
        return result;
    }
    
    /**
     * return the list of variables which are compatible with this parameter, having the same number 
     * of records, etc.
     * @param parameter
     * @param whichIndependentParameter X_PARAMETER, Y_PARAMETER
     * @return a linked hash map of name to descriptions.
     */
    public static LinkedHashMap<String,CdfVariableDescription> getCompatible( 
            LinkedHashMap<String,org.autoplot.cdf.CdfUtil.CdfVariableDescription> cdfParameterInfo, String parameter, Object whichIndependentParameter ) {
        CdfVariableDescription dependent= cdfParameterInfo.get(parameter);
        LinkedHashMap<String,CdfVariableDescription> result= new LinkedHashMap<>();
        for ( Entry<String,CdfVariableDescription> cvds : cdfParameterInfo.entrySet() ) {
            CdfVariableDescription cvd = cvds.getValue();
            if ( dependent!=null && whichIndependentParameter==X_PARAMETER ) {
                if ( cvd.numberOfRecords==dependent.numberOfRecords ) {
                    if ( cvd.dimensions.length==0 || ( cvd.dimensions.length==1 && cvd.dimensions[0]==2 ) ) {
                        result.put( cvd.name, cvd );
                    }
                } 
            } else if ( dependent!=null && whichIndependentParameter==Y_PARAMETER) {
                if ( cvd.dimensions.length==1 && dependent.dimensions.length==1 
                        && cvd.dimensions[0]==dependent.dimensions[0] ) {
                    if ( cvd.numberOfRecords==1 ) {
                        result.put( cvd.name, cvd );
                    } else if ( cvd.numberOfRecords==dependent.numberOfRecords ) {
                        result.put( cvd.name, cvd );
                    }
                } else if ( cvd.dimensions.length==0 && dependent.dimensions.length==0
                        && cvd.numberOfRecords==dependent.numberOfRecords ) {
                    result.put( cvd.name, cvd );
                }
            } else {
                result.put( cvd.name, cvd );
            }
        }
        return result;
    }
    
    private void filterComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_filterComboBoxActionPerformed
        updateTree();
    }//GEN-LAST:event_filterComboBoxActionPerformed

    private void sortAlphaCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sortAlphaCheckBoxActionPerformed
        updateTree();
    }//GEN-LAST:event_sortAlphaCheckBoxActionPerformed

    private void emptyVariablesCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_emptyVariablesCBActionPerformed
        setURI( getURI() );
    }//GEN-LAST:event_emptyVariablesCBActionPerformed

    private void updateTree() {
        String param = getParam();
        fillTree( this.parameterTree, parameterInfo, cdf, param, "" );
    }
    
    private void updateMetadata() {
       updateMetadata(0);
    }

    private void updateMetadata( int tab ) {
        switch (tab) {
            case 0:
                if ( parameter!=null ) {
                    String longName= parameterInfo.get(parameter);
                    paramInfo.setText( longName );
                    break;
                }
            case 1:
                if ( xparameter!=null ) {
                    String longName= xparameterInfo.get(xparameter);
                    paramInfo.setText( longName );
                    break;
                }
            case 2:
                if ( yparameter!=null ) {
                    String longName= yparameterInfo.get(yparameter);
                    paramInfo.setText( longName );
                    break;
                }
            default:
                break;
        }
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JCheckBox emptyVariablesCB;
    private org.autoplot.datasource.RecentComboBox filterComboBox;
    private javax.swing.JLabel interpretMetadataLabel;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JPanel jPanel4;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JScrollPane jScrollPane3;
    private javax.swing.JScrollPane jScrollPane4;
    private javax.swing.JScrollPane jScrollPane5;
    private javax.swing.JSplitPane jSplitPane1;
    private javax.swing.JSplitPane jSplitPane2;
    private javax.swing.JTabbedPane jTabbedPane1;
    private javax.swing.JCheckBox noDep;
    private javax.swing.JCheckBox noInterpMeta;
    private javax.swing.JLabel paramInfo;
    private javax.swing.JTree parameterTree;
    private javax.swing.JCheckBox showAllVarTypeCB;
    private javax.swing.JCheckBox sortAlphaCheckBox;
    private javax.swing.JComboBox subsetComboBox;
    private javax.swing.JCheckBox whereCB;
    private javax.swing.JComboBox whereOp;
    private javax.swing.JComboBox whereParamList;
    private javax.swing.JTextField whereTF;
    private javax.swing.JCheckBox xCheckBox;
    private javax.swing.JTree xParameterTree;
    private javax.swing.JCheckBox yCheckBox;
    private javax.swing.JTree yParameterTree;
    private org.jdesktop.beansbinding.BindingGroup bindingGroup;
    // End of variables declaration//GEN-END:variables

    @Override
    public JPanel getPanel() {
        if (showAllInitially) {
            SwingUtilities.invokeLater( new Runnable() {
                @Override
                public void run() {
                    showAllVarTypeCB.setSelected(true);
                    setURI( getURI() );
                }
            });
        }     
        return this;
    }


    JComponent delegateComponent = null;
    DataSetSelector delegateDataSetSelector=null;
    DataSourceEditorPanel delegateEditorPanel= null;
    
    /**
     * extra URI parameters that are not supported in the dialog.
     */
    Map<String,String> params;
    
    String vapScheme;
    
    /**
     * the location of the CDF file.
     */
    URI resourceUri;
    
    /**
     * short descriptions of the parameters
     */
    Map<String,String> parameterDescriptions;

    /**
     * long descriptions html formatted metadata about each parameter.
     */
    Map<String,String> parameterInfo;

    /**
     * long descriptions html formatted metadata about each parameter.
     */
    Map<String,String> xparameterInfo;

    /**
     * long descriptions html formatted metadata about each parameter.
     */
    Map<String,String> yparameterInfo;
    
    /**
     * new descriptions of variables with size and lengths
     */
    LinkedHashMap<String,org.autoplot.cdf.CdfUtil.CdfVariableDescription> cdfParameterInfo;
    
    String parameter;
    String xparameter;
    String yparameter;

    public static final String X_PARAMETER = "X_PARAMETER";
    public static final String Y_PARAMETER = "Y_PARAMETER";
    
    boolean showAllInitially= false;
    
    /**
     * can I reuse the slice?  Only if the maxRec doesn't change.
     */
    long subsetMaxRec=-1;

    File cdfFile;
    CDFReader cdf;
    Throwable cdfException;

    /**
     * allow more abstract sources, namely cdaweb, to turn off these controls.
     * @param v
     */
    public void setShowAdvancedSubpanel( boolean v ) {
        noDep.setVisible(v);
        noInterpMeta.setVisible(v);
        //showAllVarTypeCB.setVisible(v);
    }
    
    @Override
    public boolean reject( String url ) throws IOException, URISyntaxException {
        URISplit split = URISplit.parse(url); 

        if ( split.resourceUri==null ) {
            return true;
        }
        
        FileSystem fs = FileSystem.create( DataSetURI.getWebURL( DataSetURI.toUri(split.path) ).toURI() );
        return fs.isDirectory( split.file.substring(split.path.length()) );
    }

    @Override
    public boolean prepare( String url,  java.awt.Window parent, ProgressMonitor mon) throws Exception {
        URISplit split= URISplit.parse(url);

        cdfFile= DataSetURI.getFile( split.resourceUri, mon );
        DataSetURI.checkLength(cdfFile);

        logger.log(Level.FINE, "opening cdf file {0}", cdfFile.toString());
        try {
            CdfDataSource.checkCdf(cdfFile);
            cdf = CdfDataSource.getCdfFile(cdfFile.toString());
            if ( cdf==null ) {
                throw new IllegalArgumentException("file is not a CDF file");
            }
            cdfException= null;
        } catch ( IOException | IllegalArgumentException ex ) {
            cdfException= ex;
        }
        return true;
    }

    public static String getKeyForFile( String filename ) {
        int j=filename.indexOf("19");
        if ( j==-1 ) j= filename.indexOf("20");
        if ( j==-1 ) j= filename.length();
        while ( j>0 && filename.charAt(j-1)=='_' )  j=j-1;
        String key= filename.substring(0,j);
        return key;
    }
    
    @Override
    public void setURI(String url) {
        URISplit split= URISplit.parse(url);
        
        vapScheme= split.vapScheme;
        
        Map<String,String> lparams= URISplit.parseParams(split.params);

        try {
            resourceUri= split.resourceUri;
            
            cdfFile= DataSetURI.getFile( split.resourceUri, new NullProgressMonitor() );
            DataSetURI.checkLength(cdfFile);
            
            String fileName= cdfFile.toString();
            
            String key= getKeyForFile( split.file.substring(split.path.length()) );
            filterComboBox.setPreferenceNode("cdf_"+key);
            filterComboBox.setToolTipText("Filter parameters");
            
            logger.log(Level.FINE, "opening cdf file {0}", fileName);
            if ( cdf==null && cdfException==null ) {
                try {
                    cdf = CdfDataSource.getCdfFile(fileName);
                } catch (Exception ex) {
                    throw new RuntimeException(ex);
                }
            }
    
            if ( cdfException!=null ) {
                this.parameterTree.setModel( new DefaultTreeModel( new DefaultMutableTreeNode("") ) );
                this.paramInfo.setText( "<html>Unable to read CDF file:<br>"+cdfException.getMessage() );
                return;
            }
            
            logger.finest("inspect cdf for plottable parameters");
            
            boolean isMaster= fileName.contains("MASTERS");
            
            Map<String,String> options= new HashMap<>();
            options.put( org.autoplot.cdf.CdfUtil.OPTION_INCLUDE_EMPTY_RECORDS,  String.valueOf(this.emptyVariablesCB.isSelected()) );
            options.put( org.autoplot.cdf.CdfUtil.OPTION_IS_MASTER, String.valueOf(isMaster) );
            options.put( org.autoplot.cdf.CdfUtil.OPTION_DEEP, String.valueOf(true) );
            
            try {
                parameterDescriptions= org.autoplot.cdf.CdfUtil.getPlottable(cdf, !this.showAllVarTypeCB.isSelected(), 
                    QDataSet.MAX_RANK);
            } catch ( Exception ex ) {
                this.parameterTree.setModel( new DefaultTreeModel( new DefaultMutableTreeNode("") ) );
                this.paramInfo.setText( "<html>Unable to work with metadata in CDF file:<br>"+ex );
                throw ex;
            }            
            
            Map<String,String> allParameterInfo= org.autoplot.cdf.CdfUtil.getPlottable(cdf, false, QDataSet.MAX_RANK, options );
            Map<String,String> dataParameterInfo= org.autoplot.cdf.CdfUtil.getPlottable(cdf, true, QDataSet.MAX_RANK, options );
            options.put( org.autoplot.cdf.CdfUtil.OPTION_DEEP, String.valueOf( false ) );
            Map<String,String> whereParameterInfo= org.autoplot.cdf.CdfUtil.getPlottable(cdf, false, 2, options);

            cdfParameterInfo= org.autoplot.cdf.CdfUtil.getPlottable(cdf, options);
            
            String param= lparams.remove("arg_0");
            String[] params= null;
            if ( param!=null ) {
                params= param.split(";",-2);
                for ( String p : params ) {
                    if ( !dataParameterInfo.containsKey(p) ) {
                        this.showAllVarTypeCB.setSelected(true);
                        parameterDescriptions= org.autoplot.cdf.CdfUtil.getPlottable(cdf, 
                            !this.showAllVarTypeCB.isSelected(), QDataSet.MAX_RANK, new HashMap<String,String>());
                        this.showAllVarTypeCB.setEnabled(false);
                    }   
                }
            }
            
            if ( dataParameterInfo.isEmpty() && !cdfParameterInfo.isEmpty() ) {
                this.showAllVarTypeCB.setSelected(true);
            }
            
            String label;
            if ( this.showAllVarTypeCB.isSelected() ) {
                parameterInfo= allParameterInfo;
                label= "Select CDF Variable (%d data, %d support):";
            } else {
                parameterInfo= dataParameterInfo;
                label= "Select CDF Variable (%d data, %d support not shown):";
            }
            xparameterInfo= allParameterInfo;
            yparameterInfo= allParameterInfo;
            
            this.isValidCDF= true;
            jPanel3.setVisible(true);
            
            int numData= dataParameterInfo.size();
            int numSupport= allParameterInfo.size() - numData;

            //this.selectVariableLabel.setText( String.format( label, numData, numSupport ) );
            if ( this.showAllVarTypeCB.isSelected() ) {
                this.jTabbedPane1.setTitleAt( 0, String.format( "Select CDF Variable (of %d)", numData+numSupport ) );
            } else {
                this.jTabbedPane1.setTitleAt( 0, String.format( "Select CDF Variable (of %d)", numData ) );
            }
            
            this.jTabbedPane1.setToolTipText( String.format( label, numData, numSupport ) );
            if ( this.showAllVarTypeCB.isSelected() ) {
                this.showAllVarTypeCB.setText("show all ("+numSupport+" support shown)");
            } else {
                this.showAllVarTypeCB.setText("show all ("+numSupport+" support not shown)");
            }
            
            Pattern slice1pattern= Pattern.compile("\\[\\:\\,(\\d+)\\]");
            String slice= lparams.remove("slice1"); // legacy
            Pattern slice2pattern= Pattern.compile("\\[\\:\\,\\:\\,(\\d+)\\]");

            String subset= null;
            if ( param!=null ) {
                int i= param.indexOf("[");
                if ( i!=-1 ) {
                    subset= param.substring(i);
                    param= param.substring(0,i);
                    Matcher m= slice1pattern.matcher(subset);
                    if ( m.matches() ) {
                        slice= m.group(1);
                        subset= null;
                    }
                    if ( subset!=null ) {
                        m= slice2pattern.matcher(subset);
                        if ( m.matches() ) {
                            slice= m.group(1); 
                            subset= null;
                        }
                    }
                }
            }

            if ( allParameterInfo.containsKey(param) ) {
                if ( !dataParameterInfo.containsKey(param) ) {
                    showAllInitially= true;
                }
            }
            
            listening= false;
            if ( params!=null && params.length>1 ) {
                fillTree( this.parameterTree, parameterInfo, cdf, param, slice );
            } else {
                fillTree( this.parameterTree, parameterInfo, cdf, param, slice );
            }
            listening= true;
            
            Map<String,String> parameterDescriptions2= org.autoplot.cdf.CdfUtil.getPlottable(cdf, false, 2 );
            String xparam= lparams.remove("depend0");
            String xslice1= null;
            if ( xparam==null ) xparam= lparams.remove("X");
            if ( xparam==null ) xparam= lparams.remove("x");
            if ( xparam!=null ) {
                int i= xparam.indexOf("[");
                if ( i!=-1 ) {
                    String xsubset= xparam.substring(i);
                    xparam= xparam.substring(0,i);
                    Matcher m= slice1pattern.matcher(xsubset);
                    if ( m.matches() ) {
                        xslice1= m.group(1);
                    }
                }
            }
            
            fillTree(this.xParameterTree, parameterDescriptions2, cdf, xparam, xslice1 );
            
            String yslice1= null;
            String yparam= lparams.remove("Y");
            if ( yparam==null ) yparam= lparams.remove("y");
            if ( yparam!=null ) {
                int i= yparam.indexOf("[");
                if ( i!=-1 ) {
                    String ysubset= yparam.substring(i);
                    yparam= yparam.substring(0,i);
                    Matcher m= slice1pattern.matcher(ysubset);
                    if ( m.matches() ) {
                        yslice1= m.group(1);
                    }
                }
            }
            fillTree(this.yParameterTree, parameterDescriptions2, cdf, yparam, yslice1 );
            
            logger.finest("close cdf");

            DefaultComboBoxModel cbmodel= new DefaultComboBoxModel();
            for ( String p: parameterDescriptions.keySet() ) {
                cbmodel.addElement(p);
            }

            if ( param!=null ) {
                if ( subset!=null ) {
                    if ( subset.startsWith("[") ) subset= subset.substring(1);
                    if ( subset.endsWith("]") ) subset= subset.substring(0,subset.length()-1);
                    subsetComboBox.setSelectedItem( subset );
                } else {
                    subsetComboBox.setSelectedItem("");
                }
            } else {
                if ( !parameterDescriptions.isEmpty() ) {
                    parameter= parameterDescriptions.entrySet().iterator().next().getKey();
                    subsetComboBox.setSelectedItem("");
                    param= parameter;
                    paramInfo.setText("");
                } else {
                    param= "";
                    if ( this.parameterTree.getRowCount()==0 && numSupport>0 && numData==0 && !this.showAllVarTypeCB.isSelected() ) {
                        paramInfo.setText("(all parameters are marked as support data, select \"show all\" above)");
                    } else {
                        paramInfo.setText("(no plottable parameters)");
                    }
                }                
            }
            parameter= param.replaceAll("%3D", "=");

            if ( "no".equals( lparams.remove("interpMeta")) ) {
                noInterpMeta.setSelected(true);
            }

            if ( "no".equals( lparams.remove("doDep" ) ) ) {
                noDep.setSelected(true);
            }

            whereParamList.setModel( new DefaultComboBoxModel( whereParameterInfo.keySet().toArray() ) );
            String where= lparams.remove("where");
            if ( where!=null && where.length()>0 ) {
                whereCB.setSelected(true);
                int i= where.indexOf(".");
                if ( i>-1 ) {
                    whereParamList.setSelectedItem(where.substring(0,i)); 
                    int i0= where.indexOf("(");
                    int i1= where.indexOf(")",i0);
                    whereOp.setSelectedItem(where.substring(i,i0));
                    whereTF.setText( where.substring(i0+1,i1).replaceAll("\\+"," "));
                }
            } else {
                whereCB.setSelected(false);
            }
            
            updateMetadata();
            
        } catch (IOException ex) {
            DasExceptionHandler.handle( ex );
            logger.log(Level.SEVERE, ex.getMessage(), ex);
        } catch (IllegalArgumentException ex) {
            DasExceptionHandler.handle( ex );
            logger.log(Level.SEVERE, ex.getMessage(), ex);
        } catch (Exception ex) {
            DasExceptionHandler.handle( ex );
            logger.log(Level.SEVERE, ex.getMessage(), ex);
        }

        this.params= lparams;
        
    }

    /**
     * return the name of the selected parameter, or null.
     * @return 
     */
    private String getParam() {
        TreePath treePath= parameterTree.getSelectionPath();
        String p;
        if ( treePath==null ) {
            return null;
        } else {
            p= String.valueOf( treePath.getPathComponent(1) );
            p= p.replaceAll("=", "%3D");
        }
        return p;
    }
    
    /**
     * return the parameter, if something is selected, possibly with [:,n] to indicate a slice should be done.
     * @param jtree the tree showing the selection
     * @param subset subset by index, like [::2] for every other element.
     * @return empty string if no selection, or the path.
     */
    private String getParamAndSubset( JTree jtree, String subset )  {
        StringBuilder ps= new StringBuilder();
        TreePath[] tps= jtree.getSelectionPaths(); // typically this will be a one-element array.
        if ( tps==null ) tps= new TreePath[] { jtree.getSelectionPath() };
        for ( TreePath treePath : tps ) {
            if ( ps.length()>0 ) ps.append(";");
            if ( treePath==null ) {
                logger.fine("param was null");
            } else if ( treePath.getPathCount()==3 ) {
                String p= String.valueOf( treePath.getPathComponent(1) );
                p= p.replaceAll("=", "%3D");
                String val=  String.valueOf( treePath.getPathComponent(2) );
                int dims= 1;
                try {
                    dims= cdf.getDimensions(p).length;
                } catch ( ReaderError e ) {
                    e.printStackTrace();
                }
                if ( dims==2  ) {
                    int idx= val.indexOf(":");
                    ps.append(p).append("[:,:,").append(val.substring(0,idx).trim()).append("]");                    
                } else {
                    int idx= val.indexOf(":");
                    ps.append(p).append("[:,").append(val.substring(0,idx).trim()).append("]");
                }
            } else {
                String p= String.valueOf( treePath.getPathComponent(1) );
                p= p.replaceAll("=", "%3D");
                ps.append(p).append(subset);
            }
        }
        return ps.toString();
    }
    
    @Override
    public String getURI() {
        
        URISplit split= URISplit.parse(resourceUri);
        
        split.vapScheme= this.vapScheme;
                
        String subset= subsetComboBox.getSelectedItem().toString().trim();
        if ( subset.length()>0 && subset.charAt(0)!='[' ) {
            subset= "["+subset+"]";
        }
        
        Map<String,String> lparams= this.params;
        if ( lparams!=null ) {
            lparams= new HashMap(lparams);
        } else {
            lparams= new HashMap();
        }
        
        if ( isValidCDF ) {
            TreePath[] tps= parameterTree.getSelectionPaths();
            
            if ( tps!=null ) {
                String p= getParamAndSubset(parameterTree,subset);
                if ( p.length()>0 ) lparams.put( "arg_0", p );
            }
            
            if ( xCheckBox.isSelected() ) {
                String p = getParamAndSubset(xParameterTree,"");
                if ( p.length()>0 ) lparams.put( "X", p );
            }

            if ( yCheckBox.isSelected() ) {
                String p= getParamAndSubset(yParameterTree,"");
                if ( p.length()>0 ) lparams.put( "Y", p );
            }
            
            if ( noDep.isSelected() ) {
                lparams.put("doDep","no");
            } 
            
            if ( noInterpMeta.isSelected() ) {
                lparams.put("interpMeta", "no");
            } 

            if ( whereCB.isSelected() ) {
               if ( whereParamList.getSelectedItem()!=null ) {
                    lparams.put( "where", String.format( "%s%s(%s)", whereParamList.getSelectedItem(), whereOp.getSelectedItem(), whereTF.getText().replaceAll(" ","+") ) );
                } else {
                    lparams.remove("where");
                }
            } else {
                lparams.remove("where");
            }
        }

        split.params= URISplit.formatParams(lparams);
        if ( split.params!=null && split.params.length()==0 ) split.params= null;
        return URISplit.format(split);
    }

    @Override
    public void markProblems(List<String> problems) {
        
    }

    /**
     * fill the parameter tree using metadata.
     * @param parameterTree the tree which will contain the parameter list.
     * @param mm the metadata map from parameter names to html descriptions.
     * @param cdf the cdf file.
     * @param param null or the name of the parameter which should be selected.
     * @param slice1 null or the slice selection (X,Y,Z of BGSM, for example).
     */
    private void fillTree( JTree parameterTree, Map<String,String> mm, gov.nasa.gsfc.spdf.cdfj.CDFReader cdf, String param, String slice1 ) {
        
        logger.entering( "CdfJavaDataSourceEditorPanel", "fillTree" );
        
        DefaultMutableTreeNode root= new DefaultMutableTreeNode("");

        List<TreePath> expand=new ArrayList(mm.size());
        
        String filter= filterComboBox.getText().trim();
        Pattern filterPattern= null; 
        
        if ( filter.length()>0 ) {
            try {
                filterPattern= Pattern.compile(filter,Pattern.CASE_INSENSITIVE);    
            } catch ( PatternSyntaxException ex ) {
                filterPattern= Pattern.compile( Pattern.quote(filter), Pattern.CASE_INSENSITIVE );
            }
        }
        
        boolean sortAlpha= sortAlphaCheckBox.isSelected();
        if ( sortAlpha ) {
            Map<String,String> sortedMM= new TreeMap<>();
            sortedMM.putAll(mm);
            mm= sortedMM;
        }
            
        List<TreePath> selections= new ArrayList<>();
        List<String> params;
        if ( param!=null ) {
            params = Arrays.asList(param.split(";"));
        } else {
            params= new ArrayList<>();
        }
                
        TreePath selection=null;
        for ( Entry<String,String> e: mm.entrySet() ) {
            String varname = e.getKey();
            
            if ( filterPattern!=null ) {
                if ( filterPattern.matcher( varname ).find() || 
                        filterPattern.matcher( e.getValue() ).find() ) {
                    logger.log(Level.FINER, "found pattern for {0}", varname );
                } else {
                    continue;
                }
            }
            
            try {
                Object oattr= cdf.getAttribute( varname, "LABL_PTR_2");
                String lablPtr=null;
                
                if ( oattr!=null && oattr instanceof List ) {
                    List voattr= (List)oattr;
                    if ( voattr.size()>0 ) {
                        lablPtr= (String)((List)oattr).get(0);
                    } else {
                        oattr= Collections.emptyList();
                    }
                } 
                
                if ( oattr!=null && oattr instanceof List && ((List)oattr).size()==0 ) {
                    oattr= cdf.getAttribute( varname, "LABL_PTR_1");
                    if ( oattr!=null && oattr instanceof List ) {
                        List voattr= (List)oattr;
                        if ( voattr.size()>0 ) {
                            lablPtr= (String)((List)oattr).get(0);
                        } else {
                            oattr= null;
                        }
                    }
                }
                

                int[] dimensions= cdf.getDimensions( varname );
                boolean doComponents= oattr!=null && ( dimensions.length==1 || dimensions.length==2 ) && dimensions[dimensions.length-1]<=MAX_SLICE1_OFFER;
                if ( doComponents ) {
                    String s= lablPtr;
                    DefaultMutableTreeNode node= new DefaultMutableTreeNode( varname );
                    try {
                        Object o = cdf.get(s);
                        String[] rec;
                        if ( o.getClass().isArray() && String.class.isAssignableFrom( o.getClass().getComponentType() ) ) {
                            rec= (String[])o;
                        } else {
                            Object oo= Array.get(o,0);
                            if ( !oo.getClass().isArray() || !( String.class.isAssignableFrom( oo.getClass().getComponentType() ) ) ) {
                               logger.log(Level.FINE, "Expected string array in element: {0}", s);
                               continue;
                            }
                            rec= (String[])Array.get(o,0);
                        }
                        for ( int i=0; i<rec.length; i++ ) {
                            String snode=  String.format("%d: %s", i, rec[i] ) ;
                            DefaultMutableTreeNode child= new DefaultMutableTreeNode( snode );
                            node.add( child );
                            if ( varname.equals(param) ) {
                                if ( slice1!=null ) {
                                    if ( String.valueOf(i).equals(slice1) ) {
                                        selection= new TreePath( new Object[] { root, node, child } );
                                    }
                                } else {
                                    selection= new TreePath( new Object[] { root, node } );
                                }
                            }
                        }
                        root.add( node );
                        if ( rec.length<4 ) {
                            expand.add( new TreePath( new Object[] { root, node } ) );
                        }
                        
                    } catch (CDFException.ReaderError | ArrayIndexOutOfBoundsException | IllegalArgumentException ex ) {
                        logger.log(Level.WARNING,"parameter name found: "+s+" referred to by " +varname,ex);
                        root.add( node );
                    }

                } else {
                    DefaultMutableTreeNode node=  new DefaultMutableTreeNode( varname );
                    root.add( node );
                    if ( params.contains(varname) ) {
                        selections.add( new TreePath( new Object[] { root, node } ) );
                    }
                    if ( varname.equals(param) ) {
                        selection= new TreePath( new Object[] { root, node } );
                    }
                }
            } catch ( CDFException.ReaderError t ) {
                logger.log(Level.WARNING,t.getMessage(),t);

            }
        }

        DefaultTreeModel tm= new DefaultTreeModel( root );

        parameterTree.setRootVisible(false);
        parameterTree.setModel(tm);

        if ( selection!=null ) {
            parameterTree.setSelectionPath(selection);
            parameterTree.scrollPathToVisible(selection);
        }
        
        if ( selections.size()>0 ) {
            parameterTree.setSelectionPaths( selections.toArray(new TreePath[selections.size()]) );
        }
        
        for ( TreePath tp: expand ) {
            parameterTree.expandPath(tp);
        }
        
        logger.exiting("CdfJavaDataSourceEditorPanel", "fillTree" );
        
    }

    private static boolean isSupportParameter(Map<String, CdfVariableDescription> dataParameterInfo, String param) {
        if ( param==null || param.trim().length()==0  ) {
            return false;
        }
        String[] params;
        if ( param.contains(";") ) {
            params= param.split(";");
        } else {
            params= new String[] { param };
        }
        for ( String p: params ) {
            CdfVariableDescription cdfvd= dataParameterInfo.get(p);
            if ( cdfvd!=null ) { // sure hope so
                if ( cdfvd.isSupport ) return true;
            }
        }
        return false;
    }

}