
/**
 * DataSnoopDialog.java
 * User interface for searhing through save data in the sdl format
 *
 * Created: May 22, 2004
 *
 * @author Nathan Stevens
 * @version 0.3 3/9/06
 */
 
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.JTree;
import javax.swing.tree.*;
import java.util.*;
import java.io.File;

public class DataSnoopDialog extends JFrame implements ActionListener,
  ItemListener {
  private InstruView instruView = null;
  private JFileChooser fc = new JFileChooser(); // The file chooser object
  private JSplitPane splitPane = null;
  private JPanel searchPanel = null;
  private JPanel resultsPanel = null;
  private JTextField searchInTF = null;
  private JTextField searchTF = null;
  private JRadioButton nameRB = null;
  private JRadioButton notesRB = null;
  private JRadioButton dateRB = null;
  private JRadioButton pageRB = null;
  private JCheckBox anyCB = null;
  private JCheckBox absCB = null;
  private JCheckBox emCB = null;
  private JCheckBox rmCB = null;
  private JCheckBox srCB = null;
  private JCheckBox ppCB = null;
  private JCheckBox ooCB = null;
  private JCheckBox xyCB = null;
  private JTextField xydataTypeTF = null;
  private JTextArea infoArea = null;
  private DefaultMutableTreeNode rootNode = null;
  private DefaultTreeModel treeModel = null;
  private JTree dataTree = null;
  private DataSnoop dataSnoop = null;
  private DataSnoopSearchList[] dataSnoopSearchList = null;
  private int sdlcount = 0;
  private int sdcount = 0;
  private int abcount = 0;
  private int emcount = 0;
  private int rmcount = 0;
  private int srcount = 0;
  private int oocount = 0;
  private int ppcount = 0;
  private int xycount = 0;
  private boolean[] etypes = new boolean[8];
  private DataSnoopSearchList currentList = null;
  private DataSnoopSearchObject currentSearchObject = null;
  private int currentType = 0;
  
  public DataSnoopDialog(InstruView instruView) {
    super("Data Snoop");
    
    this.instruView = instruView;
    
    // close the window
		addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent we) {
				setVisible(false);
		  }
		});
    
    // Some gui components
		JButton button;
		JLabel label;
    JPanel panel;
    
    // add the search panel
    searchPanel = new JPanel();
    searchPanel.setLayout(new BorderLayout());
    
    JPanel sp1 = new JPanel();
    sp1.setLayout(new BoxLayout(sp1, BoxLayout.Y_AXIS));
    
    panel = new JPanel();
    panel.setLayout(new FlowLayout(FlowLayout.LEFT));
    
    button = new JButton("Search In ");
		button.addActionListener(this);
    button.setMargin(new Insets(0,1,0,1));
		button.setActionCommand("browse");
    panel.add(button);
    
    searchInTF = new JTextField(instruView.dataDirectoryName, 15);
    searchInTF.setActionCommand("searchin");
    searchInTF.addActionListener(this);
    panel.add(searchInTF);
    
     sp1.add(panel);
    
    panel = new JPanel();
    panel.setLayout(new FlowLayout(FlowLayout.LEFT));
    
    label = new JLabel("Search For ");
    panel.add(label);
    
    searchTF = new JTextField("", 15);
    searchTF.setActionCommand("search");
    searchTF.addActionListener(this);
    panel.add(searchTF);
    
    sp1.add(panel);
    
    panel = new JPanel();
    panel.setLayout(new GridLayout(1, 3));
    
    ButtonGroup group = new ButtonGroup();
    
    nameRB = new JRadioButton("Name");
    group.add(nameRB);
    panel.add(nameRB);
    
    notesRB = new JRadioButton("Notes");
    notesRB.setSelected(true);
    group.add(notesRB);
    panel.add(notesRB);
    
    dateRB = new JRadioButton("Date");
    group.add(dateRB);
    panel.add(dateRB);
    
    pageRB = new JRadioButton("Page");
    group.add(pageRB);
    panel.add(pageRB);
    
    sp1.add(panel);
    
    panel = new JPanel();
    panel.setLayout(new GridLayout(4, 2));
    
    anyCB = new JCheckBox("Any");
    anyCB.setSelected(true);
    anyCB.addItemListener(this);
    panel.add(anyCB);
    
    absCB = new JCheckBox("Absorption");
    absCB.addItemListener(this);
    panel.add(absCB);
    
    emCB = new JCheckBox("Emission");
    emCB.addItemListener(this);
    panel.add(emCB);
    
    rmCB = new JCheckBox("Raman");
    rmCB.addItemListener(this);
    panel.add(rmCB);
    
    srCB = new JCheckBox("Streak");
    srCB.addItemListener(this);
    panel.add(srCB);
    
    ppCB = new JCheckBox("Pump-Probe");
    ppCB.addItemListener(this);
    panel.add(ppCB);
    
    ooCB = new JCheckBox("OO Data");
    ooCB.addItemListener(this);
    panel.add(ooCB);
    
    xyCB = new JCheckBox("XY Data");
    xyCB.addItemListener(this);
    panel.add(xyCB);
    
    sp1.add(panel);
    
    // add the panel that holds the XY Data Type check box
    panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
    //panel.setAlignmentX(Component.LEFT_ALIGNMENT);
    
    label = new JLabel("XY Data Type : ");
    panel.add(label);
    
    xydataTypeTF = new JTextField("all");
    panel.add(xydataTypeTF);
    
    sp1.add(panel);
    
    searchPanel.add(sp1, "North");
    
    infoArea = new JTextArea();
    JScrollPane infoScrollPane = new JScrollPane(infoArea);
    
    searchPanel.add(infoScrollPane);
    
    // add the results panel now
    resultsPanel = new JPanel();
    resultsPanel.setLayout(new BorderLayout());
    
    JPanel rp1 = new JPanel();
    rp1.setLayout(new BoxLayout(rp1, BoxLayout.X_AXIS));
    
    button = new JButton("Re-Scan");
    button.setActionCommand("rescan");
    button.addActionListener(this);
    rp1.add(button);
    
    button = new JButton("Load");
    button.setActionCommand("load");
    button.addActionListener(this);
    rp1.add(button);
    
    button = new JButton("Plot");
    button.setActionCommand("plot");
    button.addActionListener(this);
    rp1.add(button);
    
    rp1.add(Box.createHorizontalGlue());
    
    button = new JButton("Clear");
    button.setActionCommand("clear");
    button.addActionListener(this);
    rp1.add(button);
    
    resultsPanel.add(rp1, "North");
    
    // add the data tree now
    displayDataTree();
    
    // add the panels to the split panes
    splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, searchPanel, resultsPanel);
    splitPane.setOneTouchExpandable(true);
    splitPane.setDividerLocation(250);
    
    //Provide a preferred size for the split pane
    splitPane.setPreferredSize(new Dimension(550, 400));
    
    getContentPane().add(splitPane);
    
    // set the file chooser so that it only accepts directories and show sdl files
    ExperimentDataFileFilter sdlFileFilter = new ExperimentDataFileFilter("sdl");
    fc.addChoosableFileFilter(sdlFileFilter);
    fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
    
    
    // initialze some stuff
    File dataDirectory = new File(instruView.dataDirectoryName);
    dataSnoop = new DataSnoop(dataDirectory);
  }
  
  // Method to display the data tree
  private void displayDataTree() {
    // Create the nodes.
    rootNode = new DefaultMutableTreeNode("My Data");
    treeModel = new DefaultTreeModel(rootNode);
    
    // Create a tree that allows one selection at a time.
    dataTree = new JTree(treeModel);
    dataTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
    
    // Listen for when the selection changes.
    dataTree.addTreeSelectionListener(new TreeSelectionListener() {
      public void valueChanged(TreeSelectionEvent e) {
        DefaultMutableTreeNode node = (DefaultMutableTreeNode)dataTree.getLastSelectedPathComponent();
        
        if (node == null) return;
        
        Object nodeInfo = node.getUserObject();
        DataSnoopSearchList searchList;
        DataSnoopSearchObject searchObject;
        
        if (node.isLeaf()) {
          searchObject = (DataSnoopSearchObject)nodeInfo;
          String datainfo = "Data Name : " + searchObject.toString() + "\n" +
                                        "Data Type : " + searchObject.getType() + "\n" +
                                        "Data Date : " + searchObject.getDate() + "\n" +
                                        "Data Notes : " + searchObject.getNotes();
          
          infoArea.setText(datainfo);
          
          // set the current search object
          currentSearchObject = searchObject;
          currentType = 0;
        }
        else { 
          if(nodeInfo.toString().equals("My Data")) {
            printDataStats();
          }
          else {
            searchList = (DataSnoopSearchList)nodeInfo;
            String sdlinfo = "SDL File : " + searchList.getFile().toString() + "\n" +
                                        "SDL Type : " + searchList.getType() + "\n" +
                                        "SDL Date : " + searchList.getDate() + "\n" +
                                        "SDL Notes : " + searchList.getNotes();
            
            infoArea.setText(sdlinfo);
            
            // set the currentList
            currentList = searchList;
            currentType = 1;
          }
        }
      }
    });
    
    //  Create the scroll pane and add the tree to it.
    JScrollPane treeView = new JScrollPane(dataTree);
    
    resultsPanel.add(treeView, "Center");
  }
  
  //  Remove all nodes except the root node. 
  private void clear() {
    rootNode.removeAllChildren();
    treeModel.reload();
    
    // clear the text area
    infoArea.setText("");
  }
  
  // Method to handel action events
  public void actionPerformed(ActionEvent ae) {
    String cmd = ae.getActionCommand();
    
    if(cmd.equals("browse")) {
			browseDataFileDirectory();
		}
    else if(cmd.equals("searchin")) {
			setDataFileDirectory();
		}
    else if(cmd.equals("search")) {
			searchDataFiles();
		}
    else if(cmd.equals("load")) {
      loadSelectedData();
    }
    else if(cmd.equals("plot")) {
      showPlotDialog();
    }
    else if(cmd.equals("rescan")) {
      scanDataDirectory();
    }
    else if(cmd.equals("clear")) {
      clear();
    }
    else {
      System.err.println("Action Command not handeled in class DataSnoopDialog...");
      System.err.println(cmd);
    }
  }
  
  // Method to listen to item state changes
  public void itemStateChanged(ItemEvent e) {
    Object source = e.getItemSelectable();
    if(source == anyCB) {
      if (e.getStateChange() == ItemEvent.SELECTED) {
        etypes[0] = true;
      }
      else {
         etypes[0] = false;
      }
    }
    else if(source == absCB) {
      if (e.getStateChange() == ItemEvent.SELECTED) {
        etypes[1] = true;
      }
      else {
         etypes[1] = false;
      }
    }
    else if(source == emCB) {
      if (e.getStateChange() == ItemEvent.SELECTED) {
        etypes[2] = true;
      }
      else {
         etypes[2] = false;
      }
    }
    else if(source == rmCB) {
      if (e.getStateChange() == ItemEvent.SELECTED) {
        etypes[3] = true;
      }
      else {
         etypes[3] = false;
      }
    }
    else if(source == srCB) {
      if (e.getStateChange() == ItemEvent.SELECTED) {
        etypes[4] = true;
      }
      else {
         etypes[4] = false;
      }
    }
    else if(source == ppCB) {
      if (e.getStateChange() == ItemEvent.SELECTED) {
        etypes[5] = true;
      }
      else {
         etypes[5] = false;
      }
    }
    else if(source == ooCB) {
      if (e.getStateChange() == ItemEvent.SELECTED) {
        etypes[6] = true;
      }
      else {
         etypes[6] = false;
      }
    }
    else if(source == xyCB) {
      if (e.getStateChange() == ItemEvent.SELECTED) {
        etypes[7] = true;
      }
      else {
         etypes[7] = false;
      }
    }
  }
  
  // Method to browse the data file directory
  private void browseDataFileDirectory() {
    int returnVal = fc.showOpenDialog(this);
    
    if (returnVal == JFileChooser.APPROVE_OPTION) {
      File dir = fc.getSelectedFile();
      searchInTF.setText(dir.toString());
      dataSnoop.setDataDirectory(dir);
      dataSnoopSearchList =null;
      clear();
    }
  }
  
  // Method to set the data file directory from the comand line
  private void setDataFileDirectory() {
    String searchIn = searchInTF.getText();
    
    if(searchIn != null) {
      File dir = new File(searchIn);
      if(dir.isDirectory()) {
        dataSnoop.setDataDirectory(dir);
        dataSnoopSearchList =null;
        clear();
      }
      else {
        searchInTF.setText(searchIn + " \"Not A Valid Directory\"");
      }
    }
  }
  
  // Method to search for data files
  private void searchDataFiles() {
    String searchfor = searchTF.getText();
    
    if(searchfor.length() < 1) {
      clear();
      showAllData();
      printDataStats();
    }
    else if(searchfor.equalsIgnoreCase("all")) {
      dataSnoopSearchList = dataSnoop.searchForAll(etypes);
      displaySearchResults();
      printDataStats();
    }
    else {
      String searchby = "";
      
      if(nameRB.isSelected()) {
        searchby = "name";
      }
      else if(notesRB.isSelected()) {
        searchby = "note";
      }
      else if(dateRB.isSelected()) {
        searchby = "date";
      }
      else {
        searchby = "page";
      }
      
      dataSnoopSearchList = dataSnoop.searchThroughList(searchby, searchfor, etypes);
      displaySearchResults();
      printDataStats();
    }
  }
  
  // Method to load a selected data
  private void loadSelectedData() {
    if(currentType == 0 && currentSearchObject != null) {
      instruView.addSpectraDataToFolder(currentSearchObject.getSDLFile(),
                                                                     currentSearchObject.getIndex());
    }
    else if (currentType == 1 && currentList != null){
      instruView.loadSDL(currentList.getFile());
    }
  }
  
  // Method to plot a spectra data object
  private void showPlotDialog() {
    if(currentType == 0 && currentSearchObject != null) {
      File file = currentSearchObject.getSDLFile();
      if(file != null && file.exists()) {
        Object object = BinaryFileManager.getObjectFromFile(file);
        ExperimentData edata = (ExperimentData)object;
        
        SpectraData[] sda = new SpectraData[1];
        sda[0] = edata.getData(currentSearchObject.getIndex());
        
        instruView.showPlotDialog(currentSearchObject.getType(), sda);
      }
    }
  }
  
  // Method to load a selected data
  private void scanDataDirectory() {
    dataSnoopSearchList = dataSnoop.getDataSearchList();
  }
  
  // Method to display the search results
  private void displaySearchResults() {
    // clear previous results
    clear();
    
    // now add nodes to the tree now
    DataSnoopSearchObject searchObject;
    DefaultMutableTreeNode sdlfile = null;
    DefaultMutableTreeNode sd = null;
    sdlcount = 0;
    sdcount = 0;
    resetExperimentCount();
    
    for(int i = 0; i < dataSnoopSearchList.length; i++) {
      if(dataSnoopSearchList[i].isShown()) {
        sdlfile = new DefaultMutableTreeNode(dataSnoopSearchList[i]);
        rootNode.add(sdlfile);
        sdlcount++;
        for (Enumeration e = dataSnoopSearchList[i].elements(); e.hasMoreElements(); ) {
          searchObject = (DataSnoopSearchObject)e.nextElement();
          if(searchObject.isShown()) {
            sd = new DefaultMutableTreeNode(searchObject);
            sdlfile.add(sd);
            sdcount++;
            if(searchObject.getType().equals("pump-probe")) { // count only one pump-probe spectra data
              ppcount++;
              break;
            }
            else {
              countExperimentType(searchObject.getType());
            }
          }
        }
      }
    }
    treeModel.reload();
  }
  
  // Method to show all the data
  private void showAllData() {
    // get the search list if its null
    if(dataSnoopSearchList ==null) {
      scanDataDirectory();
    }
    
    // now add nodes to the tree now
    DataSnoopSearchObject searchObject;
    DefaultMutableTreeNode sdlfile = null;
    DefaultMutableTreeNode sd = null;
    sdlcount = dataSnoopSearchList.length;
    sdcount = 0;
    resetExperimentCount();
    
    for(int i = 0; i < dataSnoopSearchList.length; i++) {
      sdlfile = new DefaultMutableTreeNode(dataSnoopSearchList[i]);
      rootNode.add(sdlfile);
      
      for (Enumeration e = dataSnoopSearchList[i].elements(); e.hasMoreElements(); ) {
        searchObject = (DataSnoopSearchObject)e.nextElement();
        sd = new DefaultMutableTreeNode(searchObject);
        sdlfile.add(sd);
        sdcount++;
        
        if(searchObject.getType().equals("pump-probe")) { // count only one pump-probe spectra data
          ppcount++;
          break;
        }
        else {
          countExperimentType(searchObject.getType());
        }
      }
    }
    
    treeModel.reload();
  }
  
  // Method to update the type of experiment read in
  private void countExperimentType(String exptype) {
    if(exptype.equals("absorption")) {
      abcount++;
    }
    else if(exptype.equals("emission")) {
      emcount++;
    }
    else if(exptype.equals("raman")) {
      rmcount++;
    }
    else if(exptype.equals("streak")) {
      srcount++;
    }
    else if(exptype.equals("pump-probe")) {
      ppcount++;
    }
    else if(exptype.equals("oodata")) {
      oocount++;
    }
    else if(exptype.equals("xydata")) {
      xycount++;
    }
    else {
      System.err.println("Unkown experiment type " + exptype + " in DataSnoopDialog");
    }
  }
  
  // Method to reset the experiment count
  private void resetExperimentCount() {
    abcount = 0;
    emcount = 0;
    rmcount = 0;
    srcount = 0;
    ppcount = 0;
    oocount = 0;
    xycount = 0;
  }
  // Method to print the data stats
  private void printDataStats() {
    String stats = "There are " + sdlcount + " Spectra Data List (SDL) files.\n" +
                            "There are " + sdcount + " Data Files.\n" +
                            "Absorption Data : " + abcount + "\n" +
                            "Emission Data : " + emcount + "\n" +
                            "Raman Data : " + rmcount + "\n" +
                            "Streak Camera Data : " + srcount + "\n" +
                            "Pump-Probe Data : " + ppcount + "\n" +
                            "OO Data : " + oocount + "\n" +
                            "XY Data : " + xycount + "\n";
                            
    infoArea.setText(stats);
  }
} //--end class DataSnoopDialog
