package ij.plugin.filter;
import ij.*;
import ij.process.*;
import ij.gui.*;
import ij.measure.ResultsTable;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.ArrayList;

/** Displays the active image's look-up table.
* Implements the Image/Color/Show LUT command.
*/
public class LutViewer implements PlugInFilter {
	private double guiScale = Prefs.getGuiScale();
	private ImagePlus imp;
	
	public int setup(String arg, ImagePlus imp) {
		this.imp = imp;
		return DOES_ALL+NO_UNDO+NO_CHANGES;
	}

	public void run(ImageProcessor ip) {
		if (ip.getNChannels()==3) {
			IJ.error("RGB images do not have LUTs.");
			return;
		}
		int xMargin = (int)(35*guiScale);
		int yMargin = (int)(20*guiScale);
		int width = (int)(256*guiScale);
		int height = (int)(128*guiScale);
		int x, y, x1, y1, x2, y2;
		int imageWidth, imageHeight;
		int barHeight = (int)(12*guiScale);
		boolean isGray;

        ip = imp.getChannelProcessor();
        IndexColorModel cm = (IndexColorModel)ip.getColorModel();
        LookUpTable lut = new LookUpTable(cm);
		int mapSize = lut.getMapSize();
		byte[] reds = lut.getReds();
		byte[] greens = lut.getGreens();
		byte[] blues = lut.getBlues();
        isGray = lut.isGrayscale();

		imageWidth = width + 2*xMargin;
		imageHeight = height + 3*yMargin;
		Image img = IJ.getInstance().createImage(imageWidth, imageHeight);
		Graphics2D g = (Graphics2D)img.getGraphics();
		g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
		g.setFont(new Font("SansSerif",Font.PLAIN,(int)(12*guiScale)));
		g.setColor(Color.white);
		g.fillRect(-1, 0, imageWidth, imageHeight);
		g.setColor(Color.black);
		g.drawRect(xMargin, yMargin-1, width+1, height+1);

		if (isGray)
			g.setColor(Color.black);
		else
			g.setColor(Color.red);

		boolean drawSteps = width > mapSize;		//more than 1 pxl per color
		double xShift = drawSteps ? 0.5 : 0.0;		//when drawing steps, vertical lines are at half-integer positions
		x1 = scaledX(-0.5, xMargin, width, mapSize);	//for drawing steps, we need the x where the previous color would end
		y1 = yMargin + height - 1 - (int)Math.round(((reds[0]&0xff)-0.5)*guiScale/2);
		for (int i=0; i<mapSize; i++) {				// R E D   or   G R A Y S C A L E
			x2 = scaledX(i+xShift, xMargin, width, mapSize);
			y2 = yMargin + height - 1 - (int)Math.round(((reds[i]&0xff)-0.5)*guiScale/2);
			if (drawSteps) {
				if (i>0) g.drawLine(x1, y1, x1, y2);
				g.drawLine(x1, y2, x2, y2);
			} else if (i>0)
				g.drawLine(x1, y1, x2, y2);
			x1 = x2;
			y1 = y2;
		}

		if (!isGray) {								// G R E E N
			g.setColor(Color.green);
			x1 = scaledX(-0.5, xMargin, width, mapSize);
			y1 = yMargin + height - 1 - (int)Math.round(((greens[0]&0xff)-0.5)*guiScale/2);
			for (int i=0; i<mapSize; i++) {
			x2 = scaledX(i+xShift, xMargin, width, mapSize);
				y2 = yMargin + height - 1 - (int)Math.round(((greens[i]&0xff)-0.5)*guiScale/2);
				if (drawSteps) {
					if (i>0) g.drawLine(x1, y1, x1, y2);
					g.drawLine(x1, y2, x2, y2);
				} else if (i>0)
					g.drawLine(x1, y1, x2, y2);
				x1 = x2;
				y1 = y2;
			}

			g.setColor(Color.blue);					// B L U E
			x1 = scaledX(-0.5, xMargin, width, mapSize);
			y1 = yMargin + height - 1 - (int)Math.round(((blues[0]&0xff)-0.5)*guiScale/2);
			for (int i=0; i<mapSize; i++) {
				x2 = scaledX(i+xShift, xMargin, width, mapSize);
				y2 = yMargin + height - 1 - (int)Math.round(((blues[i]&0xff)-0.5)*guiScale/2);
				if (drawSteps) {
					if (i>0) g.drawLine(x1, y1, x1, y2);
					g.drawLine(x1, y2, x2, y2);
				} else if (i>0)
					g.drawLine(x1, y1, x2, y2);
				x1 = x2;
				y1 = y2;
			}
		}

		x = xMargin;
		y = yMargin + height + (int)Math.round(2*guiScale);
		lut.drawColorBar(g, x, y, width, barHeight);
		
		y += barHeight + (int)(15*guiScale);
		g.setColor(Color.black);
		g.drawString("0", x-(int)(4*guiScale), y);
		g.drawString(""+(mapSize-1), x+width - (int)(10*guiScale), y);
		g.drawString("255", (int)(7*guiScale), yMargin + (int)(4*guiScale));
		g.dispose();
		
        ImagePlus imp = new ImagePlus("Look-Up Table", img);
        new LutWindow(imp, new ImageCanvas(imp), ip);
    }

	private int scaledX(double x, int xMargin, int width, int mapSize) {
		return xMargin + (int)Math.round(0.5 + (x+0.5)*width*(1.0/mapSize));
	}

} // LutViewer class

class LutWindow extends ImageWindow implements ActionListener {

	private Button button;
	private ImageProcessor ip;

	LutWindow(ImagePlus imp, ImageCanvas ic, ImageProcessor ip) {
		super(imp, ic);
		this.ip = ip;
		addPanel();
	}

	void addPanel() {
		Panel panel = new Panel();
		panel.setLayout(new FlowLayout(FlowLayout.RIGHT));
		button = new Button(" List... ");
		button.addActionListener(this);
		panel.add(button);
		add(panel);
		pack();
	}
	
	public void actionPerformed(ActionEvent e) {
		Object b = e.getSource();
		if (b==button)
			list(ip);
	}

	void list(ImageProcessor ip) {
		IndexColorModel icm = (IndexColorModel)ip.getColorModel();
		int size = icm.getMapSize();
		byte[] r = new byte[size];
		byte[] g = new byte[size];
		byte[] b = new byte[size];
		icm.getReds(r); 
		icm.getGreens(g); 
		icm.getBlues(b);		
		ResultsTable rt = new ResultsTable();
		for (int i=0; i<size; i++) {
      		rt.setValue("Index", i, i);
      		rt.setValue("Red", i, r[i]&255);
      		rt.setValue("Green", i, g[i]&255);
      		rt.setValue("Blue", i, b[i]&255);
      	}
		rt.show("LUT");
	}

} // LutWindow class


