
/**
 * TransformDialog.java
 * Used to generate do simple data transform of collected data
 *
 * Created: Jan 4, 2004
 *
 * @author Nathan Stevens
 * @version 0.5 6/13/07
 */
 
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import java.io.*;

public class TransformDialog extends JFrame implements ActionListener, TransformViewer {
  private InstruView instruView = null;
  private ExperimentPanel epanel = null;
  private JComboBox opCB = null;
  private JComboBox axisCB = null; // used to specify the axis on which the arithmatic operation should be perfomed on
  private JComboBox sopCB = null;
  private JComboBox aopCB = null; // used for counts and to calculate area
  private JTextField TFn0 = null; // used to normalize the spectra
  private JTextField TFn1 = null; // used to normalize the spectra
  private JTextField TF1 = null;
  private JTextField TF2 = null;
  private JTextField TF3 = null;
  private JTextField TF4 = null;
  private JTextField TF5 = null;
  private JTextField TF6 = null;
  private JTextField trimTF1 = null; // minimum x value to keep when trimining data
  private JTextField trimTF2 = null; // maximum x value to keep when trimining data
  private JTextField areaTF1 = null; // minimum x value to keep when summing counts
  private JTextField areaTF2 = null; // maximum x value to keep when summing counts
  private JTextField areaTF3 = null; // allows defining the X range.
  private JCheckBox CB1 = null;
  private JLabel status = null;
  private JLabel smstatus = null;
  private SpectraData[] sdata = null;
  private SpectraData[] smbdata = null;
  private SpectraData bsdata = null;
  private String tftype = "arithmetic";
  private String op = "+";
  private String sop = "-";
  private float fconstant = 0;
  
  //private ExperimentData ICFdata = null; // hold the any instrument correction file data
  private SpectraData[] ICFdata = null;  // holds the any instrument correction file data
  
  public TransformDialog(InstruView instruView) {
    super("Data Transform");
    this.instruView = instruView;
    
    // load any instrument correction files
    loadICFData();
    
    //setLayout(new GridLayout(1, 4));
    getContentPane().setLayout(new BorderLayout());
    
    // some gui components
    JPanel panel, centerPanel, runPanel;
    JLabel label;
    JButton button;
    JRadioButton rbutton;
    
    /**Add the center panel now**/
    centerPanel = new JPanel();
    centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.Y_AXIS));
    
    // set the border
    Border border = BorderFactory.createRaisedBevelBorder();
    centerPanel.setBorder(border);
    
    // Add row 1
    panel = new JPanel();
    panel.setLayout(new FlowLayout(FlowLayout.LEFT));
    
    ButtonGroup group = new ButtonGroup();
    
    rbutton = new JRadioButton("Arithmetic on");
		rbutton.setSelected(true);
    rbutton.addActionListener(this);
		rbutton.setActionCommand("arithmetic");
    group.add(rbutton);
    panel.add(rbutton);
    
    panel.add(Box.createRigidArea(new Dimension(2,0)));
    
    String[] axisString = { "Y", "X"};
    axisCB = new JComboBox(axisString);
    axisCB.setSelectedIndex(0);
    panel.add(axisCB);
    
    panel.add(Box.createRigidArea(new Dimension(2,0)));
    
    label = new JLabel("Operation ");
    panel.add(label);
    
    String[] opString = { "+", "-", "/", "*", "log", "exp"};
    opCB = new JComboBox(opString);
    opCB.setSelectedIndex(0);
    panel.add(opCB);
    
    panel.add(Box.createRigidArea(new Dimension(10,0)));
    
    label = new JLabel("Constant ");
    panel.add(label);
    
    TF1 =  new JTextField("0", 5);
    panel.add(TF1);
    
    centerPanel.add(panel);
    
    // Add row 2
    panel = new JPanel();
    panel.setLayout(new FlowLayout(FlowLayout.LEFT));
    
    rbutton = new JRadioButton("Normalize to ");
    rbutton.addActionListener(this);
		rbutton.setActionCommand("normalize0");
    group.add(rbutton);
    panel.add(rbutton);
    
    TFn0 = new JTextField("0", 4);
    TFn0.setEditable(false);
    panel.add(TFn0);
    
    panel.add(Box.createRigidArea(new Dimension(5,0)));
    
    label = new JLabel("Wavelength ");
    panel.add(label);
    
    TF2 =  new JTextField("635", 5);
    panel.add(TF2);
    
    label = new JLabel(" nm/cm-1");
    panel.add(label);
    
    centerPanel.add(panel);
    
    // Add row 3
    panel = new JPanel();
    panel.setLayout(new FlowLayout(FlowLayout.LEFT));
    
    rbutton = new JRadioButton("Normalize to ");
		rbutton.setSelected(true);
    rbutton.addActionListener(this);
		rbutton.setActionCommand("normalize1");
    group.add(rbutton);
    panel.add(rbutton);
    
    TFn1 = new JTextField("1", 4);
    panel.add(TFn1);
    
    panel.add(Box.createRigidArea(new Dimension(5,0)));
    
    label = new JLabel("Wavelength ");
    panel.add(label);
    
    TF3 =  new JTextField("000", 5);
    panel.add(TF3);
    
    label = new JLabel(" nm/cm-1");
    panel.add(label);
    
    centerPanel.add(panel);
    
    // Add row 4. The spectra math
    panel = new JPanel();
    panel.setLayout(new FlowLayout(FlowLayout.LEFT));
    
    rbutton = new JRadioButton("Spectra Math");
		rbutton.setSelected(true);
    rbutton.addActionListener(this);
		rbutton.setActionCommand("spectramath");
    group.add(rbutton);
    panel.add(rbutton);
    
    panel.add(Box.createRigidArea(new Dimension(32,0)));
    
    label = new JLabel("Operation ");
    panel.add(label);
    
    sopCB = new JComboBox(getSpectraOperations());
    sopCB.setSelectedIndex(0);
    panel.add(sopCB);
    
    panel.add(Box.createRigidArea(new Dimension(10,0)));
    
    label = new JLabel("Status : ");
    panel.add(label);
    
    smstatus = new JLabel("Not Ready");
    smstatus.setForeground(Color.blue);
    panel.add(smstatus);
    
    centerPanel.add(panel);
    
    // Add row 5 now this allows data to be trimmed
    panel = new JPanel();
    panel.setLayout(new FlowLayout(FlowLayout.LEFT));
    
    rbutton = new JRadioButton("Data Trim");
    rbutton.addActionListener(this);
		rbutton.setActionCommand("datatrim");
    group.add(rbutton);
    panel.add(rbutton);
    
    panel.add(Box.createRigidArea(new Dimension(2,0)));
    
    label = new JLabel("Keep Data From ");
    panel.add(label);
    
    trimTF1 =  new JTextField("min", 6);
    panel.add(trimTF1);
    
    panel.add(Box.createRigidArea(new Dimension(2,0)));
    
    label = new JLabel("to");
    panel.add(label);
    
    panel.add(Box.createRigidArea(new Dimension(2,0)));
    
    trimTF2 =  new JTextField("max", 6);
    panel.add(trimTF2);
    
    label = new JLabel("X units");
    panel.add(label);
    
    centerPanel.add(panel);
    
    /* Add row 5 now
    panel = new JPanel();
    panel.setLayout(new FlowLayout(FlowLayout.LEFT));
    
    rbutton = new JRadioButton("Streak Clean");
    rbutton.addActionListener(this);
		rbutton.setActionCommand("streakclean");
    group.add(rbutton);
    panel.add(rbutton);
    
    panel.add(Box.createRigidArea(new Dimension(2,0)));
    
    label = new JLabel("Min. Diff. ");
    panel.add(label);
    
    TF4 =  new JTextField("200", 4);
    panel.add(TF4);
    
    panel.add(Box.createRigidArea(new Dimension(2,0)));
    
    label = new JLabel("Noise Level ");
    panel.add(label);
    
    TF5 =  new JTextField("25", 3);
    panel.add(TF5);
    
    label = new JLabel(" % Max");
    panel.add(label);
    
    centerPanel.add(panel);*/
    
    // Add row 7
    panel = new JPanel();
    panel.setLayout(new FlowLayout(FlowLayout.LEFT));
    
    rbutton = new JRadioButton("Normalize Decay Profile");
    rbutton.addActionListener(this);
		rbutton.setActionCommand("ndp");
    group.add(rbutton);
    panel.add(rbutton);
    
    panel.add(Box.createRigidArea(new Dimension(10,0)));
    
    label = new JLabel("Max Intensity @ ");
    panel.add(label);
    
    TF6 =  new JTextField("0", 6);
    panel.add(TF6);
    
    label = new JLabel(" ps/ns");
    panel.add(label);
    
    centerPanel.add(panel);
    
    // Add row 8. This allows the area and counts to be calculated from a spectra or 
    // decay profile
    panel = new JPanel();
    panel.setLayout(new FlowLayout(FlowLayout.LEFT));
    
    rbutton = new JRadioButton();
		rbutton.setSelected(true);
    rbutton.addActionListener(this);
		rbutton.setActionCommand("area");
    group.add(rbutton);
    panel.add(rbutton);
    
    panel.add(Box.createRigidArea(new Dimension(2,0)));
    
    String[] ops = {"Sum", "Area", "S & A", "FP"};
    aopCB = new JComboBox(ops);
    aopCB.setSelectedIndex(0);
    panel.add(aopCB);
    
    panel.add(Box.createRigidArea(new Dimension(5,0)));
    
    label = new JLabel("From ");
    panel.add(label);
    
    areaTF1 =  new JTextField("min", 5);
    panel.add(areaTF1);
    
    panel.add(Box.createRigidArea(new Dimension(2,0)));
    
    label = new JLabel("to");
    panel.add(label);
    
    panel.add(Box.createRigidArea(new Dimension(2,0)));
    
    areaTF2 =  new JTextField("max", 5);
    panel.add(areaTF2);
    
    label = new JLabel("X units ");
    panel.add(label);
    
    areaTF3 =  new JTextField("0,0", 5);
    panel.add(areaTF3);
    
    centerPanel.add(panel);
    
    // Add row 9 now
    panel = new JPanel();
    panel.setLayout(new FlowLayout(FlowLayout.LEFT));
    
    rbutton = new JRadioButton("Blank");
		rbutton.setSelected(true);
    rbutton.addActionListener(this);
		rbutton.setActionCommand("blank");
    group.add(rbutton);
    panel.add(rbutton);
    
    panel.add(Box.createRigidArea(new Dimension(62,0)));
    
    label = new JLabel("Status : ");
    panel.add(label);
    
    status = new JLabel("Not Ready");
    status.setForeground(Color.blue);
    panel.add(status);
    
    centerPanel.add(panel);
    
    // Panel that allow users to select whether to add new ojects or just update the data in
    // the data 
    panel = new JPanel();
    panel.setLayout(new FlowLayout(FlowLayout.LEFT));
    
    // add the center panel now
    centerPanel.add(panel);
    
    CB1 = new JCheckBox("Add New Spectra Data Objects");
    CB1.setSelected(true);
    panel.add(CB1);
    
    getContentPane().add(centerPanel, "Center");
    
    // Add the button panel
    panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
    
    Border border2 = BorderFactory.createRaisedBevelBorder();
    panel.setBorder(border2);
    
    button = new JButton("Set Data");
    button.setActionCommand("setdata");
		button.addActionListener(this);
    panel.add(button);
    
    button = new JButton("Set Blank");
    button.setActionCommand("setblank");
		button.addActionListener(this);
    panel.add(button);
    
    button = new JButton("Loaded Data ?");
    button.setActionCommand("info");
		button.addActionListener(this);
    panel.add(button);
    
    panel.add(Box.createHorizontalGlue());
    
    button = new JButton("Run");
    button.setActionCommand("run");
		button.addActionListener(this);
    panel.add(button);
    
    getContentPane().add(panel, "South");
  }
  
  // Method to load instrument correction data
  private void loadICFData() {
    File dataDirectory = new File(InstruView.standardDataDirectory);
    File file = new File(dataDirectory, InstruView.ICFfilename);
    
    // readin the data now
    if(file.exists()) {
      Object object = BinaryFileManager.getObjectFromFile(file);
      try {
        ExperimentData experimentData = (ExperimentData)object;
        String exp_type = experimentData.getType();
        
        int size = experimentData.getDataCount();
        if(size > 0) {
          ICFdata = new SpectraData[size];
          for(int i = 0; i < size; i++) {
            ICFdata[i] = experimentData.getData(i);
          }
        }
        else {
          System.err.println("No Correctiion Data in File " + file);
        }
      }
      catch(ClassCastException cce) { }  // handel any class cast excpetion
    }
  }
  
  // function to return a string array with spectra operation names
  private String[] getSpectraOperations() {
    String[] sops = null;
    
    if(ICFdata != null) {
      sops = new String[5 + ICFdata.length];
      sops[0] = "-";
      sops[1] = "+";
      sops[2] = "/";
      sops[3] = "*";
      sops[4] = "avg";
      for(int i = 0; i < ICFdata.length; i++) {
        sops[5 + i] = "ICF-" + (i + 1);
      }
    }
    else {
      sops = new String[]{ "-", "+", "/", "*", "avg"};
    }
    
    return sops;
  }
  
  // This method hadels action commands
  public void actionPerformed(ActionEvent e) {
    String cmd = e.getActionCommand();
    
    if(cmd.equals("setdata")) {
      setData();
    }
    else if(cmd.equals("setblank")) {
      setBlankData();
    }
    else if(cmd.equals("info")) {
      displayLoadedData();
    }
    else if(cmd.equals("arithmetic") || cmd.equals("normalize0")  || cmd.equals("normalize1")
    || cmd.equals("spectramath") || cmd.equals("blank") || cmd.equals("datatrim")
    || cmd.equals("ndp") || cmd.equals("area")) {
      tftype = cmd;
    }
    else if(cmd.equals("run")) {
      if(sdata == null) {
        return;
      }
      
      if(tftype.equals("blank") && bsdata == null) {
        return;
      }
      
      runTransform();
    }
    else {
      System.err.println("Event not handel in class TransformationPanel " + cmd);
    }
  }
  
  // Method to set the result
  public void setResults(SpectraData[] sda) {
    if(CB1.isSelected()) {
      epanel.addSpectraData(sda);
    }
    else {
      epanel.updateSpectraData(sda);
    }
  }
  
  // Method to set the status of the transform job
  public void setStatus(int code, String message) {
    if(code == 0) {
      status.setText("Done");
    }
    else if(code == 100) {
      status.setText("Done");
      instruView.console.print(message);
      instruView.console.setVisible(true);
    }
    else {
      status.setText("Error");
      instruView.console.print(message);
      instruView.console.setVisible(true);
    }
  }
  
  // Method to load data
  private void setData() {
    epanel = instruView.experimentPanel;
    if(epanel.getSelectedSpectraData() != null) {
      sdata = epanel.getSelectedSpectraData();
      if(!tftype.equals("blank") || !tftype.equals("normalize1") || !tftype.equals("spectramath")) {
        status.setText("Ready");
      }
    }
  }
  
  // Method to load the blank data
  private void setBlankData() {
    epanel = instruView.experimentPanel;
    
    if(epanel.getSelectedSpectraData() != null) {
      sop = (String)sopCB.getSelectedItem();
      if(tftype.equals("spectramath")) {
        smbdata = epanel.getSelectedSpectraData();
        
        //debug code
        //System.out.println("Blank 1 is " + smbdata[0].toString());
        //System.out.println("Blank 2 is " + smbdata[1].toString());
      }
      else {
        bsdata = epanel.getSelectedSpectraData()[0];
      }
    }
    
    if(sdata != null && tftype.equals("spectramath")) {
      smstatus.setText("Ready");
    }
    else if(sdata != null) {
      status.setText("Ready");
    }
  }
  
  // display the loaded data
  private void displayLoadedData() {
    String message;
    if(sdata != null) {
      StringBuffer buffer = new StringBuffer();
      buffer.append("Data files loaded into Transform Dialog >\n");
      for(int i = 0; i < sdata.length; i++) {
        buffer.append("Spectra Data ").append(i + 1).append(" : ").append(sdata[i].toString()).append("\n");
      }
      
      if(bsdata != null) {
        buffer.append("Blank Data : ").append(bsdata.toString()).append("\n");
      }
      
      if(smbdata != null) {
        buffer.append("SpectraMath Blank Data 1 : ").append(smbdata[0].toString()).append("\n");
      }
      
      if(ICFdata != null) {
         buffer.append("\nInstrument Correction File Data: \n");
        for(int i = 0; i < ICFdata.length; i++) {
          String[] header = ICFdata[i].getHeader();
          String note = header[header.length -1];
          buffer.append("ICF-").append(i+1).append(" : ").append(ICFdata[i].toString()).
          append("/").append(note).append("\n");
        }
      }
      else {
        buffer.append("\n\n");
      }
      
      message = buffer.toString();
    }
    else {
      message = "No Data Loaded In Transform Dialog\n\n";
    }
    
    if(epanel != null) {
      instruView.console.print(message);
      instruView.console.setVisible(true);
    }
  }
  
  // Method to run the transform
  private void runTransform() {
    if(tftype.equals("arithmetic")) {
      try {
        String axis = (String)axisCB.getSelectedItem();
        op = (String)opCB.getSelectedItem();
        float fc = Float.parseFloat(TF1.getText());
        new ArithmeticTransformThread(this, sdata, axis, op, fc).start();
      }
      catch (NumberFormatException nfe) { }
    }
    else if(tftype.equals("normalize0")) {
      try {
        float wl = Float.parseFloat(TF2.getText());
        new NormalizeTransformThread(this, sdata, 0, 0, wl).start();
      }
      catch(NumberFormatException nfe) { }
    }
    else if(tftype.equals("normalize1")) {
      try {
        float normalizeFactor = Float.parseFloat(TFn1.getText());
        float wl = Float.parseFloat(TF3.getText());
        new NormalizeTransformThread(this, sdata, 1, normalizeFactor, wl).start();
      }
      catch(NumberFormatException nfe) { }
    }
    if(tftype.equals("spectramath")) {
      runSpectraMathTransform();
    }
    else if(tftype.equals("blank")) {
      new BlankTransformThread(this, sdata, bsdata).start();
    }
    else if(tftype.equals("datatrim")) {
      String minX = trimTF1.getText();
      String maxX =trimTF2.getText();
      new DataTrimThread(this, sdata, minX, maxX).start();
    }
    /*else if(tftype.equals("streakclean")) { *** This is no longer used as of 3/12/06 ***
      try {
        float mindiff = Float.parseFloat(TF4.getText());
        float percent =Float.parseFloat(TF5.getText());
        new StreakCleanThread(this, sdata, mindiff, percent).start();
      }
      catch(NumberFormatException nfe) { }
    }*/
    else if(tftype.equals("ndp") && sdata.length >=2) { // must allow for normarlization without shifting
      try {
        float max_intensity_time = Float.parseFloat(TF6.getText());
        new NormalizeDecayProfileThread(this, sdata, max_intensity_time).start();
      }
      catch(NumberFormatException nfe) { }
    }
    else if(tftype.equals("area")) { // calculate the area or sum the data in the specified data region
      try {
        String minX = areaTF1.getText();
        String maxX = areaTF2.getText();
        String xUnits = areaTF3.getText();
        String op = (String)aopCB.getSelectedItem();
        new SumAreaThread(this, sdata, op, minX, maxX, xUnits).start();
      }
      catch(NumberFormatException nfe) { }
    }
    
    //debug code
    System.out.println("Running " + tftype + " transform...");
  }
  
  // Method to run a spectra math transform
  private void runSpectraMathTransform() {
    // code 9/25/06
    sop = (String)sopCB.getSelectedItem();
    
    if(sop.indexOf("ICF-") != -1) {
      SpectraData[] sda = {getICFData(sop)};
      sop = getICFOperation(sda[0]);
      new SpectraMathTransformThread(this, sdata, sda, sop).start();
    }
    else {
      new SpectraMathTransformThread(this, sdata, smbdata, sop).start();
    }
  }
  
  // Method to return the ICF data
  private SpectraData getICFData(String icfname) {
    SpectraData sd = null;
    String[] sa = icfname.split("-");
    
    try {
      int index = Integer.parseInt(sa[1]) -1;
      sd = ICFdata[index];
    }
    catch(NumberFormatException nfe) { }
    
    return sd;
  }
  
  // Method to return the function to perfom on ICF data
  private String getICFOperation(SpectraData sd) {
    String op = "";
    
    String[] header = sd.getHeader();
    String sample_notes = header[header.length - 1];
    
    //System.out.println("Sample notes is " + sample_notes);
    
    if(sample_notes.indexOf("(-)") != -1) {
      op = "-";
    }
    else if(sample_notes.indexOf("(+)") != -1) {
      op = "+";
    }
    else if(sample_notes.indexOf("(/)") != -1) {
      op = "/";
    }
    else if(sample_notes.indexOf("(*)") != -1) {
      op = "*";
    }
    
    return op;
  }
} // -- end class TransformDialog
