import javax.swing.ButtonGroup;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import javax.swing.JPanel;
import javax.swing.JButton;
import java.util.prefs.*;
import java.io.File;
import java.io.PrintStream;
import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.commons.cli.*;
import com.lowagie.text.Font;
import com.lowagie.text.DocumentException;

import com.xinapse.apps.active.ROICalculation;
import com.xinapse.apps.active.SelectableROICalculation;
import com.xinapse.apps.active.ROIPropagateFrame;
import com.xinapse.image.PixelDataType;
import com.xinapse.image.ComplexMode;
import com.xinapse.image.ReadableImage;
import com.xinapse.multisliceimage.ImageName;
import com.xinapse.numerical.Correlation;
import com.xinapse.util.GridBagConstrainer;
import com.xinapse.util.LocaleIndependentFormats;
import com.xinapse.util.ImageOrganiserFrame;
import com.xinapse.util.PreferencesSettable;
import com.xinapse.util.ReportGenerator;
import com.xinapse.util.PdfReportGenerator;
import com.xinapse.util.InvalidArgumentException;
import com.xinapse.graph.*;
import com.xinapse.multisliceimage.roi.*;

/**
   Classes that perform calculations on propagated ROIs must extend SelectableROICalculation.

   This example class simply sums up the areas of all ROIs for the individual slices and
   time points, and outputs them to a file called "Areas.txt" in the current folder.
*/
public class ROIArea extends SelectableROICalculation {

  /** Whether a PDF report is to be created - ignored in the example. */
  private final boolean pdfReport;
  /** Whether verbose reporting to System.out is turned on. */
  private final boolean verbose;

  /**
     Returns the name of this calculation, which appears in the tabbed pane to select the
     calculation.

     @return the name of this calculation.
  */
  @Override public String getCalculationName() {
    return("ROI Area");
  }

  /**
     Returns a short (normally one word) description of the calculation.

     @return a short description of the calculation.
  */
  @Override public String getCalculationDescription() {
    return("area");
  }

  /**
     Returns the name to be used when selecting this calculation from the command line.

     @return the name used for selecting this calculation from the command line.
  */
  public static String getOptionName() {
    return("area");
  }

  /**
     Returns the array of options that may be selected with this calculation.
     In this simple case, there are no options, so it returns an array of length zero.

     @return the array of options that may be selected with this calculation.
  */
  public static Option[] getCalcOptions() {
    return(new Option[0]);
  }

  /**
     A public constructor that takes no arguments must be supplied.
  */
  public ROIArea() {
    this.pdfReport = false;
    this.verbose = false;
  }

  /**
     Constructor used by command-line version of the tool.

     @param commandLine the command line (for the command-line version of the tool).
     @param pdfReport whether a PDF repost has been requested.
     @param verbose whether verbose reprting to System.out is turned on.
  */
  public ROIArea(CommandLine commandLine, boolean pdfReport, boolean verbose) {
    this.pdfReport = pdfReport;
    this.verbose = verbose;
  }

  /**
     Performs the calculation on the ROIs.

     @param parentFrame if non-null, the ROIPropagateFrame from which the calculation was
     inititated.
     @param rois and array of ROIs. The first index refers to the slice number; the second
     index to the time point; and the third index to the ROI.
     @param inputImages the input images.
     @param nCols the number of columns of pixels in the input images.
     @param nRows the number of rows of pixels in the input images.
     @param pixelXSize the pixel width in mm.
     @param pixelYSize the pixel height in mm.
  */
  @Override public void doCalc(ROIPropagateFrame parentFrame, ROI[][][] rois,
                               ReadableImage[] inputImages,
                               int nCols, int nRows, float pixelXSize, float pixelYSize) {

    int nSliceLocations = rois.length;
    int nTimes = rois[0].length;

    // Create the output file in the current folder.
    PrintStream areasOutputStream;
    try {
      areasOutputStream = new PrintStream(new FileOutputStream("Areas.txt"));
    }
    catch (IOException ioE) {
      javax.swing.JOptionPane.showMessageDialog(parentFrame, ioE.getMessage());
      return;
    }

    for (int slice = 0; slice < nSliceLocations; slice++) {
      // Get the number of ROIs for this slice. The number of ROIs will be the same at all
      // time points.
      int nROIs = rois[slice][0].length;
      if (verbose) {
        System.out.println("Slice " + Integer.toString(slice+1));
      }
      areasOutputStream.println("Slice " + Integer.toString(slice+1));

      for (int tIndex = 0; tIndex < nTimes; tIndex++) {
        // The total area of all ROIs at this time point.
        double area = 0;
        for (int iROI = 0; iROI < nROIs; iROI++) {
          // Add this ROI's area.
          area += rois[slice][tIndex][iROI].getStats((Object) null,
                                                     PixelDataType.SHORT,
                                                     nCols, nRows, 0, pixelXSize, pixelYSize,
                                                     (ComplexMode) null).area;
        }
        if (verbose) {
          System.out.println("Time point " + Integer.toString(tIndex+1) + " area=" + area);
        }
        areasOutputStream.println("Time point " + Integer.toString(tIndex+1) + " area=" + area);
      }
    }
    areasOutputStream.close();
  }

  /**
     This panel will appear as one of the selectable calculation tabs.

     @param parentFrame the ROIPropagateFrame in which the tab will appear.
     @param preferencesNodeName the preferences node name to used if this calculation needs
     to save any of its settings.
  */
  @Override public ROICalculation.SpecifierPanel getSpecifierPanel(ROIPropagateFrame parentFrame,
                                                                   String preferencesNodeName) {
    return(new Panel(parentFrame, preferencesNodeName));
  }

  /**
     The ROICalculation.SpecifierPanel used to setup this calculation. In this simple case there
     is nothing to setup, so it just contains a simple label to say what the calculation does.
     It could, for example, have a text field to select the output file name.
  */
  public static class Panel extends ROICalculation.SpecifierPanel {

    /**
       Creates a new ROICalculation.SpecifierPanel.

       @param parentFrame the ROIPropagateFrame in which the panel tab will appear.
       @param preferencesNodeName the preferences node name to used if this calculation needs
       to save any of its settings.
    */
    public Panel(ROIPropagateFrame parentFrame, String preferencesNodeName) {
      super(parentFrame);
      this.add(new javax.swing.JLabel("Calculates ROI areas"));
    }

    /**
       Returns the calculation as set up in this panel.

       @erturn the calculation.
    */
    @Override public ROIArea getCalc() {
      return(new ROIArea((CommandLine) null, false /* no PDF report */,
                         false /* not verbose */));
    }

    /**
       Sets the defaults for this calculation.
       In this case, there are no options that can be changed,
    */
    @Override public void setDefaults() {
    }

    /**
       Saves the settings for this calculation.
       In this case, there are no options that can be saved,

       @param prefs the Preferences where the settings are to be saved.
    */
    @Override public void savePreferences(Preferences prefs) {
    }

    /**
       Shows an error message using the parent frame's showError method.

       @param message the error message to show.
    */
    @Override public void showError(String message) {
      parentFrame.showError(message);
    }
  }
}
