
/**
 * SpectraDataUtil.java
 * This class provides methods for creating string arrays from spectra data objects,
 * splitting spectra data objects, and integrasting spectra data arrays.
 *
 * Created: Jan 2, 2004
 *
 * @author Nathan Stevens
 * @version 0.2 10/16/08
 */
import java.util.*;

public class SpectraDataUtil {
  
  /**
    * Methods to get String Data Arrays From Spectra Data Objects
    */
  
  // Method to return the spectra string[][] array for a spectra data object
  public static String[][] getStringArray(SpectraData sd) {
    float[][] data = sd.getData();
    String[][] xydata = new String[data.length][2];
    
    for(int i = 0; i < data.length; i++) {
      xydata[i][0] = ""+ data[i][0];
      xydata[i][1] = ""+ data[i][1];
    }
    return xydata;
  }
  
  // Method to return the spectra string[][] array for a spectra data object
  public static String[][] get3DStringArray(SpectraData sd) {
    float[][] data = sd.getData();
    String[][] xydata = new String[data.length-1][data[0].length];
    
    for(int i = 0; i < xydata.length; i++) {
      for(int j = 0; j < xydata[0].length; j++) {
        xydata[i][j] = data[i+1][j] + "";
      }
    }
    
    return xydata;
  }
  
  // Method to return the spectra string[][] array for a spectra data with references
  public static String[][] getRefStringArray(SpectraData sd) {
    float[][] data = sd.getData();
    float[][] rdata = sd.getReferenceData();
    String[][] xydata = new String[data.length][3];
    
    for(int i = 0; i < data.length; i++) {
      xydata[i][0] = ""+ data[i][0];
      xydata[i][1] = ""+ data[i][1];
      xydata[i][2] = ""+ rdata[i][1];
    }
    return xydata;
  }
  
  // Method to return the spectra string[][] array for an array of spectra data objects
  public static String[][] getStringArray(SpectraData[] sda, boolean ref) {
    String[][] xydata = null;
    SpectraData sd = null;
    float[][] data, rdata, ndata;
    boolean exportx;
    
    int[] count = getSize(sda, ref);
    xydata = new String[count[1]][count[0]];
    
    //System.out.println("Array bounds is " + count[1] + " , " + count[0]);
    
    int k = 0;
    int l = 0;
    for(int i = 0; i < sda.length; i++) {
      sd = sda[i];
      data = sd.getData();
      rdata = sd.getReferenceData();
      
      exportx = sd.exportX();
      int j = 0;
      
      // add the data into the array now
      for( ; j < data.length; j++) {
        l = 0;
        if(exportx) {
          xydata[j][k+l] = "" + data[j][0]; // add x data
          l++;
          xydata[j][k+l] = "" + data[j][1]; // add y data
          
          if(ref && sd.hasRef()) {
            l++;
            xydata[j][k+l] = "" + rdata[j][1];
          }
        }
        else {
          xydata[j][k+l] = "" + data[j][1]; // and y data only
          
          if(ref && sd.hasRef()) {
            l++;
            xydata[j][k+l] = "" + rdata[j][1]; // change back to 2 if it doesn't work
          }
        }
      }
      
      // add an blanks if nessassary now
      for( ; j < xydata.length; j++) {
        l = 0;
        if(exportx) {
          xydata[j][k+l] = "";
          l++;
          xydata[j][k+l] = "";
          
          if(ref && sd.hasRef()) {
            l++;
            xydata[j][k+l] = "";
          }
        }
        else {
          xydata[j][k+l] = "";
          
          if(ref && sd.hasRef()) {
            l++;
            xydata[j][k+l] = ""; // change back to 2 if it doesn't work
          }
        }
      }
      
      // increment k now
      if(exportx) {
        k += 2;
      }
      else {
        k++;
      }
      
      if(ref && sd.hasRef()) {
        k++;
      }
    }
    return xydata;
  }
  
  // Method to return the spectra string[][] array for a vector of spectra data objects
  public static String[][] getStringArray(Vector vsda) {
    return getStringArray(getSpectraDataArray(vsda), false);
  }
  
  // Method to get the colum labels for a single spectra data.  probably only used for 3D
  // data
  public static String[] get3DColumnLabels(SpectraData sd) {
    float[][] data = sd.getData();
    String[] clabels = new String[data[0].length];
    clabels[0] = "time(ps)/wl(nm)";
    
    for(int i = 1; i < data[0].length; i++) {
      clabels[i] = data[0][i]+"";
    }
    return clabels;
  }
  
  // Method to return a String array containing column names
  public static String[] getColumnLabels(SpectraData[] sda, boolean ref) {
    String[] clabels;
    SpectraData sd;
    
    int[] count = getSize(sda, ref);
    clabels = new String[count[0]];
    
    // next actually make the array
    int j = 0;
    for(int i = 0; i < sda.length; i++) {
      sd = sda[i];
      String[] label = sd.getColumnLabels();
      
      if(sd.exportX()) {
        clabels[j] = label[0];
        j++;
      }
      
      clabels[j] = label[1];
      j++;
      
      if(ref && sd.hasRef()) {
        clabels[j] = label[1] + "-ref";
        j++;
      }
    }
    
    return clabels;
  }
  
  // Method to get the size of the array
  public static int[] getSize(SpectraData[] sda, boolean ref) {
    SpectraData sd;
    int[] count = new int[2];
    int c1 = 0;
    int c2 = 0;
    
    for(int i = 0; i < sda.length; i++) {
      sd = sda[i];
      
      if(sd.size() > c2) {
        c2 = sd.size();
      }
      
      c1++;
      
      if(ref && sd.hasRef()) {
        c1++;
      }
      
      if(sd.exportX()) {
        c1++;
      }
    }
    
    count[0] = c1;
    count[1] = c2;
    
    return count;
  }
  
  /**
    * Methods to get Spectra Data Arrays Below
    */
  
  // Method to get an Array of spectra data from a spectra data array
  public static SpectraData[] getSpectraDataArray(Vector vsda) {
    Object[] vda = vsda.toArray();
    
    if(vsda.size() != 0) {
      SpectraData[] sda = new SpectraData[vda.length];
      
      for(int i = 0; i < sda.length; i++) {
        sda[i] = (SpectraData)vda[i];
      }
      return sda;
    }
    else {
      return null;
    }
  }
  
  // Method to split sdata into 2D and 3D data
  public static SpectraData[] get2DSpectraData(SpectraData[] sda2) {
    SpectraData[] sda;
    Vector vdata = new Vector();
    
    for(int i = 0; i < sda2.length; i++) {
      if(!sda2[i].is3D()) {
        vdata.addElement(sda2[i]);
      }
    }
    
    // check to se if it's empty
    if(vdata.size() == 0) {
      return null;
    }
    
    // now put them into an array
    sda = new SpectraData[vdata.size()];
    for(int i  = 0; i < sda.length; i++) {
      sda[i] = (SpectraData)vdata.elementAt(i);
    }
    return sda;
  }
  
  // Method to split sdata into 2D and 3D data
  public static SpectraData[] get3DSpectraData(SpectraData[] sda2) {
    SpectraData[] sda;
    Vector vdata = new Vector();
    
    for(int i = 0; i < sda2.length; i++) {
      if(sda2[i].is3D()) {
        vdata.addElement(sda2[i]);
      }
    }
    
    // check to se if it's empty
    if(vdata.size() == 0) {
      return null;
    }
    
    // now put them into an array
    sda = new SpectraData[vdata.size()];
    for(int i  = 0; i < sda.length; i++) {
      sda[i] = (SpectraData)vdata.elementAt(i);
    }
    return sda;
  }
  
  // Method to return a real copy of a 2D primative array
  public static float[][] copy2DArray(float[][] xydata) {
    float[][] nxydata = new float[xydata.length][xydata[0].length];
    
    for(int i = 0; i < xydata.length; i++) {
      for(int j = 0; j < xydata[0].length; j++) {
        nxydata[i][j] = xydata[i][j];
      }
    }
    
    return nxydata;
  }
  
  
  /**
    *Streak Camera Specific Methods Below
    *
    **/
  
  // Method to get the ROI data
  public static float[][] getROIData(float[][] data, int wl_index, int wl_width,
                                                            int t_index, int t_width) {
    float[][] roidata = new float[t_width+1][wl_width+1];
    roidata[0][0] = 0.0f;
    
    // fill the wavelength and time axis now
    int k = wl_index;
    for(int i = 1; i < roidata[0].length; i++) {
      roidata[0][i] = data[0][k];
      k++;
    }
    
    k = t_index;
    for(int i = 1; i < roidata.length; i++) {
      roidata[i][0] = data[k][0];
      k++;
    }
    
    // now add the data
    k = t_index;
    int l = wl_index;
    
    for(int i = 1; i < roidata.length; i++) {
      for(int j = 1; j < roidata[0].length; j++) {
        roidata[i][j] = data[k][l];
        l++;
      }
      k++;
      l = wl_index;
    }
    
    return roidata;
  }
  
  // Method to return 2D array containing the normalized integrated intensity 
  // of a three dimensional data. used for streak camera
  public static float[][] integrateH(float[][] data) {
    float[][] idata = new float[data[0].length-1][2];
    
    // add in the wavelengths now
    for(int i = 0; i < idata.length; i++) {
      idata[i][0] = data[0][i+1];
    }
    
    // now integrate the 3D data
    //float dx = data[0][2]-data[0][1];
    float dx = 1.0f;
    
    for(int i = 0; i < idata.length; i++) {
      for(int j = 1; j < (data.length-2); j++) {
        idata[i][1] += dx*(data[j+1][i+1] + data[j+2][i+1])/2.0f;
      }
      //normilize it now or do we
      //idata[i][1] = idata[i][1]/(data.length-1);
    }
    
    return idata;
  }
  
  // Method to return 2D array containing the normalized integrated intensity 
  // of a three dimensional data. used for streak camera
  public static float[][] integrateV(float[][] data) {
    float[][] idata = new float[data.length-1][2];
    
    // add in the time now
    for(int i = 0; i < idata.length; i++) {
      idata[i][0] = data[i+1][0];
    }
    
    if(data[0].length == 2) {// must have one dimension data so copy data and return
      for(int i = 0; i < idata.length; i++) {
        idata[i][1] = data[i+1][1];
      }
    }
    else {
      // data is 3D so integrate it
      //float dx = data[2][0] - data[1][0];
      float dx = 1.0f;
      
      for(int i = 0; i < idata.length; i++) {
        for(int j = 0; j < (data[0].length-2); j++) {
          idata[i][1] += dx*(data[i+1][j+1] + data[i+1][j+2])/2.0f;
        }
        //normilize it now or do we
        //idata[i][1] = idata[i][1]/(data.length-1);
      }
    }
    return idata;
  }
  
  // function to return a string array which consist consist of the data
  // in a format that igor pro can understand
  public static String[] getDataForIgor(SpectraData spectraData) {
    float[][] xydata = spectraData.getData();
    String name = spectraData.getName();
    
    String xwave = "ADD_WAVE;" + name + "_X";
    String ywave = "ADD_WAVE;" + name + "_Y";
    String[] igorData = new String[2];
    
    for(int i = 0; i < xydata.length; i++) {
      xwave += ";" + xydata[i][0];
      ywave += ";" + xydata[i][1];
    }
    
    igorData[0] = xwave;
    igorData[1] = ywave;
    
    return igorData;
  }
  
  // Method to get 3D data for igor
  public static String[] get2DDataForIgor(SpectraData spectraData) {
    float[][] xydata = spectraData.getData();
    String name = spectraData.getName();
    
    String xwave = "ADD_WAVE;" + name + "_X";
    String ywave = "ADD_WAVE;" + name + "_Y";
    String zwave = "ADD_2DWAVE;" + name + "_Z";
    String[] igorData = new String[3];
    
    // copy the y data
    for(int i = 1; i < xydata[0].length; i++) {
      ywave += ";" + xydata[0][i];
    }
    
    // copy the x data
    for(int i = 1; i < xydata.length; i++) {
      xwave += ";" + xydata[i][0];
    }
    
    // copy the zdata
    StringBuffer buffer = new StringBuffer();
    for(int i = 1; i < xydata.length; i++) {
      buffer.append(";");
      for(int k = 1; k < xydata[0].length; k++) {
        buffer.append(xydata[i][k]);
        if(k != xydata[0].length - 1) {
          buffer.append(",");
        }
      }
    }
    
    igorData[0] = xwave;
    igorData[1] = ywave;
    igorData[2] = zwave + buffer.toString();
    
    return igorData;
  }
} // --end class SpectraDataUtil
