
/** 
 * SpectraMathTransformThread.java
 * do basic arithematic on the spectra data files
 * 
 *
 * Created:  Mar 1, 2004
 *
 * @author Nathan Stevens
 * @version 0.4 8/24/05
 */
import java.util.Vector;

public class SpectraMathTransformThread extends Thread {
  private TransformViewer transformViewer = null;
  private SpectraData[] sdata = null;
  private SpectraData[] bsdata = null;
  private String op = null;
  private Vector sdataVector = new Vector();
  private int code = 0;
  private StringBuffer buffer = new StringBuffer();
  
  // The main constructor
  public SpectraMathTransformThread(TransformViewer transformViewer, SpectraData[] sdata, 
                                                               SpectraData[] bsdata, String op) {
    this.transformViewer = transformViewer;
    this.sdata = sdata;
    this.bsdata = bsdata;
    this.op = op;
    
    buffer.append("Transform Error >\n");
  }
  
  // The run method
  public void run() {
    
    if(op.equals("-")) {
      subtractSpectra();
    }
    else if(op.equals("+")) {
      addSpectra();
    }
    else if(op.equals("/")) {
      divideSpectra();
    }
    else if(op.equals("*")) {
      multiplySpectra();
    }
    else if(op.equals("avg")) {
      averageSpectra();
    }
    else {
      System.err.println("Unknown Operation (" + op + ") in SpectraMathTransformThread...");
    }
  }
  
  // Method to substract spectra from each order
  private void subtractSpectra() {
    for(int i = 0; i < sdata.length; i++) {
      String[] header = (String[])sdata[i].getHeader().clone();
      String[] dmeta = (String[])sdata[i].getMetaInfo().clone();
      
      float[][] data = sdata[i].getData();
      float[][] rdata = sdata[i].getReferenceData();
      float[][] bdata = bsdata[0].getData();
      float[][] ndata = new float[data.length][2];
      float[][] nrdata = null;
      if(rdata != null) {
        nrdata = new float[data.length][2];
      }
      
      if(data.length == bdata.length) {
        for(int j = 0; j < data.length; j++) {
          ndata[j][0] = data[j][0];
          ndata[j][1] = data[j][1] - bdata[j][1];
          if(rdata != null) {
           nrdata[j][0] = rdata[j][0];
           nrdata[j][1] = rdata[j][1] - bdata[j][1];
          }
        }
      }
      else {
        for(int j = 0; j < data.length; j++) {
          float cf = getYValue(bdata, data[j][0]);
          ndata[j][0] = data[j][0];
          ndata[j][1] = data[j][1] - cf;
          if(rdata != null) {
           nrdata[j][0] = rdata[j][0];
           nrdata[j][1] = rdata[j][1] - cf;
          }
        }
      }
      
      String name;
      if(sdata[i].getType().equals("pump-probe") || sdata[i].getType().equals("frgs")) {
        name = sdata[i].getName() + "-" + sdata[i].getDelay() + "-SSTF";
      }
      else {
        name = sdata[i].getName() + "-SSTF";
      }
      SpectraData sd = new SpectraData(name, sdata[i].getType(), header, dmeta,
      ndata, nrdata);
      sdataVector.addElement(sd);
    }
    if(sdataVector.size() > 0) {
       SpectraData[] sda = SpectraDataUtil.getSpectraDataArray(sdataVector);
       transformViewer.setResults(sda);
     }
     transformViewer.setStatus(code, buffer.toString());
  }
  
  // Method to add spectra
  private void addSpectra() {
    for(int i = 0; i < sdata.length; i++) {
      String[] header = (String[])sdata[i].getHeader().clone();
      String[] dmeta = (String[])sdata[i].getMetaInfo().clone();
      
      float[][] data = sdata[i].getData();
      float[][] rdata = sdata[i].getReferenceData();
      float[][] bdata = bsdata[0].getData();
      float[][] ndata = new float[data.length][2];
      float[][] nrdata = null;
      if(rdata != null) {
        nrdata = new float[data.length][2];
      }
      
      if(data.length == bdata.length) {
        for(int j = 0; j < data.length; j++) {
          ndata[j][0] = data[j][0];
          ndata[j][1] = data[j][1] + bdata[j][1];
          if(rdata != null) {
           nrdata[j][0] = rdata[j][0];
           nrdata[j][1] = rdata[j][1] + bdata[j][1];
          }
        }
      }
      else {
        for(int j = 0; j < data.length; j++) {
          float cf = getYValue(bdata, data[j][0]);
          ndata[j][0] = data[j][0];
          ndata[j][1] = data[j][1] + cf;
          if(rdata != null) {
           nrdata[j][0] = rdata[j][0];
           nrdata[j][1] = rdata[j][1] + cf;
          }
        }
      }
      
      String name;
      if(sdata[i].getType().equals("pump-probe") || sdata[i].getType().equals("frgs")) {
        name = sdata[i].getName() + "-" + sdata[i].getDelay() + "-SATF";
      }
      else {
        name = sdata[i].getName() + "-SATF";
      }
      SpectraData sd = new SpectraData(name, sdata[i].getType(), header, dmeta,
      ndata, nrdata);
      sdataVector.addElement(sd);
    }
    if(sdataVector.size() > 0) {
       SpectraData[] sda = SpectraDataUtil.getSpectraDataArray(sdataVector);
       transformViewer.setResults(sda);
     }
     transformViewer.setStatus(code, buffer.toString());
  }
  
  // Method to divide spectra
  private void divideSpectra() {
    for(int i = 0; i < sdata.length; i++) {
      String[] header = (String[])sdata[i].getHeader().clone();
      String[] dmeta = (String[])sdata[i].getMetaInfo().clone();
      
      float[][] data = sdata[i].getData();
      float[][] rdata = sdata[i].getReferenceData();
      float[][] bdata = bsdata[0].getData();
      float[][] ndata = new float[data.length][2];
      float[][] nrdata = null;
      if(rdata != null) {
        nrdata = new float[data.length][2];
      }
      
      if(data.length == bdata.length) {
        for(int j = 0; j < data.length; j++) {
          ndata[j][0] = data[j][0];
          ndata[j][1] = data[j][1] / bdata[j][1];
          if(rdata != null) {
           nrdata[j][0] = rdata[j][0];
           nrdata[j][1] = rdata[j][1] / bdata[j][1];
          }
        }
      }
      else {
        for(int j = 0; j < data.length; j++) {
          float cf = getYValue(bdata, data[j][0]);
          ndata[j][0] = data[j][0];
          ndata[j][1] = data[j][1] / cf;
          if(rdata != null) {
           nrdata[j][0] = rdata[j][0];
           nrdata[j][1] = rdata[j][1] / cf;
          }
        }
      }
      
      String name;
      if(sdata[i].getType().equals("pump-probe") || sdata[i].getType().equals("frgs")) {
        name = sdata[i].getName() + "-" + sdata[i].getDelay() + "-SDTF";
      }
      else {
        name = sdata[i].getName() + "-SDTF";
      }
      SpectraData sd = new SpectraData(name, sdata[i].getType(), header, dmeta,
      ndata, nrdata);
      sdataVector.addElement(sd);
    }
    if(sdataVector.size() > 0) {
       SpectraData[] sda = SpectraDataUtil.getSpectraDataArray(sdataVector);
       transformViewer.setResults(sda);
     }
     transformViewer.setStatus(code, buffer.toString());
  }
  
  // Method to multiply spectra
  private void multiplySpectra() {
    for(int i = 0; i < sdata.length; i++) {
      String[] header = (String[])sdata[i].getHeader().clone();
      String[] dmeta = (String[])sdata[i].getMetaInfo().clone();
      
      float[][] data = sdata[i].getData();
      float[][] rdata = sdata[i].getReferenceData();
      float[][] bdata = bsdata[0].getData();
      float[][] ndata = new float[data.length][2];
      float[][] nrdata = null;
      if(rdata != null) {
        nrdata = new float[data.length][2];
      }
      
      if(data.length == bdata.length) {
        for(int j = 0; j < data.length; j++) {
          ndata[j][0] = data[j][0];
          ndata[j][1] = data[j][1] * bdata[j][1];
          if(rdata != null) {
           nrdata[j][0] = rdata[j][0];
           nrdata[j][1] = rdata[j][1] * bdata[j][1];
          }
        }
      }
      else {
        for(int j = 0; j < data.length; j++) {
          float cf = getYValue(bdata, data[j][0]);
          ndata[j][0] = data[j][0];
          ndata[j][1] = data[j][1] * cf;
          if(rdata != null) {
           nrdata[j][0] = rdata[j][0];
           nrdata[j][1] = rdata[j][1] * cf;
          }
        }
      }
      
      String name;
      if(sdata[i].getType().equals("pump-probe") || sdata[i].getType().equals("frgs")) {
        name = sdata[i].getName() + "-" + sdata[i].getDelay() + "-SMTF";
      }
      else {
        name = sdata[i].getName() + "-SMTF";
      }
      SpectraData sd = new SpectraData(name, sdata[i].getType(), header, dmeta,
      ndata, nrdata);
      sdataVector.addElement(sd);
    }
    if(sdataVector.size() > 0) {
       SpectraData[] sda = SpectraDataUtil.getSpectraDataArray(sdataVector);
       transformViewer.setResults(sda);
     }
     transformViewer.setStatus(code, buffer.toString());
  }
  
  // Method to average spectras
  private void averageSpectra() {
    String[] header = (String[])sdata[0].getHeader().clone();
    String[] dmeta = (String[])sdata[0].getMetaInfo().clone();
    
    int rcount = 0;
    
    float[][] ndata = new float[sdata[0].getData().length][2];
    float[][] nrdata = new float[ndata.length][2];
    float[] sum_squar = new float[ndata.length];
    float[] rsum_squar = new float[ndata.length];
    
    for(int i = 0; i < sdata.length; i++) {
      float[][] data = sdata[i].getData();
      float[][] rdata = sdata[i].getReferenceData();
      
      for(int j = 0; j < data.length; j++) {
        ndata[j][0] = data[j][0];
        ndata[j][1] += data[j][1];
        sum_squar[j] += Math.pow(data[j][1], 2);
        
        if(rdata != null) {
          nrdata[j][0] = rdata[j][0];
          nrdata[j][1] += rdata[j][1];
          rsum_squar[j] += Math.pow(rdata[j][1], 2);
          rcount++;
        }
      }
    }
    
    // now divide by the number of spectra
    float[][] std_dev = new float[ndata.length][2];
    float[][] rstd_dev = new float[ndata.length][2];
    
    int N = sdata.length;
    for(int i = 0; i < ndata.length; i++) {
      // caculate the coefficient of variation
      float std1 = (float)(sum_squar[i] - Math.pow(ndata[i][1], 2)/N)/(N -1);
      float std2 = (float)((Math.sqrt(std1)/(ndata[i][1]/N))*100);
      std_dev[i][0] = ndata[i][0];
      std_dev[i][1] = std2;
      
      std1 = (float)(rsum_squar[i] - Math.pow(nrdata[i][1], 2)/N)/(N -1);
      std2 = (float)((Math.sqrt(std1)/(nrdata[i][1]/N))*100);
      rstd_dev[i][0] = nrdata[i][0];
      rstd_dev[i][1] = std2;
      
      // now final get the average of the data
      ndata[i][1] = ndata[i][1]/N;
      nrdata[i][1] = nrdata[i][1]/rcount;
    }
    
    if(rcount == 0) {
      nrdata = null;
      rstd_dev = null;
    }
    
    String name = null;
    String type = sdata[0].getType();
    int direction = sdata[0].getProfileDirection();
    
    name = sdata[0].getName() + "-AVTF";
    
    SpectraData sd = new SpectraData(name, type, header, dmeta, ndata, nrdata);
    sd.setProfileDirection(direction);
    
    sdataVector.addElement(sd);
    
    // Add the spectra data which has the standard deviation data
    String[] header2 = (String[])sdata[0].getHeader().clone();
    String[] dmeta2 = (String[])sdata[0].getMetaInfo().clone();
    
    // set the modify the header information so that the correct lables are shown in the plot
    // code
    
    String name2 = sdata[0].getName() + "-CV";
    String type2 = sdata[0].getType();
    int direction2 = sdata[0].getProfileDirection();
    
    SpectraData sd2 = new SpectraData(name2, type2, header2, dmeta2, std_dev, rstd_dev);
    sd2.setProfileDirection(direction);
    
    sdataVector.addElement(sd2);
    
    if(sdataVector.size() > 0) {
      SpectraData[] sda = SpectraDataUtil.getSpectraDataArray(sdataVector);
      transformViewer.setResults(sda);
    }
    transformViewer.setStatus(0, "No Message");
  }
  
  // Method to get the y value for a particular x value
  private float getYValue(float[][] data, float xvalue) {
    float yvalue = 0.0f;
    
    float p = Math.abs((data[1][0] - data[0][0])/2.0f);
    for(int i = 0; i < data.length; i++) {
      float diff = Math.abs(data[i][0] - xvalue);
      if(diff < p) {
        yvalue = data[i][1];
        break;
      }
    }
    
    return yvalue;
  }
}//--end class SpectraMathTransform
