
/**
 * FRETViewPlugin.java
 * A simple plugin for looking at helping designing more 
 * Created: May 11, 2006
 *
 * @author Nathan Stevens
 * @version 0.2 2/18/2007
 */
import java.awt.*;
import java.awt.event.*;
import java.awt.datatransfer.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.*;
import javax.swing.table.*;
import java.io.*;
import java.text.*;
import java.util.*;
import java.net.*;

public class FRETViewPlugin extends JFrame implements InstruViewPlugin, ActionListener, 
ListSelectionListener, ChangeListener {
  private static final String VERSION = "0.2 (2-18-07)"; // the plugin version
  public final static String FILE_EXT = ".dal"; // the extension binary files should be saved with
  private InstruView instruView= null; // the main instruview object
  private JFileChooser fc = new JFileChooser(); // The file chooser object
  private String name = "FRETView"; // the name of the dialog
  private SpectraData[] sda = null; // stores any spectra data
  private JList daList = null;  // hold the absorption/emission spectra data
  private JTabbedPane tabPane = null; // the main tab pane
  private DBInfoDialog infoDialog = null; // displays informations about the database
  
  /** The binary file manager
  */
  private BinaryFileManager2 bm = new BinaryFileManager2();
  
  /** Objects that hold the spectra data
  */
  public DonorAcceptorData dyeData = null; // hold the spectra data
  public DyeSpectra currentDye = null;
  public DyeSpectra donorDye = null;
  public DyeSpectra acceptorDye = null;
  private DyeSpectra sbDye = null; // the data used for calculating lifetime using Strickler-Berg formula
  
  /** gui components for the FRET tab
  */
  private JLabel donorLB = null; // the donor name
  private JLabel acceptorLB = null; // the acceptor name
  private JCheckBox d_absCB = null; // used to plot the donor's absorption
  private JCheckBox d_emsCB = null; // used to plot the donor's emission
  private JCheckBox a_absCB = null; // used to plot the acceptor's absorption
  private JCheckBox a_emsCB = null; // used to plot the acceptor's emission
  
  // gui components for input parameters
  private JComboBox sbCoB = null; // select the dye to calculate the lifetime of using sb
  private JTextField sbecTF = null; // EC max of the dye
  private JTextField sbqyTF = null; // QY of the dye
  private JTextField sbrangeTF = null; // wavelength range
  
  private JTextField ecTF = null; // the extinction coefficient textfield
  private JTextField qyTF = null; // the quantum yield textfield
  private JTextField tauTF = null; // the lifetime textfield
  public JComboBox unitsCoB = null; // the lifetime units
  private JTextField r0TF = null; // the forter distant textfield
  private JTextField nTF = null; // the refractive index textfield
  private JTextField kTF = null; // the kappa textfield
  private JTextField daTF = null; // the donor/acceptor ratio text field
  private JTextField wlminTF = null; // the wavelenght min
  private JTextField wlmaxTF = null; // the wavelenght max
  private JTextField wlincTF = null; // the wavelenght increment
  private JTextField dminTF = null; // the distance min
  private JTextField dmaxTF = null; // the distance max
  private JTextField dincTF = null; // the distance increment
  
  // gui components for output parameters
  public JComboBox varCoB = null; // the variable wavelenght or distance selection 
  private JLabel varLB = null; // which of the two is variable
  public JComboBox valueCoB = null; // the wavelenght or distance value
  
  // the main table that displays the data
  private JTable results_table = null;
  
  /** gui components for the database manage tab
  */
  private JCheckBox invCB = null; // used to import invitrogen data
  private JCheckBox aeCB = null; // used to import absorption/emission pair files
  private JTextField grabTF = null; // name of absorption spectra data imported from InstruView
  
  private JTextField dnameTF = null; // name of dye spectra object
  private JTextField decTF = null; // EC dye spectra
  private JTextField dqyTF = null; // EC dye spectra
  private JTextField dtauTF = null; // EC dye spectra
  private JComboBox dunitsCoB = null; // the lifetime units
  private JTextField dnotesTF = null; // EC dye spectra
  
  private JTextArea console = null; // the programs console
  
  /** stores the current selections
  */
  private int[] selectedData = null;
  
  // the index of the currnt tab
  private int tab_index = 0;
  
  // used to download a database file from the server
  private DownloadDialog downloadDialog = null;
  
  // used to plot the results
  private PlotPropertiesDialog plotPropertiesDialog = null;
  
  // used to plot spectra
  private PlotSpectraDialog plotSpectraDialog = null;
  
  // store the wavelengths, distances, and results
  public float[] wavelengths = null;
  public float[] distances = null;
  public float[][] efficiency = null;
  public float[][] transfer_rate = null;
  public float[][] donor_intensity = null;
  public float[][] acceptor_intensity = null;
  public float[][] total_intensity = null;
  public float[][] lifetime = null;
  
  // store the data that is presented in the table
  private static String[] colNames = {"WL", "r", "E", "kt", "Fd", "Fa", "Ft", "Fa/Fd", "Tau_a"};
  private String[][] data = null;
  
  // properties object for storing of program attributes
  public static Properties properties = new Properties();
  public static String propertiesFileName = System.getProperty("user.home") + 
  System.getProperty("file.separator") + "fretview.ini";
  
  // constructor isn't really used
  public FRETViewPlugin() { }
  
  // the main constructor
  public FRETViewPlugin(InstruView instruView) {
    super("FRETView v- " + VERSION);
    
    this.instruView = instruView;
    
    // handles clossing of this plugin
		addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent we) {
        setVisible(false);
        dispose();
      }
		});
    
    // initialize the donor acceptor data
    String[] meta  = new String[8];
    meta[0] = InstruView.getProperty("organization");
    meta[1] = InstruView.getProperty("laboratory");
    meta[2] = InstruView.getProperty("owner");
    meta[3] = InstruView.getProperty("email");
    meta[4] = "FRETView Database";
    meta[5] = "mm-dd-yyyy";
    meta[6] = "00";
    this.dyeData = new DonorAcceptorData("FRETView Data", meta);
    
    // if a deafult spectra datalist file exist load it
    File dataDirectory = new File(InstruView.dataDirectoryName + "/DAL");
    
    //set the file filter for the program
    fc.setCurrentDirectory(dataDirectory);
    fc.setMultiSelectionEnabled(true);
    
    FRETViewFileFilter fileFilter  = new FRETViewFileFilter();
    fc.resetChoosableFileFilters();
    fc.addChoosableFileFilter(fileFilter);
    
    /**
    **Create the gui now
    **/
    // set the layout to border layer
    getContentPane().setLayout(new BorderLayout());
    
    // some gui stuff
    JPanel panel;
    JLabel label;
    JButton button;
    TitledBorder titleBorder;
    
    // add the ab list to the east panel
    JPanel pA = new JPanel();
    pA.setLayout(new BoxLayout(pA, BoxLayout.Y_AXIS));
    titleBorder = BorderFactory.createTitledBorder("Spectral Database");
    pA.setBorder(titleBorder);
    
    String[] daNames = getDonorAcceptorNames();
    
    daList = new JList(daNames);
		daList.addListSelectionListener(this);
		
    JScrollPane listScrollPane = new JScrollPane(daList);
		listScrollPane.setAlignmentX(Component.LEFT_ALIGNMENT);
    
    pA.add(listScrollPane);
    
    getContentPane().add(pA, "Center");
    
    // add the tabbed panel
    tabPane = new JTabbedPane();
    tabPane.addChangeListener(this);
    
     //panel for entering FREt parameters
    tabPane.addTab("FRET Parameters", null, getFRETParameterPanel(),
                                                       "Enter and calculate FRET parameters"); //tooltip text
    
    tabPane.addTab("Manage Spectral Database", null, getManageDBPanel(),
                                                       "Manage the spectral database"); //tooltip text
    
    // add the help tab
    tabPane.addTab("Help", null, getHelpPanel(),
    "Help page for using this plugin"); //tooltip text
    
    getContentPane().add(tabPane, "East");
    
    // add the button panel to the south location
    JPanel buttonPanel = new JPanel();
		buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
    
    button = new JButton("Calculate");
		button.setActionCommand("calculate");
		button.addActionListener(this);
    buttonPanel.add(button);
    
    button = new JButton("Plot");
		button.setActionCommand("plot");
		button.addActionListener(this);
    buttonPanel.add(button);
    
    /*button = new JButton("FRET Map");
		button.setActionCommand("fretmap");
		button.addActionListener(this);
    buttonPanel.add(button);*/
    
    button = new JButton("Spectra");
		button.setActionCommand("spectra");
		button.addActionListener(this);
    buttonPanel.add(button);
    
    button = new JButton("Lifetime");
		button.setActionCommand("slifetime");
		button.addActionListener(this);
    buttonPanel.add(button);
    
    button = new JButton("Copy");
		button.setActionCommand("copy");
		button.addActionListener(this);
    buttonPanel.add(button);
    
    /*button = new JButton("To InstruView");
		button.setActionCommand("toinstruview");
		button.addActionListener(this);
    buttonPanel.add(button);*/
    
    button = new JButton("Clear");
		button.setActionCommand("clear");
		button.addActionListener(this);
    buttonPanel.add(button);
    
    buttonPanel.add(Box.createHorizontalGlue());
    
    button = new JButton("Close");
		button.setActionCommand("close");
		button.addActionListener(this);
    buttonPanel.add(button);
    
    getContentPane().add(buttonPanel, "South");
    
    // load the spectral database file and other program properties
    loadProperties();
    String filename = properties.getProperty("dbfile");
    if(filename != null) {
      File file = new File(filename);
      openDonorAcceptorList(file);
    }
    
    // set this visible
    pack();
    setVisible(true);
  }
  
  // function to get the fret panel
  private JPanel getFRETParameterPanel() {
    JPanel mainPanel = new JPanel();
    mainPanel.setLayout(new BorderLayout());
    
    // The gui components
    GridBagLayout gridbag;
    GridBagConstraints c;
    JButton button;
    JLabel label;
    TitledBorder titledB;
    
    // add the "set donor" and "set acceptor" button
    JPanel panel_A = new JPanel();
    gridbag = new GridBagLayout();
    c = new GridBagConstraints();
    c.fill = GridBagConstraints.HORIZONTAL; 
    panel_A.setLayout(gridbag);
    
    // set the border
    titledB = BorderFactory.createTitledBorder("Donor/Acceptor");
    panel_A.setBorder(titledB);
    
    button = new JButton("Set Donor");
    button.setActionCommand("setdonor");
		button.addActionListener(this);
    c.gridx = 0;
    c.gridy = 0;
    gridbag.setConstraints(button, c);
    panel_A.add(button);
    
    donorLB = new JLabel(" No Donor Set...");
    donorLB.setForeground(Color.blue);
    c.gridx = 1;
    c.gridy = 0;
    c.weightx = 1.0; // get any extra width space
    gridbag.setConstraints(donorLB, c);
    panel_A.add(donorLB);
    
    c.weightx = 0; // reset this
    
    d_absCB = new JCheckBox("Abs");
    d_absCB.setSelected(true);
    c.gridx = 2;
    c.gridy = 0;
    gridbag.setConstraints(d_absCB, c);
    panel_A.add(d_absCB);
    
    d_emsCB = new JCheckBox("Ems");
    d_emsCB.setSelected(true);
    c.gridx = 3;
    c.gridy = 0;
    gridbag.setConstraints(d_emsCB, c);
    panel_A.add(d_emsCB);
    
    button = new JButton("Plot");
    button.setActionCommand("plot1");
		button.addActionListener(this);
    c.gridx = 4;
    c.gridy = 0;
    c.gridheight = 2;
    //c.fill = GridBagConstraints.VERTICAL;
    gridbag.setConstraints(button, c);
    panel_A.add(button);
    
    c.gridheight = 1; // reset the grid height and horizontal fill
    c.fill = GridBagConstraints.HORIZONTAL;
    
    button = new JButton("Set Acceptor");
    button.setActionCommand("setacceptor");
		button.addActionListener(this);
    c.gridx = 0;
    c.gridy = 1;
    gridbag.setConstraints(button, c);
    panel_A.add(button);
    
    acceptorLB = new JLabel(" No Acceptor Set...");
    acceptorLB.setForeground(Color.red);
    c.gridx = 1;
    c.gridy = 1;
    gridbag.setConstraints(acceptorLB, c);
    panel_A.add(acceptorLB);
    
    a_absCB = new JCheckBox("Abs");
    a_absCB.setSelected(true);
    c.gridx = 2;
    c.gridy = 1;
    gridbag.setConstraints(a_absCB, c);
    panel_A.add(a_absCB);
    
    a_emsCB = new JCheckBox("Ems");
    a_emsCB.setSelected(true);
    c.gridx = 3;
    c.gridy = 1;
    gridbag.setConstraints(a_emsCB, c);
    panel_A.add(a_emsCB);
    
    // add panel to the north position
    mainPanel.add(panel_A, "North");
    
    /**
    *Add the panel that allows the inputing of parameters
    */
    
    int tfs = 7; // the text field size
    
    JPanel panel_B = new JPanel();
    gridbag = new GridBagLayout();
    c = new GridBagConstraints();
    c.fill = GridBagConstraints.HORIZONTAL; 
    panel_B.setLayout(gridbag);
    
    // set the border
    titledB = BorderFactory.createTitledBorder("Input Parameters");
    panel_B.setBorder(titledB);
    
    // first row
    // Add the panel that allows calculating of R0 and lifetime using strickler berg
    // formular
    JPanel panel_B1 = new JPanel();
    panel_B1.setLayout(new FlowLayout(FlowLayout.LEFT, 2, 2));
    
    c.gridx = 0;
    c.gridy = 0;
    c.gridwidth = 8;
    gridbag.setConstraints(panel_B1, c);
    
    button = new JButton("Ro");
    button.setActionCommand("r0");
		button.addActionListener(this);
    panel_B1.add(button);
    
    panel_B1.add(Box.createRigidArea(new Dimension(5,0)));
    
    button = new JButton("Tau");
    button.setActionCommand("tau");
		button.addActionListener(this);
    panel_B1.add(button);
    
    label = new JLabel(" Data ");
    panel_B1.add(label);
    
    String[] data = {"Selected", "Donor", "Acceptor"};
    sbCoB = new JComboBox(data);
    sbCoB.setBackground(Color.yellow);
    sbCoB.setActionCommand("sbdata");
		sbCoB.addActionListener(this);
    panel_B1.add(sbCoB);
    
    label = new JLabel(" EC = ");
    panel_B1.add(label);
    
    sbecTF = new JTextField("1.0", tfs);
    sbecTF.setBackground(Color.yellow);
    panel_B1.add(sbecTF);
    
    label = new JLabel(" QY = ");
    panel_B1.add(label);
    
    sbqyTF = new JTextField("1.0", 3);
    sbqyTF.setBackground(Color.yellow);
    panel_B1.add(sbqyTF);
    
    label = new JLabel("<html> S<sub>0</sub> -> S<sub>1</sub> ");
    panel_B1.add(label);
    
    sbrangeTF = new JTextField("", tfs);
    sbrangeTF.setBackground(Color.yellow);
    panel_B1.add(sbrangeTF);
    
    panel_B.add(panel_B1);
    
    c.gridwidth = 1; // reset this value
    
    // second row
    label = new JLabel("EC = ");
    c.gridx = 0;
    c.gridy = 1;
    gridbag.setConstraints(label, c);
    panel_B.add(label);
    
    ecTF = new JTextField("1.0", tfs);
    c.gridx = 1;
    c.gridy = 1;
    gridbag.setConstraints(ecTF, c);
    panel_B.add(ecTF);
    
    label = new JLabel(" QY = ");
    c.gridx = 2;
    c.gridy = 1;
    gridbag.setConstraints(label, c);
    panel_B.add(label);
    
    qyTF = new JTextField("1.0", tfs);
    c.gridx = 3;
    c.gridy = 1;
    gridbag.setConstraints(qyTF, c);
    panel_B.add(qyTF);
    
    label = new JLabel(" Tau = ");
    c.gridx = 4;
    c.gridy = 1;
    gridbag.setConstraints(label, c);
    panel_B.add(label);
    
    tauTF = new JTextField("1.0", tfs);
    tauTF.setActionCommand("tau"); // used to calcualte the lifetime using strickler-berg formular
		tauTF.addActionListener(this);
    c.gridx = 5;
    c.gridy = 1;
    gridbag.setConstraints(tauTF, c);
    panel_B.add(tauTF);
    
    label = new JLabel(" Units ");
    c.gridx = 6;
    c.gridy = 1;
    gridbag.setConstraints(label, c);
    panel_B.add(label);
    
    String[] units = {"picosecond", "nanosecond", "microsecond", "millisecond", "second"};
    unitsCoB = new JComboBox(units);
    c.gridx = 7;
    c.gridy = 1;
    gridbag.setConstraints(unitsCoB, c);
    panel_B.add(unitsCoB);
    
    // add this for alignment
    label = new JLabel("");
    c.gridx = 8;
    c.gridy = 1;
    c.weightx = 1.0; // get any extra width space
    gridbag.setConstraints(label, c);
    panel_B.add(label);
    
    c.weightx = 0.0;
    
    // the third row
    label = new JLabel("Ro = ");
    c.gridx = 0;
    c.gridy = 2;
    gridbag.setConstraints(label, c);
    panel_B.add(label);
    
    r0TF = new JTextField("1.0", tfs);
    r0TF.setActionCommand("r0"); // used to calcualte the forster distance
		r0TF.addActionListener(this);
    c.gridx = 1;
    c.gridy = 2;
    gridbag.setConstraints(r0TF, c);
    panel_B.add(r0TF);
    
    label = new JLabel(" n = ");
    c.gridx = 2;
    c.gridy = 2;
    gridbag.setConstraints(label, c);
    panel_B.add(label);
    
    nTF = new JTextField("1.33", tfs);
    c.gridx = 3;
    c.gridy = 2;
    gridbag.setConstraints(nTF, c);
    panel_B.add(nTF);
    
    label = new JLabel(" K^2 = ");
    c.gridx = 4;
    c.gridy = 2;
    gridbag.setConstraints(label, c);
    panel_B.add(label);
    
    kTF = new JTextField("0.667", tfs);
    c.gridx = 5;
    c.gridy = 2;
    gridbag.setConstraints(kTF, c);
    panel_B.add(kTF);
    
    label = new JLabel(" D/A ratio ");
    c.gridx = 6;
    c.gridy = 2;
    gridbag.setConstraints(label, c);
    panel_B.add(label);
    
    daTF = new JTextField("1 : 1", tfs);
    c.gridx = 7;
    c.gridy = 2;
    gridbag.setConstraints(daTF, c);
    panel_B.add(daTF);
    
    // the fourth row
    label = new JLabel("Wavelength Range (nm) ");
    c.gridx = 0;
    c.gridy = 3;
    c.gridwidth = 3;
    gridbag.setConstraints(label, c);
    panel_B.add(label);
    
    c.gridwidth = 1; // reset this
    
    wlminTF = new JTextField("400.0", tfs);
    c.gridx = 3;
    c.gridy = 3;
    gridbag.setConstraints(wlminTF, c);
    panel_B.add(wlminTF);
    
    label = new JLabel(" to ");
    c.gridx = 4;
    c.gridy = 3;
    gridbag.setConstraints(label, c);
    panel_B.add(label);
    
    wlmaxTF = new JTextField("500.0", tfs);
    c.gridx = 5;
    c.gridy = 3;
    gridbag.setConstraints(wlmaxTF, c);
    panel_B.add(wlmaxTF);
    
    label = new JLabel(" Inc = ");
    c.gridx = 6;
    c.gridy = 3;
    gridbag.setConstraints(label, c);
    panel_B.add(label);
    
    wlincTF = new JTextField("10.0", tfs);
    c.gridx = 7;
    c.gridy = 3;
    gridbag.setConstraints(wlincTF, c);
    panel_B.add(wlincTF);
    
    // the fifth row
    label = new JLabel("Distance Range (Ang) ");
    c.gridx = 0;
    c.gridy = 4;
    c.gridwidth = 3;
    gridbag.setConstraints(label, c);
    panel_B.add(label);
    
    c.gridwidth = 1; // reset this
    
    dminTF = new JTextField("10.0", tfs);
    c.gridx = 3;
    c.gridy = 4;
    gridbag.setConstraints(dminTF, c);
    panel_B.add(dminTF);
    
    label = new JLabel(" to ");
    c.gridx = 4;
    c.gridy = 4;
    gridbag.setConstraints(label, c);
    panel_B.add(label);
    
    dmaxTF = new JTextField("210.0", tfs);
    c.gridx = 5;
    c.gridy = 4;
    gridbag.setConstraints(dmaxTF, c);
    panel_B.add(dmaxTF);
    
    label = new JLabel(" Inc = ");
    c.gridx = 6;
    c.gridy = 4;
    gridbag.setConstraints(label, c);
    panel_B.add(label);
    
    dincTF = new JTextField("1.0", tfs);
    c.gridx = 7;
    c.gridy = 4;
    gridbag.setConstraints(dincTF, c);
    panel_B.add(dincTF);
    
    mainPanel.add(panel_B, "Center");
    
    
    /**
    *Add the panel that allows viewing of results
    */
    JPanel panel_C = new JPanel();
    panel_C.setLayout(new BorderLayout());
    
    // set the border
    titledB = BorderFactory.createTitledBorder("Output Parameters");
    panel_C.setBorder(titledB);
    
    JPanel panel_C1 = new JPanel();
    panel_C1.setLayout(new BoxLayout(panel_C1, BoxLayout.X_AXIS));
    
    label = new JLabel("Variable : ");
    panel_C1.add(label);
    
    String[] var = {"Distance", "Wavelength"};
    varCoB = new JComboBox(var); // must implement a change listener
    varCoB.setActionCommand("setvariable");
    varCoB.addActionListener(this);
    panel_C1.add(varCoB);
    
    varLB = new JLabel(" Wavelength @ ");
    panel_C1.add(varLB);
    
    String[] values = {"400", "410", "420", "430", "440", "450"};
    valueCoB = new JComboBox(values); // must implement a change listener
    panel_C1.add(valueCoB);
    
    panel_C1.add(Box.createHorizontalGlue());
    
    button = new JButton("Update");
    button.setActionCommand("update_results");
		button.addActionListener(this);
    panel_C1.add(button);
    
    panel_C.add(panel_C1, "North");
    
    // add the table that holds the results here
    //panel_C.add(Box.createRigidArea(new Dimension(0, 200)));
    results_table = new JTable(15, 9);
    JScrollPane scrollpane = new JScrollPane(results_table);
    scrollpane.setPreferredSize(new Dimension(400, 200));
    panel_C.add(scrollpane, "Center");
    
    //label = new JLabel("<html>FRETView Plugin<br>Simple plugin for obtaining FRET parameters designing...");
    // panel_C.add(label, "South");
    
    mainPanel.add(panel_C, "South");
    
    return mainPanel;
  }
  
  // function to get the database management panel
  private JPanel getManageDBPanel() {
    JPanel mainPanel = new JPanel();
    mainPanel.setLayout(new BorderLayout());
    
    // The gui components
    GridBagLayout gridbag;
    GridBagConstraints c;
    JButton button;
    JLabel label;
    TitledBorder titledB;
    
    /** add the panel that allows importing of data
    */
    JPanel panel_A = new JPanel();
    gridbag = new GridBagLayout();
    c = new GridBagConstraints();
    c.fill = GridBagConstraints.HORIZONTAL; 
    panel_A.setLayout(gridbag);
    
    // set the border
    titledB = BorderFactory.createTitledBorder("Import Dye Spectra");
    panel_A.setBorder(titledB);
    
    button = new JButton("Import");
    button.setActionCommand("import");
		button.addActionListener(this);
    c.gridx = 0;
    c.gridy = 0;
    gridbag.setConstraints(button, c);
    panel_A.add(button);
    
    ButtonGroup group = new ButtonGroup();
    
    invCB = new JCheckBox("Invitrogen");
    invCB.setSelected(true);
    group.add(invCB);
    c.gridx = 1;
    c.gridy = 0;
    gridbag.setConstraints(invCB, c);
    panel_A.add(invCB);
    
    aeCB = new JCheckBox("Abs/Ems Pair");
    aeCB.setSelected(false);
    group.add(aeCB);
    c.gridx = 2;
    c.gridy = 0;
    gridbag.setConstraints(aeCB, c);
    panel_A.add(aeCB);
    
    button = new JButton("Grab");
    button.setActionCommand("grab");
		button.addActionListener(this);
    c.gridx = 0;
    c.gridy = 1;
    gridbag.setConstraints(button, c);
    panel_A.add(button);
    
    int tfs = 14;
    grabTF = new JTextField("None", tfs);
    grabTF.setEditable(false);
    grabTF.setBackground(Color.white);
    c.gridx = 1;
    c.gridy = 1;
    c.gridwidth =2;
    gridbag.setConstraints(grabTF, c);
    panel_A.add(grabTF);
    
    c.gridwidth =1;
    
    label = new JLabel("");
    c.gridx = 3;
    c.gridy = 1;
    c.weightx = 1.0f;
    gridbag.setConstraints(label, c);
    panel_A.add(label);
    
    c.weightx = 0.0f; // reset
    
    button = new JButton("Download");
    button.setActionCommand("download"); // must implement later
		button.addActionListener(this);
    c.gridx = 4;
    c.gridy = 1;
    gridbag.setConstraints(button, c);
    panel_A.add(button);
    
    button = new JButton("New");
    button.setActionCommand("new");
		button.addActionListener(this);
    c.gridx = 0;
    c.gridy = 2;
    gridbag.setConstraints(button, c);
    panel_A.add(button);
    
    JPanel panel_A1 = new JPanel();
    panel_A1.setLayout(new FlowLayout(FlowLayout.LEFT, 0,0));
    c.gridx = 1;
    c.gridy = 2;
    gridbag.setConstraints(panel_A1, c);
    
    button = new JButton("Open");
    button.setActionCommand("open");
		button.addActionListener(this);
    panel_A1.add(button);
    
    button = new JButton("Save");
    button.setActionCommand("save");
		button.addActionListener(this);
    panel_A1.add(button);
    
    button = new JButton("Save As");
    button.setActionCommand("saveas");
		button.addActionListener(this);
    panel_A1.add(button);
    
    panel_A.add(panel_A1);
    
    label = new JLabel("");
    c.gridx = 3;
    c.gridy = 2;
    c.weightx = 1.0f;
    gridbag.setConstraints(label, c);
    panel_A.add(label);
    
    c.weightx = 0.0f; // reset
    
    button = new JButton("DB Info");
    button.setActionCommand("info");
		button.addActionListener(this);
    c.gridx = 4;
    c.gridy = 2;
    gridbag.setConstraints(button, c);
    panel_A.add(button);
    
    mainPanel.add(panel_A, "North");
    
    /** add the panel that allows changing of the dye spectra object properties
    */
    
    JPanel panel_B = new JPanel();
    gridbag = new GridBagLayout();
    c = new GridBagConstraints();
    c.fill = GridBagConstraints.HORIZONTAL; 
    panel_B.setLayout(gridbag);
    
    // set the border
    titledB = BorderFactory.createTitledBorder("Current Dye Spectra");
    panel_B.setBorder(titledB);
    
    tfs = 10;
    
    // row one
    label = new JLabel("Name ");
    c.gridx = 0;
    c.gridy = 0;
    gridbag.setConstraints(label, c);
    panel_B.add(label);
    
    dnameTF = new JTextField("", tfs);
    dnameTF.setActionCommand("update");
		dnameTF.addActionListener(this);
    c.gridx = 1;
    c.gridy = 0;
    c.gridwidth = 3;
    c.weightx = 1.0f;
    gridbag.setConstraints(dnameTF, c);
    panel_B.add(dnameTF);
    
    c.gridwidth = 1; // reset these
    c.weightx = 0.0f;
    
    JPanel panel_B1 = new JPanel();
    panel_B1.setLayout(new FlowLayout(FlowLayout.LEFT, 0,0));
    c.gridx = 4;
    c.gridy = 0;
    gridbag.setConstraints(panel_A1, c);
    
    button = new JButton("Abs");
    button.setActionCommand("abs_data");
		button.addActionListener(this);
    panel_B1.add(button);
    
    button = new JButton("Ems");
    button.setActionCommand("ems_data");
		button.addActionListener(this);
    panel_B1.add(button);
    
    panel_B.add(panel_B1);
    
    // the second row
    label = new JLabel("EC ");
    c.gridx = 0;
    c.gridy = 1;
    gridbag.setConstraints(label, c);
    panel_B.add(label);
    
    decTF = new JTextField("", tfs);
    decTF.setActionCommand("update");
		decTF.addActionListener(this);
    c.gridx = 1;
    c.gridy = 1;
    gridbag.setConstraints(decTF, c);
    panel_B.add(decTF);
    
    label = new JLabel(" QY ");
    c.gridx = 2;
    c.gridy = 1;
    gridbag.setConstraints(label, c);
    panel_B.add(label);
    
    dqyTF = new JTextField("", tfs);
    dqyTF.setActionCommand("update");
		dqyTF.addActionListener(this);
    c.gridx = 3;
    c.gridy = 1;
    gridbag.setConstraints(dqyTF, c);
    panel_B.add(dqyTF);
    
    // the third row
    label = new JLabel("Tau ");
    c.gridx = 0;
    c.gridy = 2;
    gridbag.setConstraints(label, c);
    panel_B.add(label);
    
    dtauTF = new JTextField("", tfs);
    dtauTF.setActionCommand("update");
		dtauTF.addActionListener(this);
    c.gridx = 1;
    c.gridy = 2;
    gridbag.setConstraints(dtauTF, c);
    panel_B.add(dtauTF);
    
    label = new JLabel(" Units ");
    c.gridx = 2;
    c.gridy = 2;
    gridbag.setConstraints(label, c);
    panel_B.add(label);
    
    String[] units = {"picosecond", "nanosecond", "microsecond", "millisecond", "second"};
    dunitsCoB = new JComboBox(units);
    c.gridx = 3;
    c.gridy = 2;
    gridbag.setConstraints(dunitsCoB, c);
    panel_B.add(dunitsCoB);
    
    
    button = new JButton("Update");
    button.setActionCommand("update");
		button.addActionListener(this);
    c.gridx = 4;
    c.gridy = 2;
    gridbag.setConstraints(button, c);
    panel_B.add(button);
    
    // the fourth row
    label = new JLabel("Notes ");
    c.gridx = 0;
    c.gridy = 3;
    gridbag.setConstraints(label, c);
    panel_B.add(label);
    
    dnotesTF = new JTextField("", tfs);
    dnotesTF.setActionCommand("update");
		dnotesTF.addActionListener(this);
    c.gridx = 1;
    c.gridy = 3;
    c.gridwidth = 3;
    c.weightx = 1.0f;
    gridbag.setConstraints(dnotesTF, c);
    panel_B.add(dnotesTF);
    
    c.gridwidth = 1; // reset these
    c.weightx = 0.0f;
    
    button = new JButton("Remove");
    button.setActionCommand("remove");
		button.addActionListener(this);
    c.gridx = 4;
    c.gridy = 3;
    gridbag.setConstraints(button, c);
    panel_B.add(button);
    
    mainPanel.add(panel_B, "Center");
    
    
     /** add the panel that allows changing of the dye spectra object properties
    */
    
    JPanel panel_C = new JPanel();
    panel_C.setLayout(new BorderLayout());
    
    // set the border
    titledB = BorderFactory.createTitledBorder("Console");
    panel_C.setBorder(titledB);
    
    JPanel panel_C1 = new JPanel();
    panel_C1.setLayout(new BoxLayout(panel_C1, BoxLayout.X_AXIS));
    
    button = new JButton("Clear");
    button.setActionCommand("cclear");
		button.addActionListener(this);
    panel_C1.add(button);
    
    button = new JButton("Copy");
    button.setActionCommand("ccopy");
		button.addActionListener(this);
    panel_C1.add(button);
    
    button = new JButton("Run Command");
    button.setActionCommand("runcomand");
		button.addActionListener(this);
    button.setEnabled(false);
    panel_C1.add(button);
    
    panel_C1.add(Box.createHorizontalGlue());
    
    panel_C.add(panel_C1, "North");
    
    console = new JTextArea();
    console.setEditable(true);
    JScrollPane scrollpane = new JScrollPane(console);
    scrollpane.setPreferredSize(new Dimension(400, 200));
    panel_C.add(scrollpane, "Center");
    
    mainPanel.add(panel_C, "South");
    
    return mainPanel;
  }
  
  // function to get the database management panel
  private JPanel getHelpPanel() {
    JPanel mainPanel = new JPanel();
    mainPanel.setLayout(new BorderLayout());
    
    JEditorPane editorPane = new JEditorPane();
    editorPane.setEditable(false);
    
    // get the help url.
    URL helpURL = null;
    String fileName = "jar:file:" + InstruViewPluginLoader.getJarFileName("fretview")
    + "!/help.html";
    
    try {
      helpURL = new URL(fileName);
      editorPane.setPage(helpURL);
    }
    catch (IOException e) {
      System.err.println("Attempted to read a bad URL: " + helpURL);
    }
    
    JScrollPane editorScrollPane = new JScrollPane(editorPane);
    editorScrollPane.setPreferredSize(new Dimension(400, 200));
    mainPanel.add(editorScrollPane, "Center");
    
    return mainPanel;
  }
  
  // Method to return information about this plugin
  public String[] getPluginInformation() {
    String[] information = {"Author : Nathan Stevens",
                                            "Version : " + VERSION,
                                            "",
                                            "A simple plugin for calculating energy transfer parameters"};
    
    return information;
  }
  
  // Method to handel action events
  public void actionPerformed(ActionEvent ae) {
    String cmd = ae.getActionCommand();
    
    if(cmd.equals("calculate")) {
			calculate();
		}
    else if(cmd.equals("plot")) {
      if(tab_index == 0) {
        showPlotOptions();
      }
      else if(tab_index == 1) { // show the plot spectra dialog box
        showPlotSpectraDialog();
      }
    }
    else if(cmd.equals("spectra")) {
      showSimulatedSpectra();
    }
    else if(cmd.equals("slifetime")) {
      showSimulatedLifetime();
    }
    else if(cmd.equals("setdonor")) {
      setDyeSpectra("donor");
    }
    else if(cmd.equals("setacceptor")) {
      setDyeSpectra("acceptor");
    }
    else if(cmd.equals("plot1")) {
      plotDyeSpectra();
    }
    else if(cmd.equals("tau")) {
      calculateLifetime();
    }
    else if(cmd.equals("r0")) {
      calculateR0();
    }
    else if(cmd.equals("sbdata")) {
      setSBData();
    }
    else if(cmd.equals("setvariable")) {
      setVariableData();
    }
    else if(cmd.equals("update_results")) {
      updateResults();
    }
    else if(cmd.equals("import")) {
      importDataFile();
    }
    else if(cmd.equals("new")) {
      createNewDonorAcceptorList();
    }
    else if(cmd.equals("open")) {
      openDonorAcceptorList();
    }
    else if(cmd.equals("save")) {
      saveDonorAcceptorList();
    }
    else if(cmd.equals("saveas")) {
      saveDonorAcceptorListAs();
    }
    else if(cmd.equals("download")) {
      showDownloadDialog();
    }
    else if(cmd.equals("info")) {
      showDBInfoDialog();
    }
    else if(cmd.equals("abs_data")) {
      showDataViewDialog("absorption");
    }
    else if(cmd.equals("ems_data")) {
      showDataViewDialog("emission");
    }
    else if(cmd.equals("update")) {
      updateCurrentDyeInfo();
    }
    else if(cmd.equals("remove")) {
      removeCurrentDye();
    }
    else if(cmd.equals("copy")) {
      copyResults();
    }
    else if(cmd.equals("toinstruview")) {
      addToInstruView();
    }
    else if(cmd.equals("grab")) {
      getFromInstruView();
    }
    else if(cmd.equals("clear")) {
      clearData();
    }
    else if(cmd.equals("cclear")) {
      console.setText("");
    }
    else if(cmd.equals("ccopy")) {
      copyConsoleText();
    }
    else if(cmd.equals("close")) {
      setVisible(false);
      dispose();
    }
    else {
      System.err.println("Action Command not handeled in class FRETViewPlugin ...");
      System.err.println(cmd);
    }
  }
  
  // method to handel events when different tabs are selected
  public void stateChanged(ChangeEvent ce) {
		JTabbedPane tabbedPane = (JTabbedPane)ce.getSource();
		tab_index = tabbedPane.getSelectedIndex();
  }
  
  // Method to handel list selection events
	public void valueChanged(ListSelectionEvent e) {
    if (e.getValueIsAdjusting()) {
      return;
		}
		
    JList theList = (JList)e.getSource();
    if (!theList.isSelectionEmpty()) {
      selectedData = theList.getSelectedIndices();
    }
    
    if(dyeData.size() > 0 && selectedData != null) {
      currentDye = dyeData.getDyeSpectra(selectedData[0]);
      updateInfoPanel();
      
      // check to see if to call the setDBdata
      if(sbCoB.getSelectedIndex() == 0) {
        setSBData();
      }
    }
  }
  
  // Method to set the donor or acceptor dye spectra
  private void setDyeSpectra(String type) {
    if(selectedData == null) {
      return;
    }
    
    DyeSpectra ds = dyeData.getDyeSpectra(selectedData[0]);
    
    if(type.equals("donor")) {
      donorDye = ds;
      donorLB.setText(ds.toString());
      qyTF.setText("" + ds.getQY());
      tauTF.setText("" + ds.getLifetime());
      unitsCoB.setSelectedItem(ds.getLifetimeUnit());
      if(acceptorDye == null) {
        ecTF.setText("" + ds.getEC());
      }
    }
    else {
      acceptorDye = ds;
      ecTF.setText("" + ds.getEC());
      acceptorLB.setText(ds.toString());
    }
  }
  
  // function to set the data for a Strickler-Berg calculation data
  private void setSBData() {
    String data = (String)sbCoB.getSelectedItem();
    if(data.equals("Selected")) {
      sbDye = currentDye;
    }
    else if(data.equals("Donor")) {
      sbDye = donorDye;
    }
    else { // must be acceptor data
      sbDye = acceptorDye;
    }
    
    if(sbDye != null) {
      sbecTF.setText("" + sbDye.getEC());
      sbqyTF.setText("" + sbDye.getQY());
      
      float[][] xydata = sbDye.getAbsorption().getData();
      int min = Math.round(xydata[0][0]);
      int max = Math.round(xydata[xydata.length-1][0]);
      
      sbrangeTF.setText(min + "-" + max);
    }
  }
  
  // Method to set the variable data
  private void setVariableData() {
    if(wavelengths == null || distances == null) {
      return;
    }
    
    String axis = (String)varCoB.getSelectedItem();
    
    if(axis.equals("Distance")) {
      varLB.setText(" Wavelength @ ");
      
      valueCoB.removeAllItems();
      for(int i = 0; i < wavelengths.length; i++) {
        valueCoB.addItem("" + wavelengths[i]);
      }
    }
    else { // must be variable wavelenght
      varLB.setText(" Distance @ ");
      
      valueCoB.removeAllItems();
      for(int i = 0; i < distances.length; i++) {
        valueCoB.addItem("" + distances[i]);
      }
    }
    
    valueCoB.setSelectedIndex(0);
  }
  
  // Method to update the results that are displayed
  private void updateResults() {
    if(distances == null || wavelengths == null) {
      return;
    }
    
    // construct a new table model
    //"WL", "r", "E", "kt", "Fd", "Fa", "Ft", "Fd/Fa", "Tau_a"};
    NumberFormat nf = NumberFormat.getInstance();
    DecimalFormat df = (DecimalFormat) nf;
    df.setDecimalSeparatorAlwaysShown(true);
    
    // get the time units
    String unit = (String)unitsCoB.getSelectedItem();
    float mf = FRETViewUtil.getTimeUnitMF(unit);
    
    String axis = (String)varCoB.getSelectedItem();
    
    if(axis.equals("Distance")) {
      data = new String[distances.length][9];
      String WL = (String)valueCoB.getSelectedItem();
      int index = valueCoB.getSelectedIndex();
      
      for(int i = 0; i < distances.length; i++) {
        data[i][0] = WL;
        data[i][1] = "" + distances[i];
        
        df.applyPattern("0.###");
        data[i][2] = df.format(efficiency[i][1]);
        
        df.applyPattern("0.#E0");
        data[i][3] = df.format(transfer_rate[i][1]);
        
        df.applyPattern("0.###");
        float Fd = donor_intensity[index + 1][i + 1];
        data[i][4] = df.format(Fd);
        
        float Fa = acceptor_intensity[index + 1][i + 1];
        data[i][5] = df.format(Fa);
        
        float Ft = total_intensity[index + 1][i + 1];
        data[i][6] = df.format(Ft);
        
        df.applyPattern("0.##");
        float FaFd = Fa/Fd;
        data[i][7] = df.format(FaFd);
        
        float tau = lifetime[i][1];
        data[i][8] = FRETViewUtil.formatTau(tau);
      }
    }
    else { // must be variable wavelength
      data = new String[wavelengths.length][9];
      String distance = (String)valueCoB.getSelectedItem();
      int index = valueCoB.getSelectedIndex();
      
      for(int i = 0; i < wavelengths.length; i++) {
        data[i][0] = "" + wavelengths[i];
        data[i][1] = distance;
        
        df.applyPattern("0.###");
        data[i][2] = df.format(efficiency[index][1]);
        
        df.applyPattern("0.#E0");
        data[i][3] = df.format(transfer_rate[index][1]);
        
        df.applyPattern("0.###");
        float Fd = donor_intensity[i + 1][index + 1];
        data[i][4] = df.format(Fd);
        
        float Fa = acceptor_intensity[i + 1][index + 1];
        data[i][5] = df.format(Fa);
        
        float Ft = total_intensity[i + 1][index + 1];
        data[i][6] = df.format(Ft);
        
        df.applyPattern("0.##");
        float FaFd = Fa/Fd;
        data[i][7] = df.format(FaFd);
        
        float tau = lifetime[i][1];
        data[i][8] = FRETViewUtil.formatTau(tau);
      }
    }
    
    // add the new data to the table
    DefaultTableModel tableModel = new DefaultTableModel(data, colNames);
    results_table.setModel(tableModel);
  }
  
  // Method to calculate the FRETMap
  private void calculate() {
    if(donorDye == null || acceptorDye == null) {
      return;
    }
    
    // reset this two to null
    wavelengths = null;
    distances = null;
    
    float R0 = 0.0f;
    float ratio = 0.0f;
    float tau = 0.0f;
    
    // get the wavelength and distance range
    try {
      float wlmin = Float.parseFloat(wlminTF.getText());
      float wlmax = Float.parseFloat(wlmaxTF.getText());
      float wlinc = Float.parseFloat(wlincTF.getText());
      
      float dmin = Float.parseFloat(dminTF.getText());
      float dmax = Float.parseFloat(dmaxTF.getText());
      float dinc = Float.parseFloat(dincTF.getText());
      
      R0 =  Float.parseFloat(r0TF.getText());
      
      String rs = daTF.getText();
      if(rs.indexOf(":") != -1) {
        String[] sa = rs.split(":");
        ratio =  Float.parseFloat(sa[0])/Float.parseFloat(sa[1]);
      }
      else {
        ratio  = Float.parseFloat(rs);
      }
      
      // get the lifetime
      String unit = (String)unitsCoB.getSelectedItem();
      float mf = FRETViewUtil.getTimeUnitMF(unit);
      tau = Float.parseFloat(tauTF.getText())/mf;
      
      // check to make sure the increment are not zero
      if(wlinc <= 0 || dinc <= 0) {
        String error = "The wavelength and/or distance increment\nmust be greater than zero";
        showErrorDialog(error);
        return;
      }
      
      // check to that the and max wavelength at 
      if(wlmin > wlmax || dmin > dmax) {
        String error = "The wavelength and/or distance maximum\nmust be greater than minimum";
        showErrorDialog(error);
        return;
      }
      
      // now check to see we don't a single wavelenght or
      // distance wlmax = wlmin etc ...
      if(wlmin == wlmax) {
        wavelengths = new float[]{wlmin};
      }
      else {
        wavelengths = getDataArray(wlmin, wlmax, wlinc);
      }
      
      if(dmin == dmax) {
        distances = new float[]{dmin};
      }
      else {
        distances = getDataArray(dmin, dmax, dinc);
      }
    }
    catch(NumberFormatException nfe) {
      System.err.println("Numbers only please");
      return;
    }
    
    // calculate the efficiency array
    efficiency = FRETViewUtil.calculateEfficiency(distances, R0, ratio);
    
    // calculate the enrgy transfer rate
    transfer_rate = FRETViewUtil.calculateRate(efficiency, tau);
    
    // calculate the fluorescent intensity of the donor
    donor_intensity = FRETViewUtil.calculateDonorIntensity(donorDye, efficiency, wavelengths);
    
    // calculate the fluorescent intensity of the acceptor
    acceptor_intensity = FRETViewUtil.calculateAcceptorIntensity(donorDye, acceptorDye, efficiency, wavelengths);
    
    // calculate the total intensity.  This will also normalize the data
    total_intensity = FRETViewUtil.calculateTotalIntensity(donor_intensity, acceptor_intensity);
    
    // calculate the lifetime increase
    lifetime = FRETViewUtil.calculateAcceptorLifetime(efficiency, tau);
    
    // display the results
    varCoB.setSelectedIndex(0);
    valueCoB.setSelectedIndex(0);
    updateResults();
  }
  
  // Method to return an float array after provding a min, max, and increment
  private float[] getDataArray(float min, float max, float inc) {
    Vector vdata = new Vector(); 
    Float dp;
    
    do {
      dp = new Float(min);
      vdata.addElement(dp);
      min += inc;
    }
    while(min <= max);
    
    // now return the data array code
    float[] data = new float[vdata.size()];
    for(int i = 0; i < data.length; i++) {
      dp = (Float)vdata.elementAt(i);
      data[i] = dp.floatValue();
    }
    
    return data;
  }
  
  // Method to calculate the lifetime
  private void calculateLifetime() {
    if(sbDye != null) {
      try {
        float EC = Float.parseFloat(sbecTF.getText());
        float QY = Float.parseFloat(sbqyTF.getText());
        float n = Float.parseFloat(nTF.getText());
        
        float[] range = null;
        String rs = sbrangeTF.getText();
        if(rs.indexOf("-") != -1) {
          range = new float[2];
          String[] sa = rs.split("-");
          range[0] =  Float.parseFloat(sa[0]);
          range[1] =  Float.parseFloat(sa[1]);
        }
        
        float lifetime = FRETViewUtil.calculateLifetime(sbDye, EC, QY, n, range);
        
        // the the multiplicative factor for the current time unit
        String unit = (String)unitsCoB.getSelectedItem();
        float mf = FRETViewUtil.getTimeUnitMF(unit);
        
        // format the lifetime
        NumberFormat nf = NumberFormat.getInstance();
        DecimalFormat df = (DecimalFormat) nf;
        df.setDecimalSeparatorAlwaysShown(true);
        df.applyPattern("0.##");
        
        float f_lifetime = mf*lifetime;
        tauTF.setText(df.format(f_lifetime));
      }
      catch(NumberFormatException nfe) { }
    }
  }
  
  // function to calculate the forster distance R0
  private float calculateR0() {
    float R0 = 0.0f;
    if(donorDye != null && acceptorDye != null) {
      try {
        float EC = Float.parseFloat(ecTF.getText());
        float QY = Float.parseFloat(qyTF.getText());
        float n = Float.parseFloat(nTF.getText());
        float k = Float.parseFloat(kTF.getText());
        
        R0 = FRETViewUtil.calculateR0(donorDye, acceptorDye, EC, QY, n, k);
        
        NumberFormat nf = NumberFormat.getInstance();
        DecimalFormat df = (DecimalFormat) nf;
        df.setDecimalSeparatorAlwaysShown(true);
        df.applyPattern("0.#");
        
        r0TF.setText(df.format(R0));
        
        return R0;
      }
      catch(NumberFormatException nfe) { }
    }
    return R0;
  }
  
  // Method to import spectra files
  private void importDataFile() {
    File[] files = openDataFile();
    if(files !=null) {
      if(invCB.isSelected()) {
        new InvitrogenFileReader(this, files).start();
      }
      else {
        if(files.length%2 == 0) {
          new AbsEmsFileReader(this, files).start();
        }
        else {
          showErrorDialog("Importing of Abs/Ems files must be done in pairs ...");
        }
      }
    }
  }
  
  // Method to create a new donor acceptor list
  private void createNewDonorAcceptorList() {
    String[] meta  = new String[8];
    meta[0] = InstruView.getProperty("organization");
    meta[1] = InstruView.getProperty("laboratory");
    meta[2] = InstruView.getProperty("owner");
    meta[3] = InstruView.getProperty("email");
    meta[4] = "FRETView Database";
    meta[5] = "mm-dd-yyyy";
    meta[6] = "00";
    this.dyeData = new DonorAcceptorData("FRETView Data", meta);
    updateDisplay(false);
  }
  
  // Method to load donor acceptor list
  private void openDonorAcceptorList() {
    File[] files = openDataFile();
    if(files !=null) {
      openDonorAcceptorList(files[0]);
    }
  }
  
  // function to open 
  private void openDonorAcceptorList(File file) {
    if(file !=null && file.exists()) {
      DonorAcceptorData daData = bm.getDonorAcceptorData(file);
      if(daData != null) {
        dyeData = daData;
        dyeData.setFile(file);
      }
      else {
        System.err.println("Unable to open donor acceptor list in file " + file);
      }
      
      updateDisplay(false);
    }
  }
  
  // Method to set the daList
  public void setDonorAcceptorList(DonorAcceptorData daData) {
    if(daData != null) {
      dyeData = daData;
      updateDisplay(false);
    }
  }
  
  // Method to return the names of data files
  private File[] openDataFile() {
    File[] files = null;
    int returnVal = fc.showOpenDialog(this);
    
		if (returnVal == JFileChooser.APPROVE_OPTION) {
			files = fc.getSelectedFiles();
    }
    return files;
  }
  
  // Method to save the dye spectra list
  private void saveDonorAcceptorList() {
    File file = dyeData.getFile();
    if(file !=null) {
      bm.saveObjectToFile(dyeData, file);
      properties.setProperty("dbfile", file.toString());
      storeProperties();
    }
    else {
      saveDonorAcceptorListAs();
    }
  }
  
  // save the donor acceptor list as ...
  private void saveDonorAcceptorListAs() {
    int returnVal = fc.showSaveDialog(this);
    
    if (returnVal == JFileChooser.APPROVE_OPTION) {
      File file = fc.getSelectedFile();
      if(file != null) {
        // check to see if correct file extension is there.  if not add it
        String name = file.toString();
        if(name.toLowerCase().indexOf(FILE_EXT) == -1) {
          name += FILE_EXT;
          file = new File(name);
        }
        
        bm.saveObjectToFile(dyeData, file);
        dyeData.setFile(file);
        properties.setProperty("dbfile", file.toString());
        storeProperties();
      }
    }
  }
  
  // function to save the program properties such as spectral database file and so on
  public void storeProperties() {
    try {
      File file = new File(propertiesFileName);
      FileOutputStream output = new FileOutputStream(file);
      properties.store(output, "---FretView Properties File---");
    }
    catch(IOException ioe) {
      System.err.println("Error Saving Program Properties");
    }
  }
  
  // Method to load the system properties
  public void loadProperties() {
    File file = new File(propertiesFileName);
    if(file.exists()) {
      try {
        FileInputStream fis = new FileInputStream(file);
        properties.load(fis);
        fis.close();
      }
      catch(IOException e) {
        System.err.println("Unable to load properties file ...");
      }
    }
  }
  
  // Method to update info current dye info panel
  private void updateInfoPanel() {
    if(currentDye != null) {
      dnameTF.setText(currentDye.toString());
      decTF.setText("" + currentDye.getEC());
      dqyTF.setText("" + currentDye.getQY());
      dtauTF.setText("" + currentDye.getLifetime());
      dunitsCoB.setSelectedItem(currentDye.getLifetimeUnit());
      dnotesTF.setText(currentDye.getNotes());
    }
    else { // just celar the text fields
      dnameTF.setText("");
      decTF.setText("");
      dqyTF.setText("");
      dtauTF.setText("");
      dunitsCoB.setSelectedItem("picosecond");
      dnotesTF.setText("");
    }
  }
  
  // Method to update the current dye
  private void updateCurrentDyeInfo() {
    if(currentDye != null) {
      try {
        String name = dnameTF.getText().trim();
        float ec = Float.parseFloat(decTF.getText());
        float qy = Float.parseFloat(dqyTF.getText());
        float tau = Float.parseFloat(dtauTF.getText());
        String unit = (String)dunitsCoB.getSelectedItem();
        String notes =  dnotesTF.getText();
        
        currentDye.setEC(ec);
        currentDye.setQY(qy);
        currentDye.setLifetime(tau);
        currentDye.setLifetimeUnit(unit);
        currentDye.setNotes(notes);
        
        String old_name = currentDye.toString();
        if(!name.equals(old_name)) {
          currentDye.setName(name);
          updateDisplay(true);
          daList.setSelectedValue(name, true); // reselect this dye
        }
      }
      catch(NumberFormatException nfe) {
        return;
      }
    }
  }
  
  // Method to remove
  private void removeCurrentDye() {
     if(currentDye != null) {
       dyeData.remove(currentDye);
       currentDye = null;
       updateInfoPanel();
       updateDisplay(false);
     }
  }
  
  // Method to update the GUI components after any anchanges have been made to 
  // the donor acceptor list
  public void updateDisplay(boolean sort) {
    if(sort) {
      dyeData.sort();
    }
    
    String[] dyeNames = getDonorAcceptorNames();
    
    // set the current dye to null
    currentDye = null;
    selectedData = null;
    updateInfoPanel();
    
    // update the names
    daList.clearSelection();
    daList.setListData(dyeNames);
    
    // if the db info panel is not null update it
    if(infoDialog != null) {
      infoDialog.updateDisplay();
    }
  }
  
  // Method to read in the donor/acceptor database and return there names
  private String[] getDonorAcceptorNames() {
    String[] dyeNames = null;
    
    if(dyeData.size() != 0) {
      dyeNames = new String[dyeData.size()];
      Vector v = dyeData.getDyeData();
      
      int i = 0;
      for(Enumeration e = v.elements() ; e.hasMoreElements();) {
        DyeSpectra ds = (DyeSpectra)e.nextElement();
        //String name = "[" + (i + 1) + " ] " + ds.toString();
        String name = ds.toString();
        dyeNames[i] = name;
        i++;
      }
    }
    else { // test code
      dyeNames = new String[1]; // test code
      
      for(int i = 0; i < dyeNames.length; i++) {
        dyeNames[i] = "No Donor/Acceptor Data Loaded";
      }
    }
    
    return dyeNames;
  }
  
  // Method to add spectra data to instruview
  private void addToInstruView() {
    if(selectedData != null && dyeData.size() > 0) {
      instruView.loadSpectraData("absorption", getSpectraData("absorption"));
      instruView.loadSpectraData("emission", getSpectraData("emission"));
    }
  }
  
  // Method to get spectra data from the instruview
  private void getFromInstruView() {
    SpectraData[] absa = instruView.absorptionPanel.getSelectedSpectraData();
    SpectraData[] emsa = instruView.emissionPanel.getSelectedSpectraData();
    
    if(absa == null || emsa == null) {
      grabTF.setText("Error ...");
      String message = "Either no absorption or emission data selected ...";
      print(message);
      return;
    }
    
    if(absa.length != emsa.length) {
      grabTF.setText("Error ...");
      String message = "Absorption and emission data must be selected in pairs ...";
      print(message);
      return;
    }
    
    // now load the new dye spectra data
    DyeSpectra[] dsa = FRETViewUtil.getDyeSpectra(absa, emsa);
    for(int i = 0; i < dsa.length; i++) {
      dyeData.addDyeSpectra(dsa[i]);
    }
    
    // update the grabTF
    grabTF.setText(dsa.length + " Dye Spectra Added ...");
    
    // update the daLIST now
    updateDisplay(true);
  }
  
  // Method to return the absorption or emission spectra data array
  private SpectraData[] getSpectraData(String type) {
    SpectraData[] sda = null;
    if(selectedData != null) {
      sda = new SpectraData[selectedData.length];
      for(int i = 0; i < selectedData.length; i++) {
        DyeSpectra ds = dyeData.getDyeSpectra(selectedData[i]);
        if(type.equals("absorption")) {
          sda[i] = ds.getAbsorption();
        }
        else { // must be emmission data
          sda[i] = ds.getEmission();
        }
      }
    }
    
    return sda;
  }
  
  // Method to copy the text from the console
  private void copyResults() {
    if(data == null) {
      return;
    }
    
    Clipboard cb =Toolkit.getDefaultToolkit().getSystemClipboard();
    String s = console.getText();
    
    // define a string buffer just in case the data needs to be copied
    StringBuffer buffer = new StringBuffer();
    
    // append the column names
    for(int i = 0; i < colNames.length; i++) {
      if(i + 1 != colNames.length) {
        buffer.append(colNames[i]).append("\t");
      }
      else {
        buffer.append(colNames[i]).append("\n");
      }
    }
    
    // now append the data
    for(int i = 0; i < data.length; i++) {
      for(int j = 0; j < data[0].length; j++) {
        if(j + 1 != data[0].length) {
          buffer.append(data[i][j]).append("\t");
        }
        else {
          buffer.append(data[i][j]).append("\n");
        }
      }
    }
    
    StringSelection contents = new StringSelection(buffer.toString());
    cb.setContents(contents, null);
  }
  
  // Method to copy the text from the console
  private void copyConsoleText() {
    Clipboard cb =Toolkit.getDefaultToolkit().getSystemClipboard();
    String s = console.getText();
    StringSelection contents = new StringSelection(s);
    cb.setContents(contents, null);
  }
  
  // Method to plot the dye spectra
  private void plotDyeSpectra() {
    if(donorDye == null && acceptorDye == null) {
      return;
    }
    
    boolean[] spectra = new boolean[4];
    spectra[0] = d_absCB.isSelected();
    spectra[1] = d_emsCB.isSelected();
    spectra[2] = a_absCB.isSelected();
    spectra[3] = a_emsCB.isSelected();
    
    FRETViewPlotDialog plotDialog = new FRETViewPlotDialog(donorDye, acceptorDye, spectra);
    plotDialog.pack();
    plotDialog.setVisible(true);
  }
  
  // Method to display the plot internal frame
  private void showPlotOptions() {
    if(plotPropertiesDialog == null) {
      plotPropertiesDialog = new PlotPropertiesDialog(this);
      plotPropertiesDialog.pack();
    }
    plotPropertiesDialog.setVisible(true);
  }
  
  // Method to show the plotSpectradialog
  private void showPlotSpectraDialog() {
    if(plotSpectraDialog == null) {
      plotSpectraDialog = new PlotSpectraDialog(this);
      plotSpectraDialog.pack();
    }
    plotSpectraDialog.setVisible(true);
  }
  
  // Method to show plots of the simulated spectra
  private void showSimulatedSpectra() {
    if(distances == null || wavelengths == null) {
      return;
    }
    
    String axis = (String)varCoB.getSelectedItem();
    int index = valueCoB.getSelectedIndex() + 1;
     
    FRETViewPlotDialog plotDialog = new FRETViewPlotDialog(donorDye, acceptorDye, donor_intensity, 
    acceptor_intensity, index, axis);
    plotDialog.pack();
    plotDialog.setVisible(true);
  }
  
   // Method to show plots of the simulated spectra
  private void showSimulatedLifetime() {
    if(distances == null || wavelengths == null) {
      return;
    }
    
    String axis = (String)varCoB.getSelectedItem();
    if(!axis.equals("Distance")) { // only display simulation for varaible distance
      return;
    }
    
    // check to make sure tht we only display window
    int index = valueCoB.getSelectedIndex() + 1;
     
    LifetimeSimDialog lifetimeSimDialog = new LifetimeSimDialog(donorDye,
    acceptorDye, efficiency, transfer_rate, lifetime);
    lifetimeSimDialog.pack();
    lifetimeSimDialog.setVisible(true);
  }
  
  // Method to display the plot internal frame
  private void showDownloadDialog() {
    if(downloadDialog == null) {
      downloadDialog = new DownloadDialog(this);
      downloadDialog.pack();
    }
    downloadDialog.setVisible(true);
  }
  
  // Method to display the DBInfo dialog
  private void showDBInfoDialog() {
    if(infoDialog == null) {
      infoDialog = new DBInfoDialog(this);
      infoDialog.pack();
    }
    else {
      infoDialog.updateDisplay();
    }
    
    infoDialog.setVisible(true);
  }
  
  // function to show the datadialog
  private void showDataViewDialog(String type) {
    if(currentDye != null) {
      SpectraData sd;
      String title;
      
      if(type.equals("absorption")) {
        sd = currentDye.getAbsorption();
        title = "Absorption Data";
      }
      else {
        sd = currentDye.getEmission();
        title = "Emission Data";
      }
      
      DataViewDialog dataViewDialog = new DataViewDialog(title, sd);
      dataViewDialog.pack();
      dataViewDialog.setVisible(true);
    }
  }
  
  // Function to show the error dialog
  private void showErrorDialog(String error) {
    JOptionPane.showMessageDialog(this, error, "Error", JOptionPane.ERROR_MESSAGE);
  }
  
  // function to clear the selected data
  private void clearData() {
    // set the donor and acceptor to null
    currentDye = null;
    donorDye = null;
    acceptorDye = null;
    
    donorLB.setText(" No Donor Set...");
    acceptorLB.setText(" No Acceptor Set...");
    
    // clear the selection in daList
    selectedData = null;
    updateInfoPanel();
    daList.clearSelection();
    
    // clear the results table *** code ***
    wavelengths = null;
    distances = null;
  }
  
  // Method to set any spectra data
  public void setSpectraData(SpectraData[] sda) { }
  
  // Method to add a single spectra data. not used
  public void addSpectraData(SpectraData sd) {  }
  
  // Method to set any spectra data. not used
  public void addSpectraData(SpectraData[] sda) {  }
  
  // Method to load an sdl file. not used
  public void loadSDL(ExperimentData experimentData, File file) {  }
  
  // Method to load an sdl file. not used
  public void loadSDL(ExperimentData experimentData) {  }
  
  // Method to print any messages
  public void print(String message) {
    //System.out.println(message);
    console.append(message + "\n");
  }
  
  // the static class for putting it self into the class
  static class FRETViewFactory extends PluginFactory {
    public InstruViewPlugin create(InstruView instruView) {
      return (new FRETViewPlugin(instruView));
    }
    
    // get the experiment type
    public String getExperimentType() {
      return "fretview";
    }
    
    // get information about this plugin
    public String[] getPluginInformation() {
      String[] information = {"Author : Nathan Stevens",
                                              "Version : " + VERSION,
                                              "",
                                              "A simple plugin for for calculating energy transfer parameters"};
      
      return information;
    }
  }// -- end inner static class PlotterFactory
  
  // add this factory to the InstruviewPluginLoader factory hashtable
  static {
    InstruViewPluginLoader.pluginFactories.put("FRETView", new FRETViewFactory());
  }
} // --end class FRETViewPlugin
