import com.xinapse.apps.perfusion.DCEMRIModel;
import com.xinapse.apps.perfusion.AbstractDynamicContrastResult;
import com.xinapse.apps.perfusion.AbstractDynamicWorker;
import com.xinapse.dynamic.AutoCorrelationEstimate;
import com.xinapse.util.ReportGenerator;
import com.lowagie.text.DocumentException;

import com.xinapse.util.MonitorWorker;
import com.xinapse.apps.perfusion.AIF;

/**
   Simple example plugin for DCE-MRI tool to calculate the maximum upslope.
*/
public class Upslope extends DCEMRIModel {

  /**
     Create a new Upslope model. You must provide a constructor that has no arguments.
  */
  public Upslope() {
    // The super-class constructor takes 4 arguments:
    // 1. The name of the model.
    // 2. A short description of the model that appears in tooltips etc.
    // 3. A array of the names of parameters that are calculated. In this example, only a
    //    single parameter is calculated.
    // 4. Array of the names of the units that apply to the calculated parameters.
    super("Upslope", "peak upslope", new String[] {"MaxSlope"}, new String[] {"mmol/s"});
  }

  /**
     Returns the name that is used to select this model when running DCE-MRI from the command-line.
     There must be no clash between this option specifier and those for other models in use.
  */
  @Override public String getOptionSpecifier() {
    return("u");
  }

  /**
     Calculate the result for one pixel for this model.

     If needed for your model fitting, you can access the AIF (plasma concentration values
     in the feeding artery) as the instance variable Cpa.

     @param Ct the time-series of concentration values for this pixel.
     @param col the pixel column number - unused.
     @param row the pixel row number - unused.
     @param slice the pixel slice number - unused.
     @param autoCorrelationEstimate will be null since DCE-MRI models do not use
     auto-correlation estimates.
     @param worker if non-null, the MonitorWorker that may be used to cancel the operation.
  */
  @Override public AbstractDynamicContrastResult
    fit(float[] Ct, int col, int row, int slice, AutoCorrelationEstimate autoCorrelationEstimate,
        MonitorWorker worker) {

    // The maximum concentration gradient found.
    float maxSlope = 0;
    // The intercept with the y-axis.
    float intercept = 0;
    // The maximum concentration found.
    float maxConc = Ct[0];
    for (int i = 1; i < Ct.length; i++) {
      float slope = Ct[i] - Ct[i-1];
      if (slope > maxSlope) {
        // Record the maximum slope in the concentration values.
        maxSlope = slope;
        // Also record the intercept with the y-axis.
        intercept = Ct[i] - (maxSlope * i);
      }
      if (Ct[i] > maxConc) {
        // Record the maximum concentration.
        maxConc = Ct[i];
      }
    }

    // This model does not "fit" to the data, so there are no fitted concentration values.
    // However, we provide a visual indication by plotting the slope.
    float[] fittedCt = new float[Ct.length];
    for (int i = 0; i < Ct.length; i++) {
      float conc = (maxSlope * i) + intercept;
      if (conc < 0) {
        fittedCt[i] = 0;
      }
      else if (conc <= maxConc) {
        fittedCt[i] = conc;
      }
      else {
        fittedCt[i] = maxConc;
      }
    }
    // This method returns the time between samples set in the DCE-MRI tool.
    float dt = getDt();
    // Calculate the slope as the difference in concentration divided by the time between images.
    return(new UpslopeResult(maxSlope/dt, fittedCt));
  }

  /**
     This model does not compute the root-mean-square difference between the model and the data.

     @return false.
  */
  @Override public boolean computesRMSDiff() {
    return(false);
  }

  /**
     A result for the fitting using Upslope.
  */
  public class UpslopeResult extends AbstractDynamicContrastResult {

    /**
       Create a new UpslopeResult.

       @param slope the maximum slope value calculated.
       @param fittedCt the data that will be shown along with data to indicate the model fit.
       This data will be shown in reports.
    */
    UpslopeResult(float slope, float[] fittedCt) {
      super(new Upslope(), new float[] {slope}, 0.0f, fittedCt);
    }

    /**
       Returns the title of this model to be used in dialogs and reports.

       @return a title.
    */
    @Override public String getResultTitle() {
      return("Maximum Upslope");
    }


    /**
       You can use this method to add extra text to a PDF or text report generated when
       you perform ROI analysis.

       @param reportGenerator the generator of the report.
       @param dynamicWorker the AbstractDynamicWorker that generated the report.
       @param concTissue the calculated tissue concentration values.
       @param aif the plasma contrast agent concentration values in the feeding artery.

       @throws DocumentException if an error occurs when writing to the report.
    */
    @Override public void writeReportBody(ReportGenerator reportGenerator,
                                          AbstractDynamicWorker dynamicWorker,
                                          float[] concTissue, AIF aif)
      throws DocumentException {

      // You can add some text to your report like this:
      reportGenerator.addParagraph("this text will appear in the report");
    }
  }
}
