package ij.plugin.filter;
import ij.*;
import ij.gui.*;
import ij.process.*;
import ij.measure.*;
import ij.util.*;
import ij.plugin.frame.ContrastAdjuster;
import java.awt.*;
import java.util.*;

/** This plugin implements the Image/Lookup Tables/Apply LUT command. */
public class LutApplier implements PlugInFilter {
    ImagePlus imp;
    int min, max;
    boolean canceled;

    public int setup(String arg, ImagePlus imp) {
        this.imp = imp;
        int baseOptions = DOES_8G+DOES_8C+DOES_RGB+SUPPORTS_MASKING;
        if (imp!=null && imp.getType()==ImagePlus.COLOR_RGB)
            return baseOptions+NO_UNDO;
        else
            return baseOptions;
    }

    public void run(ImageProcessor ip) {
        apply(imp, ip);
    }
    
    void apply(ImagePlus imp, ImageProcessor ip) {
        if (ip.getMinThreshold()!=ImageProcessor.NO_THRESHOLD) {
            imp.unlock();
            IJ.runPlugIn("ij.plugin.Thresholder", "skip");
            return;
        }
        min = (int)ip.getMin();
        max = (int)ip.getMax();
        if (min==0 && max==255) {
                IJ.error("Apply LUT", "The display range must first be updated\n"
                +"using Image>Adjust>Brightness/Contrast\n"
                +"or threshold levels defined using\n"
                +"Image>Adjust>Threshold.");
                return;
        }
        if (imp.getType()==ImagePlus.COLOR_RGB) {
            if (imp.getStackSize()>1)
                applyRGBStack(imp);
            else {
                ip.reset();
                Undo.setup(Undo.TRANSFORM, imp);
                ip.setMinAndMax(min, max);
                //ip.snapshot();
            }
            if (canceled) ip.reset();
            resetContrastAdjuster();
            return;
        }
        ip.resetMinAndMax();
        int[] table = new int[256];
        for (int i=0; i<256; i++) {
            if (i<=min)
                table[i] = 0;
            else if (i>=max)
                table[i] = 255;
            else
                table[i] = (int)(((double)(i-min)/(max-min))*255);
        }
        if (imp.getStackSize()>1) {
            ImageStack stack = imp.getStack();
            
            int flags = IJ.setupDialog(imp, 0);
            if (flags==PlugInFilter.DONE)
                {ip.setMinAndMax(min, max); return;}
            if (flags==PlugInFilter.DOES_STACKS) {
                new StackProcessor(stack, ip).applyTable(table);
                Undo.reset();
            } else
                ip.applyTable(table);
        } else
            ip.applyTable(table);
        resetContrastAdjuster();
    }
    
    void resetContrastAdjuster() {
        Frame frame = WindowManager.getFrame("B&C");
        if (frame==null)
            frame = WindowManager.getFrame("W&L");
        if (frame!=null && (frame instanceof ContrastAdjuster))
            ((ContrastAdjuster)frame).updateAndDraw();
    }

    void applyRGBStack(ImagePlus imp) {
        int current = imp.getCurrentSlice();
        int n = imp.getStackSize();
        if (!IJ.showMessageWithCancel("Update Entire Stack?",
        "Apply brightness and contrast settings\n"+
        "to all "+n+" slices in the stack?\n \n"+
        "NOTE: There is no Undo for this operation.")) {
            canceled = true;
            return;
        }
        for (int i=1; i<=n; i++) {
            if (i!=current) {
                imp.setSlice(i);
                ImageProcessor ip = imp.getProcessor();
                ip.setMinAndMax(min, max);
                IJ.showProgress((double)i/n);
            }
        }
        imp.setSlice(current);
    }
    
}