package ij.plugin;
import ij.IJ;
import ij.ImagePlus;
import ij.ImageStack;
import ij.process.*;
import ij.gui.Roi;
import ij.plugin.filter.ThresholdToSelection;
import ij.plugin.frame.RoiManager;
import java.awt.Rectangle;
import java.util.ArrayList;

/** This class interpolates between ROIs in the ROI Manager.
 * @author Michael Doube
 * @author Johannes Schindelin
*/
public class RoiInterpolator implements PlugIn {
    int[][] idt;
    int w, h;

    public void run(String arg) {
        RoiManager roiman = RoiManager.getInstance();
        if (roiman==null || roiman.getCount()<2){
            IJ.error("RoiInterpolator", "Please populate the ROI Manager with at least two ROIs");
            return;
        }
        Roi[] rois = roiman.getRoisAsArray();
        int xmax = 0;
        int xmin = Integer.MAX_VALUE;
        int ymax = 0;
        int ymin = Integer.MAX_VALUE;
        int zmax = 1;
        int zmin = Integer.MAX_VALUE;
        ArrayList<Integer> templateSlices = new ArrayList<Integer>();
        for (Roi roi : rois){
            int slice = roiman.getSliceNumber(roi.getName());
            if (!templateSlices.contains(Integer.valueOf(slice)))
                templateSlices.add(Integer.valueOf(slice));
            if (slice==0) //ignore non-slice associated ROIs
                continue;
            zmin = Math.min(slice, zmin);
            zmax = Math.max(slice, zmax);
            Rectangle bounds = roi.getBounds();
            xmin = Math.min(xmin, bounds.x);
            ymin = Math.min(ymin, bounds.y);
            xmax = Math.max(xmax, bounds.x + bounds.width);
            ymax = Math.max(ymax, bounds.y + bounds.height);
        }
        if (templateSlices.size()<2) {
            IJ.error("RoiInterpolator", "ROIs are all on the same slice, nothing to interpolate");
            return;
        }
        //create the binary stack
        final int stackW = xmax - xmin + 1;
        final int stackH = ymax - ymin + 1;
        final int nSlices = zmax - zmin + 1;
        ImageStack stack = new ImageStack(stackW, stackH);
        for (int s=0; s<nSlices; s++){
            ByteProcessor bp = new ByteProcessor(stackW, stackH);
            bp.setColor(255);
            for (Roi roi : rois){
                int slice = roiman.getSliceNumber(roi.getName());
                if (slice==zmin+s){
                    Rectangle bounds = roi.getBounds();
                    roi.setLocation(bounds.x - xmin, bounds.y - ymin);
                    bp.setRoi(roi);
                    if (roi.getType() == Roi.RECTANGLE)
                        bp.fill();
                    else 
                        bp.fill(roi);
                }
            }
            stack.addSlice(""+s, bp);
        }
        //do the binary interpolation
        BinaryInterpolator bi = new BinaryInterpolator();
        bi.run(stack);
        ImagePlus binary = new ImagePlus("interpolated", stack);

        //get the ROIs
        ThresholdToSelection ts = new ThresholdToSelection();
        ts.setup("", binary);
        for (int s=0; s<nSlices; s++) {
            if (templateSlices.contains(Integer.valueOf(s+zmin)))
                continue;
            ImageProcessor bp = stack.getProcessor(s+1);
            int threshold = 255;
            bp.setThreshold(threshold, threshold, ImageProcessor.NO_LUT_UPDATE);
            Roi roi = ts.convert(bp);
            if (roi==null) {
                IJ.error("RoiInterpolator", "Unable to interpolate slice "+(s+1)+". More\nintermediate ROIs needed.");
                return;
            }
            roi.setPosition(s+zmin);
            Rectangle bounds = roi.getBounds();
            roi.setLocation(bounds.x+xmin, bounds.y+ymin);
            roiman.addRoi(roi);
        }
        for (Roi roi : rois){
            Rectangle bounds = roi.getBounds();
            roi.setLocation(bounds.x+xmin, bounds.y+ymin);
        }
        roiman.runCommand("sort");
        IJ.showStatus("ROIs interpolated");
    }
}