
/**
 * EPRViewPlugin.java
 * Used to view and process time resolved EPR data
 *
 * Created: May 7, 2005
 *
 * @author Nathan Stevens
 * @version 0.1 7/14/05
 */
 
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import java.util.*;
import java.awt.image.BufferedImage;
import java.awt.image.MemoryImageSource;
import java.awt.Image;
import java.io.*;

public class EPRViewPlugin extends JFrame implements ActionListener,
ListSelectionListener, InstruViewPlugin {
  private static final String VERSION = "0.1 (7-14-05)";
  private InstruView instruView= null;
  private JPanel blankPanel = null;
  private EPRImagePanel imagePanel = null;
  private JScrollPane scrollPane = null;
  private ExperimentData experimentData = null;
  private File file = null;
  private String name = "EPRView";
  
  // the file open and close dialog
  private final JFileChooser fc = new JFileChooser();
  private ExperimentDataFileFilter sdlFileFilter = null;
  private ExperimentDataFileFilter textFileFilter= null;
  
  // default constructor
  public EPRViewPlugin() { }
  
  public EPRViewPlugin(InstruView instruView) {
    super("EPRView v- " + VERSION);
    
    // exist the program
		addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent we) {
				close();
		  }
		});
    
    // Set the layout to border layout
    getContentPane().setLayout(new BorderLayout());
    
    // some gui stuff
    JPanel panel;
    JLabel label;
    JButton button;
    
    // the panel that tells the user that no data is loaded
    blankPanel = new JPanel();
    label = new JLabel("<html>EPRView Plugin<br>No data loaded...");
    blankPanel.add(label);
    
    getContentPane().add(blankPanel, "Center");
    
    /* add the information and control pane now */
    JTabbedPane tabbPane = new JTabbedPane();
    //tabPane.addChangeListener(this);
    
    // Add the information panel
    JPanel infoPanel = new JPanel();
    infoPanel.setLayout(new BoxLayout(infoPanel, BoxLayout.Y_AXIS));
    
    label = new JLabel("Data Information Goes Here");
    infoPanel.add(label);
    
    tabbPane.addTab("Information", null, infoPanel,
                                   "Information About The EPR Data"); //tooltip text
                                                       
    
    // Add the processing panel here
    JPanel processPanel = new JPanel();
    processPanel.setLayout(new BoxLayout(processPanel, BoxLayout.Y_AXIS));
    
    label = new JLabel("Process Data Here");
    processPanel.add(label);
    
    tabbPane.addTab("Process", null, processPanel,
                                   "Process The EPR Data"); //tooltip text
    
    
    
    getContentPane().add(tabbPane, "East");
    
    // add the button panel now
    JPanel southPanel = new JPanel();
    southPanel.setLayout(new BoxLayout(southPanel, BoxLayout.X_AXIS));
    
    button = new JButton("Open ASCII File");
		button.setActionCommand("open_ascii");
		button.addActionListener(this);
    button.setToolTipText("Open an ASCII EPR data file...");
    southPanel.add(button);
    
    button = new JButton("Open SDL File");
		button.setActionCommand("open_sdl");
		button.addActionListener(this);
    button.setToolTipText("Open a SDL file containing EPR data");
    southPanel.add(button);
    
    button = new JButton("Save");
		button.setActionCommand("save");
		button.addActionListener(this);
    button.setToolTipText("Save the SDL file");
    southPanel.add(button);
    
    button = new JButton("Save As");
		button.setActionCommand("save");
		button.addActionListener(this);
    button.setToolTipText("Save the SDL file as...");
    southPanel.add(button);
    
    southPanel.add(Box.createHorizontalGlue());
    
    button = new JButton("Close");
		button.setActionCommand("close");
		button.addActionListener(this);
    button.setToolTipText("Close this window");
    southPanel.add(button);
    
    getContentPane().add(southPanel, "South");
    
    // initialize the experiment data object now
    String[] meta = new String[5];
    meta[0] = InstruView.getProperty("organization");
    meta[1] = InstruView.getProperty("laboratory");
    meta[2] = InstruView.getProperty("owner");
    meta[3] = InstruView.getProperty("email");
    meta[4] = "mm-dd-yyyy";
    
    experimentData = new ExperimentData("epr", meta);
    
    // initialize some file filters
    sdlFileFilter = new ExperimentDataFileFilter("sdl");
    textFileFilter = new ExperimentDataFileFilter("text");
    
    // set the size and display the window at long last
    setSize(550, 450);
    setVisible(true);
  }
  
  // Method to handel action events
  public void actionPerformed(ActionEvent ae) {
    String cmd = ae.getActionCommand();
    
    if(cmd.equals("open_ascii")) {
      openASCIIFile();
		}
    else if(cmd.equals("open_sdl")) {
      openSDLFile();
		}
    else if(cmd.equals("save")) {
      saveSDLFile();
		}
    else if(cmd.equals("saveas")) {
      saveSDLFileAs();
		}
    else if(cmd.equals("close")) {
      close();
		}
    else {
      System.err.println("Action Command not handeled in class EPRViewPlugin...");
      System.err.println(cmd);
    }
  }
  
  // Method to handle list selection events
  public void valueChanged(ListSelectionEvent e) {
    if (e.getValueIsAdjusting()) {
      return;
    }
    // code
  }
  
  // Method to open the ascii file
  private void openASCIIFile() {
    fc.resetChoosableFileFilters();
    fc.addChoosableFileFilter(textFileFilter);
    File f = showOpenFileDialog();
    
    if(f !=null && f.exists()) {
      new EPRFileReader(this, f).start();
    }
  }
  
  // Method to open an sdl file
  private void openSDLFile() {
    fc.resetChoosableFileFilters();
    fc.addChoosableFileFilter(sdlFileFilter);
    File f = showOpenFileDialog();
    
    if(f !=null && f.exists()) {
      Object object = BinaryFileManager.getObjectFromFile(f);
      ExperimentData ed = (ExperimentData)object;
      if(ed.getType().equals("epr")) {
        loadSDL(ed);
        file = f;
      }
      else {
        System.err.println("Spectra Data List doesn't contain EPR data...");
        file = null;
      }
    }
    else {
      file = null;
    }
  }
  
  // show open file dialog
  private File showOpenFileDialog() {
    File f = null;
    
    int returnVal = fc.showOpenDialog(this);
    
		if (returnVal == JFileChooser.APPROVE_OPTION) {
			f = fc.getSelectedFile();
    }
    
    return f;
  }
  
  // Method that actually saves the sdl file
  private void  saveSDLFile() {
    if(file != null) {
      BinaryFileManager.saveObjectToFile(experimentData, file);
    }
    else {
      saveSDLFileAs();
    }
  }
  
  // Method that actually saves the sdl file
  private void  saveSDLFileAs() {
    fc.resetChoosableFileFilters();
    fc.addChoosableFileFilter(sdlFileFilter);
    
    int returnVal = fc.showSaveDialog(this);
    
    if (returnVal == JFileChooser.APPROVE_OPTION) {
      File f = fc.getSelectedFile();
      if(f != null) {
        // check to see if correct file extension is there.  if not add it
        String name = f.toString();
        if(name.toLowerCase().indexOf(".sdl") == -1) {
          name += ".sdl";
          f = new File(name);
        }
        
        file = f;
        BinaryFileManager.saveObjectToFile(experimentData, file);
      }
    }
  }
  
  // Method to return information about this plugin
  public String[] getPluginInformation() {
    String[] information = {"Author : Nathan Stevens",
                                            "Version : " + VERSION,
                                            "",
                                            "A plugin for handeling time resolved epr data"};
    
    return information;
  }
  
  // Method to add a single spectra data object used for loading initial image only
  public void addSpectraData(SpectraData sd) {
    experimentData.addData(sd);
    loadEPRImage();
  }
  
  // Method to set any spectra data, not used for now
  public void addSpectraData(SpectraData[] sda) {  }
  
  // Method to load an sdl file
  public void loadSDL(ExperimentData experimentData, File file) {
    this.experimentData = experimentData;
    this.file = file;
    loadEPRImage();
  }
  
  // Method to load an sdl file
  public void loadSDL(ExperimentData experimentData) { 
    this.experimentData = experimentData;
    loadEPRImage();
  }
  
  // Method to print any messages
  public void print(String message) {
    System.out.println(message);
  }
  
  // create and add the epr image now
  private void loadEPRImage() {
    SpectraData sd = experimentData.getData(0);
    String[] header = sd.getHeader();
    
    float min = 0.0f;
    float max = 0.0f;
    try {
      min  = Float.parseFloat(header[4]);
      max = Float.parseFloat(header[5]);
    }
    catch(NumberFormatException nfe) {
      return;
    }
    
    float[][] data = sd.getData();
    int width = data[0].length -1;
    int height = data.length - 1;
    
    // remove any images that's already there
    if(blankPanel != null) {
      getContentPane().remove(blankPanel);
      blankPanel = null;
    }
    
    if(scrollPane != null) {
      getContentPane().remove(scrollPane);
    }
    
    Image eprImage = createEPRImage(data, min, max);
    imagePanel = new EPRImagePanel(this, eprImage, width, height);
    
    // add the image to the center panel now
    
    scrollPane = new JScrollPane(imagePanel);
    scrollPane.setPreferredSize(new Dimension(width, height));
    
		getContentPane().add(scrollPane, "Center");
    
    // need to call in order to display the image
    validate();
    repaint();
  }
  
  // Method to update the ROI
  public void updateROI(Rectangle rect) {
    // code
  }
  
  // Method to close this dialog
  private void close() {
    setVisible(false);
    dispose();
  }
  
  // Method to create an EPRImage
  private Image createEPRImage(float[][] data, float min, float max) {
    int w = data[0].length - 1;  // remove 1 for the axis
    int h = data.length - 1; // remove 1 for the axis
    int pix[] = new int[w * h];
    int index = 0;
    
    float blue_increment = max/255;
    float red_increment = Math.abs(min/255);
    
    for (int y = 0; y < h; y++) {
	    for (int x = 0; x < w; x++) {
        int blue = 0;
        int green = 0;
        int red= 0;
        int alpha = 255;
        
        if(data[y+1][x + 1] > 0) {
          blue = (int)(data[y + 1][x + 1]/blue_increment);
        }
        else {
          red = (int)Math.abs(data[y +1][x + 1]/red_increment);
        }
        
        index = y*w + x;
        pix[index] = (alpha << 24) | (red << 16) | (green << 8) | blue;
	    }
    }
    
    Image image = createImage(new MemoryImageSource(w, h, pix, 0, w));
    
    return image;
  }
  
  // the static class for putting it self into the class
  static class EPRViewFactory extends PluginFactory {
    public InstruViewPlugin create(InstruView instruView) {
      return (new EPRViewPlugin(instruView));
    }
    
    // get the experiment type
    public String getExperimentType() {
      return "epr";
    }
    
    // get information about this plugin
    public String[] getPluginInformation() {
      String[] information = {"Author : Nathan Stevens",
                                              "Version : " + VERSION,
                                              "",
                                              "A plugin for handeling time resolved epr data"};
      
      return information;
    }
  }// -- end inner static class PlotterFactory
  
  // add this factory to the InstruviewPluginLoader factory hashtable
  static {
    InstruViewPluginLoader.pluginFactories.put("EPR View", new EPRViewFactory());
  }
}//--end class EPRViewPlugin
