/** 
 * SumAreaThread.java
 * this thread is used to calculate the area and sum below a curve, and also to
 * calculate the fluorescence polarization and anistropy
 *
 * Created:  December 14, 2006
 *
 * @author Nathan Stevens
 * @version 0.2 6/13/07
 */
import java.util.Vector;
import java.text.*;

public class SumAreaThread extends Thread {
  private TransformDialog transformDialog = null;
  private SpectraData[] sdata = null;
  private float[] results = null;
  private String op = null;
  private String minX = null;
  private String maxX = null;
  private String xUnits = null;
  private float min_value = 0.0f;
  private float max_value = 0.0f;
  private String[] xValues = null;
  StringBuffer buffer = null;
  
  public SumAreaThread(TransformDialog transformDialog, 
  SpectraData[] sdata, String op, String minX, String maxX, String xUnits) {
    this.transformDialog = transformDialog;
    this.sdata = sdata;
    this.op = op;
    this.minX = minX;
    this.maxX = maxX;
    this.xUnits = xUnits;
    results = new float[sdata.length];
    buffer = new StringBuffer();
    
    // set the xValues
    setXValues();
  }
  
  // The run method
  public void run() {
    // now call the appropriate method to actaully do the calculations
    if(op.equals("Sum")) {
      findSum();
    }
    else if(op.equals("Area")) { // find the area
      findArea();
    }
    else if(op.equals("S & A")) { // do both
      findSum();
      findArea();
    }
    else if(op.equals("FP")) { // calculate the polarization
      findPolarization();
    }
    
    // print the results now
    transformDialog.setStatus(100, buffer.toString());
  }
  
  // Method to calculate the area
  private void findSum() {
    for(int i = 0; i < sdata.length; i++) {
      float[][] data = sdata[i].getData();
      float min_x = data[0][0];
      float max_x = data[data.length - 1][0];
      
      try {
        if(!minX.equals("min")) {
          min_x = Float.parseFloat(minX);
        }
        
        if(!maxX.equals("max")) {
          max_x = Float.parseFloat(maxX);
        }
      }
      catch(NumberFormatException nfe) { }
      
      // now do the actual calculation
      results[i] = getDataSum(data, min_x, max_x);
      
      if(i == 0) {
        min_value = results[0];
        max_value = results[0];
      }
      else {
        if(results[i] < min_value) {
          min_value = results[i];
        }
        
        if(results[i] > max_value) {
          max_value = results[i];
        }
      }
    }
    
    // prepare some to format the data
    NumberFormat nf = NumberFormat.getInstance();
    DecimalFormat df = (DecimalFormat) nf;
    df.setDecimalSeparatorAlwaysShown(true);
    
    // now print the data out
    buffer.append(">>Sum of data between ").append(minX).append(" and ").append(maxX).append('\n');
    buffer.append("Data\t Sum \t Sum/min \t Sum/max\n");
    for(int i = 0; i < sdata.length; i++) {
      String name = getXValue(sdata[i].getName(), i);
      buffer.append(name).append('\t');
      df.applyPattern("0.000E0");
      buffer.append(df.format(results[i])).append('\t');
      df.applyPattern("0.000");
      buffer.append(df.format(results[i]/min_value)).append('\t');
      buffer.append(df.format(results[i]/max_value)).append('\n');
    }
    buffer.append("---\n");
  }
  
  // function to get the sum of the data in a particular region
  private float getDataSum(float[][] data, float min_x, float max_x) {
    float sum = 0.0f;
    
    for(int i = 0; i < data.length; i++) {
      if(data[i][0] >= min_x && data[i][0] <= max_x) {
        sum += data[i][1];
      }
    }
    
    return sum;
  }
  
  // Method to find the area under a curve
  private void findArea() {
    for(int i = 0; i < sdata.length; i++) {
      float[][] data = sdata[i].getData();
      float min_x = data[0][0];
      float max_x = data[data.length - 1][0];
      
      try {
        if(!minX.equals("min")) {
          min_x = Float.parseFloat(minX);
        }
        
        if(!maxX.equals("max")) {
          max_x = Float.parseFloat(maxX);
        }
      }
      catch(NumberFormatException nfe) { }
      
      // now do the actual calculation
      results[i] = getDataArea(data, min_x, max_x);
      
      if(i == 0) {
        min_value = results[0];
        max_value = results[0];
      }
      else {
        if(results[i] < min_value) {
          min_value = results[i];
        }
        
        if(results[i] > max_value) {
          max_value = results[i];
        }
      }
    }
    
    // prepare some to format the data
    NumberFormat nf = NumberFormat.getInstance();
    DecimalFormat df = (DecimalFormat) nf;
    df.setDecimalSeparatorAlwaysShown(true);
    
    // now print the data out
    buffer.append(">>Area of data between ").append(minX).append(" and ").append(maxX).append('\n');
    buffer.append("Data\t Area \t Area/min \t Area/max\n");
    for(int i = 0; i < sdata.length; i++) {
      String name = getXValue(sdata[i].getName(), i);
      buffer.append(name).append('\t');
      df.applyPattern("0.000E0");
      buffer.append(df.format(results[i])).append('\t');
      df.applyPattern("0.000");
      buffer.append(df.format(results[i]/min_value)).append('\t');
      buffer.append(df.format(results[i]/max_value)).append('\n');
    }
    buffer.append("---\n");
  }
  
  //function to get the area of the data in a particular region
  private float getDataArea(float[][] data, float min_x, float max_x) {
    float area = 0.0f;
    float dx =(data[1][0] - data[0][0]);
    
    for( int i=0; i < data.length; i++) {
      float x_value = data[i][0];
      if(x_value >= min_x && x_value <= max_x && (i + 1) < data.length) {
        float leftSide = data[i][1];
        float rightSide = data[i + 1][1];
        area += dx*(leftSide + rightSide) / 2.0;
      }
    }
    
    return area;
  }
  
  // Method to find the polarization
  private void findPolarization() {
    buffer.append(">>Fluorescence Polarization (P) and Anistropy (r) Calculations\n")
    .append("P = (F_VV - F_VH)/(F_VV - F_VH) || r = (F_VV - F_VH)/((F_VV + 2F_VH)\n\n");
    
    // check to see that the data is loaded in pairs
    if((sdata.length % 2) != 0) {
      buffer.append("Error, can only do polarization measurements on data pairs ...\n");
      return;
    }
    
    for(int i = 0; i < sdata.length; i += 2) {
      float[][] data1 = sdata[i].getData();
      float[][] data2 = sdata[i + 1].getData();
      
      float min_x = data1[0][0];
      float max_x = data1[data1.length - 1][0];
      
      try {
        if(!minX.equals("min")) {
          min_x = Float.parseFloat(minX);
        }
        
        if(!maxX.equals("max")) {
          max_x = Float.parseFloat(maxX);
        }
      }
      catch(NumberFormatException nfe) { }
      
      // now do the actual calculation
      float area1 = getDataArea(data1, min_x, max_x); // area exciting and collecting parrall
      float area2 = getDataArea(data2, min_x, max_x); // area exciting and collecting perpendicular
      
      results[i] = area1;
      results[i + 1] = area2;
    }
    
    // prepare some to format the data
    NumberFormat nf = NumberFormat.getInstance();
    DecimalFormat df = (DecimalFormat) nf;
    df.setDecimalSeparatorAlwaysShown(true);
    
    // print out the results now
    buffer.append("Integrated from ").append(minX).append(" to ").append(maxX).append('\n');
    buffer.append("Data\t P \t r \n");
    
    for(int i = 0; i < sdata.length; i += 2) {
      float P = (results[i] - results[i + 1])/(results[i] + results[i + 1]);
      float r = (results[i] - results[i + 1])/(results[i] + 2*results[i + 1]);
      
      String name = sdata[i].getName();
      buffer.append(name).append('\t');
      df.applyPattern("0.000");
      buffer.append(df.format(P)).append('\t');
      buffer.append(df.format(r)).append('\n');
    }
    buffer.append("---\n");
  }
  
  // Method to get the xvalues
  private void setXValues() {
    if(!xUnits.equals("0,0")) {
      xValues = new String[sdata.length];
      NumberFormat nf = NumberFormat.getInstance();
      DecimalFormat df = (DecimalFormat) nf;
      df.setDecimalSeparatorAlwaysShown(true);
      df.applyPattern("0.000");
      
      String[] sa = xUnits.split(",");
      float x_start = Float.parseFloat(sa[0]);
      float x_inc = Float.parseFloat(sa[1]);
      
      if((x_start != 0 && x_start < 1.0e-3) || x_start >= 1.0e4) {
        df.applyPattern("0.000E0");
      }
      
      float x_value = x_start;
      for(int i = 0; i < xValues.length; i++) {
        x_value = x_start + i*x_inc;
        xValues[i] = df.format(x_value);
      }
    }
  }
  
  // Method to return the XValue
  private String getXValue(String dataName, int index) {
    String xvalue;
    int start_index = dataName.indexOf("[");
    int end_index = dataName.indexOf("]");
    
    if(xValues != null) {
       xvalue = xValues[index];
    }
    else if(start_index != -1 && end_index != -1) {
      String xvalueString = dataName.substring(start_index + 1, end_index);
      xvalue = xvalueString.trim();
    }
    else {
       xvalue = dataName;
    }
    
    return xvalue;
  }
}//--end class SumAreaThread
