/*
 * Lut_Panel.java
 *
 * Created on 3 mars 2003, 16:04 Copyright (C) 2003 Patrick Pirrotte
 * ImageJ plugin
 * Version  : 2.1
 * Author   : Patrick Pirrotte
 *            written for the IBMP-CNRS Strasbourg(France)
 * Email    : patrick.pirrotte@gmx.net, jerome.mutterer@ibmp-ulp.u-strasbg.fr
 * Description :    Lut_Panel extends the LUT capabilities of ImageJ. It is especially useful
 *                  for microscopists: a red, green or blue gradient palette can be applied
 *                  with a click. Gradient LUTs can be defined with a starting and an ending color
 *                  and very easily pasted into the actual picture. Lut_Panel also implements a simple
 *                  Palette editor.
 *                  Please send bug reports and wishes to the above email address.
 *
 * Release History :
 *      
 *      
 *      19.3.2003 : v2.1 Preview functions for gradients (on request) and Lut Editor
 *      15.3.2003 : v2.0 gradient indexes can now be defined
 *      9.3.2003 : v1.0 import, export, fast R/G/B-gradient , user defined gradient (evened)
 *
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
 

// specific of WholeNumberField
import java.awt.Toolkit;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
import javax.swing.text.*; 
// specific end

import java.io.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import java.awt.Color.*;
import java.awt.geom.Rectangle2D;

import java.util.Arrays; //for sorting
import java.lang.Object;
import ij.text.TextWindow;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.colorchooser.*;

import ij.*;
import ij.io.*;
import ij.process.*;
import ij.plugin.*;
import ij.plugin.frame.*;
import ij.plugin.PlugIn;
import ij.text.TextWindow;

/* Lut_Panel class start
 * Main plugin class, (entry point)
 */

public class Lut_Panel implements PlugIn {

    public GUI theGUI;
    public Color_Chooser color_picker;
    public Lut_Edit lut_edit;
    public int initial_tooltip_delay;
    /* ImageJ plugin entry point of Lut_Panel */
    
    public void run(String args) {
       if (args.equals("about")){
                showAbout();
            } else {
                IJ.showStatus("Plugin Lut_Panel started.");
                theGUI = new GUI();
                theGUI.init();
                color_picker = new Color_Chooser();
                color_picker.colorFrame.setModal(true);
                lut_edit = new Lut_Edit();
                lut_edit.editFrame.setModal(true);
                initial_tooltip_delay = ToolTipManager.sharedInstance().getInitialDelay();
            }
    }

    void showAbout() {
        IJ.showMessage("About Lut_Panel",
        "Lut_Panel v.2.1, Copyright (C) 2003 Patrick PIRROTTE\n"+
        "written for the IBMP-CNRS Strasbourg(France)\n"+
        "Email     : patrick.pirrotte@gmx.net, jerome.mutterer@ibmp-ulp.u-strasbg.fr\n"+
        "Lut_Panel comes with ABSOLUTELY NO WARRANTY; It is licensed\n"+
        "under the GNU General Public License. You should have received\n"+
        "a copy of the GNU General Public License along with this program.\n"+
        "If not, write to the Free Software Foundation, Inc., 59 Temple Place\n"+
        "- Suite 330, Boston, MA  02111-1307, USA.\n"+
        "\n"+
        "Lut_Panel extends the LUT capabilities of ImageJ. It is especially useful\n"+
        "for microscopists: a red, green or blue gradient palette can be applied \n"+ 
        "with a click. Gradient LUTs can be defined with a starting and an ending color\n"+
        "and very easily pasted into the actual picture. Lut_Panel also implements a simple\n"+
        "Palette editor.\n\n"+
        "Please send bug reports and wishes to the above email address.\n"
        );
    }

/* class GUI start
 * GUI creates a panel with buttons
 */
    public class GUI {
        public JFrame baseFrame;
        private JPanel pan;
        private GridLayout baseGridLayout = new GridLayout(8,1,10,2);
        private Dimension ScreenDimension = Toolkit.getDefaultToolkit().getScreenSize();
        private int ScreenX = (int) ScreenDimension.getWidth();
        private int ScreenY = (int) ScreenDimension.getHeight();
        private int baseFrameXsize = (int)(ScreenX/8);
        private int baseFrameYsize = (int)(ScreenY/4);
        private int baseFrameXlocation = (int)((11*ScreenX/12) - baseFrameXsize);
        private int baseFrameYlocation = (int)((8.5*ScreenY/12) - baseFrameYsize);
  
        private smallButton red_button = new smallButton("R","replace LUT with a generic red LUT","red");
        private smallButton green_button = new smallButton("G","replace LUT with a generic green LUT","green");
        private smallButton blue_button = new smallButton("B","replace LUT with a generic blue LUT","blue");
        private smallButton import_lut_button = new smallButton("Import LUT","Apply LUT from imported .txt","");
        private smallButton export_lut_button = new smallButton("Export LUT","Export LUT to .txt","");
        private smallButton gradient_lut_button = new smallButton("Gradient LUT","Apply gradient LUT","");
        private smallButton edit_lut_button = new smallButton("Edit LUT","Check/Edit LUT","");
        private smallButton exit_button = new smallButton("Exit","Exit LUT Panel","");
        
        /** Initiates the GUI, setting its layout*/
        public void init() {
            baseFrame = new JFrame();
            baseFrame.setTitle("LUT Panel 2.1");
            baseFrame.setSize(baseFrameXsize,baseFrameYsize);
            baseFrame.setResizable(false);
            baseFrame.setLocation(baseFrameXlocation,baseFrameYlocation);
            baseFrame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
            pan = new JPanel();
            pan.setSize(baseFrameXsize, baseFrameYsize);
            pan.setForeground(SystemColor.window);
            pan.setLayout(baseGridLayout);
            
            pan.add(red_button);
            pan.add(green_button);
            pan.add(blue_button);
            pan.add(import_lut_button);
            pan.add(export_lut_button);
            pan.add(gradient_lut_button);
            pan.add(edit_lut_button);
            pan.add(exit_button);
            baseFrame.getContentPane().add(pan);
            
            addRedListener(red_button, baseFrame);
            addGreenListener(green_button, baseFrame);
            addBlueListener(blue_button, baseFrame);
            addImportListener(import_lut_button, baseFrame);
            addExportListener(export_lut_button, baseFrame);
            addGradientListener(gradient_lut_button, baseFrame);
            addEditListener(edit_lut_button, baseFrame);
            addExitListener(exit_button, baseFrame);
            
            baseFrame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                    lut_edit.editFrame.dispose();
                    color_picker.colorFrame.dispose();
                    baseFrame.dispose();
                }
            }
            );
        baseFrame.show();
        }
        
        /* Action listeners for the buttons*/
        
        private void addRedListener(final JButton button, final JFrame parent) {
            button.addActionListener(new ActionListener () {
            public void actionPerformed(ActionEvent e) {
            IJ.runPlugIn("ij.plugin.LutLoader", "red");
            }
        });
        }
        
        private void addGreenListener(final JButton button, final JFrame parent) {
            button.addActionListener(new ActionListener () {
            public void actionPerformed(ActionEvent e) {
            IJ.runPlugIn("ij.plugin.LutLoader", "green");
            }
        });
        }
        
        private void addBlueListener(final JButton button, final JFrame parent) {
            button.addActionListener(new ActionListener () {
            public void actionPerformed(ActionEvent e) {
            IJ.runPlugIn("ij.plugin.LutLoader", "blue");
            }
        });
        }
        
        private void addImportListener(final JButton button, final JFrame parent) {
            button.addActionListener(new ActionListener () {
            public void actionPerformed(ActionEvent e) {
               read_lut();
            }
        });
        }
        
        private void addExportListener(final JButton button, final JFrame parent) {
            button.addActionListener(new ActionListener () {
            public void actionPerformed(ActionEvent e) {
                String fname = WindowManager.getCurrentImage().getTitle();
                SaveDialog sd = new SaveDialog("Save LUT to...",fname,".lut");
                if (fname!=null) {
		        String directory = sd.getDirectory();
                        String path = directory+fname+".txt";
                        File file = new File(path);
                        ImagePlus imp = WindowManager.getCurrentImage();
                        imp.startTiming();
                        export_lut(file);
                    }
            }
        });
        }
        
        private void addGradientListener(final JButton button, final JFrame parent) {
            button.addActionListener(new ActionListener () {
            public void actionPerformed(ActionEvent e) {
            if (WindowManager.getCurrentImage().getFileInfo().getBytesPerPixel()!=1){
                    IJ.error("Only works on 8 bit images");
                    return;
                }
                if (color_picker.colorFrame.isShowing()== false)
                    color_picker.colorFrame.show();
                        else 
                    color_picker.colorFrame.setVisible(false);
            }
        });
        }
        
        private void addEditListener(final JButton button, final JFrame parent) {
            button.addActionListener(new ActionListener () {
            public void actionPerformed(ActionEvent e) {
                if (WindowManager.getCurrentImage().getFileInfo().getBytesPerPixel()!=1){
                    IJ.error("Only works on 8 bit images");
                    return;
                }
                if (lut_edit.editFrame.isShowing()== false){
                    lut_edit.update_lut_edit();
                    lut_edit.editFrame.show();
                } else 
                    lut_edit.editFrame.setVisible(false);
            }
        });
        }
        
        private void addExitListener(final JButton button, final JFrame parent) {
            button.addActionListener(new ActionListener () {
            public void actionPerformed(ActionEvent e) {
                color_picker.colorFrame.dispose();
                baseFrame.dispose();
            }
        });
        }

/* code written by Wayne Rasband, reads a lut with 3 or 4 columns, first line is
 * a header.
 */    
        
        public void read_lut() {
            if (WindowManager.getCurrentImage().getFileInfo().getBytesPerPixel()!=1){
                    IJ.error("Only works on 8 bit images");
                    return;
                }
            if (IJ.versionLessThan("1.26f"))
			return;
		TextReader tr = new TextReader();
		ImageProcessor ip = tr.open();
                
		if (ip==null)
			return;
		int width = ip.getWidth();
		int height = ip.getHeight();
		if (!((width==3||width==4)&&(height==256||height==257))) {
			IJ.showMessage("LUT Importer", "3 or 4 column text file required.\n"
				+"This file has "+width+" columns.");
			return;
		}
		int x = width==4?1:0;
		int y = 0;
		ip.setRoi(x, y, 3, 256);
		ip = ip.crop();
		//new ImagePlus("ip", ip).show();
		byte[] reds = new byte[256];
		byte[] greens = new byte[256];
		byte[] blues = new byte[256];
		for (int i=0; i<256; i++) {
			reds[i] = (byte)ip.getPixelValue(0,i);
			greens[i] = (byte)ip.getPixelValue(1,i);
			blues[i] = (byte)ip.getPixelValue(2,i);
		}
		IndexColorModel cm = new IndexColorModel(8, 256, reds, greens, blues);
		ImagePlus imp = WindowManager.getCurrentImage();
		if (imp==null)
			makeImage(tr.getName(), cm);
		else {
			imp.getProcessor().setColorModel(cm);
			imp.updateAndDraw();
		}
	}
        
        public void makeImage(String title, IndexColorModel cm) {
		int width = 256;
		int height = 32;
		byte[] pixels = new byte[width*height];
		ByteProcessor bp = new ByteProcessor(width, height, pixels, cm);
		int[] ramp = new int[width];
		for (int i=0; i<width; i++)
			ramp[i] = i; 
		for (int y=0; y<height; y++)
			bp.putRow(0, y, ramp, width);
		new ImagePlus(title, bp).show();
  	}
        
/*
 * End Wayne Rasband code
 */        

/*
 * Exports LUT into a text file 4 columns, with first line as header
 */
        public void export_lut(File file) {
                if (WindowManager.getCurrentImage().getFileInfo().getBytesPerPixel()!=1){
                    IJ.error("Only works on 8 bit images");
                    return;
                }
                ImagePlus imp = WindowManager.getCurrentImage();
                if (imp==null) IJ.error("8 bit image must be opened!");
		IndexColorModel icm = (IndexColorModel)imp.getProcessor().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);
		StringBuffer sb = new StringBuffer();
		String headings = "Index\tRed\tGreen\tBlue";
                try {
                PrintWriter out = new PrintWriter(new FileWriter(file));
                out.println(headings);
		for (int i=0; i<size; i++)
                    out.println(i+"\t"+(r[i]&255)+"\t"+(g[i]&255)+"\t"+(b[i]&255));
		out.close();
                } catch (IOException e1){
                    IJ.error("The file could not be opened for output!");
                } 
        }     
}
    
/* GUI class end*/

/* Color_Chooser class start
 * Color_Chooser shows a colorpicker panel and allows you to select to colors.
 * Those colors are the starting and ending colors of a gradient Lut that is applied
 * to the actual image
 */  
    
class Color_Chooser extends JDialog implements WindowListener{
        public JDialog colorFrame;
        private smallButton Apply_button = new smallButton("Apply","Apply gradient LUT","");
        private smallButton Preview_button = new smallButton("Preview","Preview gradient LUT","");
        private smallButton Cancel_button = new smallButton("Cancel","Cancel gradient LUT operation","");
        private Dimension ScreenDimension = Toolkit.getDefaultToolkit().getScreenSize();
        private int ScreenX = (int) ScreenDimension.getWidth();
        private int ScreenY = (int) ScreenDimension.getHeight();
        private int colorFrameXlocation = (int)(1*(ScreenX/12));
        private int colorFrameYlocation = (int)(4*(ScreenY/12));
        private DrawRect[] rect = new DrawRect[5];
        private Color[] color = new Color[5];
        private int selCol=0;
        private JCheckBox check = new JCheckBox();
        private float[] interval;
        private ButtonGroup cbg = new ButtonGroup();
        private JButton[] Define_button = new JButton[5];
        private JRadioButton[] cb = new JRadioButton[5];
        private WholeNumberField[] tf = new WholeNumberField[5];
        private FileInfo fi;
        
        public Color_Chooser() {
            colorFrame = new JDialog();
            colorFrame.setTitle("Pick distinct colors for gradient");
            colorFrame.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
            colorFrame.setResizable(false);
            colorFrame.setLocation(colorFrameXlocation,colorFrameYlocation);
            colorFrame.getContentPane().setLayout(new BorderLayout());
            
            JPanel panelGradient = new JPanel();
            JPanel panelColor = new JPanel();
            JPanel panelButton = new JPanel();                        
            
            panelColor.setForeground(SystemColor.window);
            panelColor.setLayout(new BorderLayout());
            JPanel gradient = new JPanel(new FlowLayout());
            JPanel panel = new JPanel(new GridLayout(5,2));
            interval = new float[5];
            for (int i = 0; i < 5; i++) {
                rect[i] = new DrawRect(0,0);
                gradient.add(rect[i]);
                color[i]= Color.white;
                tf[i] = new WholeNumberField(0,3);
                Define_button[i] = new JButton("Define color " + (i + 1)); 
                cb[i] = new JRadioButton((i + 1)+" Color(s)"); 
                cbg.add(cb[i]);
                panel.add(cb[i]);
                panel.add(Define_button[i]);
                panel.add(tf[i]);
                addButtonListener(Define_button[i],colorFrame);
                addcbListener(cb[i],colorFrame);
                tf[i].setEnabled(false);
            }
            check.setSelected(true);
            check.setText("Even automatically");
            cb[0].setVisible(false);
            cb[1].setSelected(true);
            tf[0].setBackground(Color.lightGray);
            for (int i=0;i<5;i++) if (cb[i].isSelected()) selCol=i;
            for (int i = 2; i < 5; i++){
                Define_button[i].setEnabled(false);
            }
            panelButton.add(Apply_button);
            panelButton.add(Preview_button);
            panelButton.add(Cancel_button);
            panelButton.add(check);
            
            panelColor.add(gradient,BorderLayout.NORTH);
            panelColor.add(panel,BorderLayout.CENTER);
            panelColor.add(panelButton,BorderLayout.SOUTH);
            
            addCheckListener(check,colorFrame);
            addApplyListener(Apply_button,colorFrame);
            addPreviewListener(Preview_button,colorFrame);
            addCancelListener(Cancel_button,colorFrame);
            colorFrame.getContentPane().add(panelColor);
            colorFrame.addWindowListener(this);
            colorFrame.pack();
        }
        
    // Window listeneres; essentially used for the Preview function, LUT is "saved"
    public void windowActivated(WindowEvent e) {
        fi = getLUT();
    }
    public void windowClosing(WindowEvent e) {
    }

    public void windowClosed(WindowEvent e) {
    }

    public void windowOpened(WindowEvent e) {
    }

    public void windowIconified(WindowEvent e) {
    }

    public void windowDeiconified(WindowEvent e) {
    }

    public void windowDeactivated(WindowEvent e) {
    }

    // Action listeners for the buttons 
        
    private void addApplyListener(final JButton button, final JDialog parent) {
                button.addActionListener(new ActionListener () {
                public void actionPerformed(ActionEvent e) {
                     /* selCol equals number of selected colors - 1!!!*/
                     gradient_show();
                     colorFrame.setVisible(false);
                }
        });
    }
    
    private void addPreviewListener(final JButton button, final JDialog parent) {
                button.addActionListener(new ActionListener () {
                public void actionPerformed(ActionEvent e) {
                     gradient_show();
                }
        });
    }
    private void addCancelListener(final JButton button, final JDialog parent) {
            button.addActionListener(new ActionListener () {
            public void actionPerformed(ActionEvent e) {
                if (fi!=null) setLUT(fi);
                colorFrame.setVisible(false);
           }
        });
    }
    
    private void addCheckListener(final JCheckBox button, final JDialog parent) {
            button.addActionListener(new ActionListener () {
            public void actionPerformed(ActionEvent e) {
                if (check.isSelected())
                     for (int i=0;i<=selCol;i++) {
                            tf[i].setEnabled(false);
                            tf[i].setValue(0);
                        }
                
                else {
                        for (int i=1;i<=selCol;i++) {
                            tf[i].setEnabled(true);
                        }
                        for (int i=selCol;i<5;i++) {
                            tf[i].setEnabled(false);
                        }
                        for (int i=0;i<=selCol-1;i++) tf[i].setValue(0);
                        tf[selCol].setValue(255);
                        for (int i=selCol+1;i<=5;i++) tf[i].setValue(0);
                }
                }
        });
    }
    
    private void addButtonListener(final JButton button, final JDialog parent) {
                button.addActionListener(new ActionListener () {
                public void actionPerformed(ActionEvent e) {
                    for (int i=0;i<5;i++) {
                       if (e.getSource()==Define_button[i]){
                           //selCol=i;
                           JColorChooser cc = new JColorChooser();
                           Color c = cc.showDialog(colorFrame,"Color Chooser", Color.red); 
                           if (c!=null) color[i]=c; else return;
                           rect[i].fillFace(c);
                        }
                    }
                }
        });
    }
    
    private void addcbListener(final JRadioButton button, final JDialog parent) {
                button.addActionListener(new ActionListener () {
                public void actionPerformed(ActionEvent e) {
                    selCol = 0;
                    for (int i=0;i<5;i++) {
                        if (e.getSource()==cb[i]){
                            selCol=i;
                            for (int j=0;j<=selCol;j++) {
                                Define_button[j].setEnabled(true);
                            }
                            for (int j=selCol+1;j<5;j++) {
                                Define_button[j].setEnabled(false);
                            }
                        }
                    }
                    if (check.isSelected())
                        
                        for (int i=0;i<=selCol;i++) {
                            tf[i].setEnabled(false);
                            tf[i].setValue(0);
                        }
                
                    else {
                        for (int i=1;i<=selCol;i++) {
                            tf[i].setEnabled(true);
                        }
                        for (int i=selCol;i<5;i++) {
                            tf[i].setEnabled(false);
                        }
                        for (int i=0;i<=selCol-1;i++) tf[i].setValue(0);
                        tf[selCol].setValue(255);
                        for (int i=selCol+1;i<=5;i++) tf[i].setValue(0);
                }
                }
        });
        }
        private void gradient_show(){
                    /* selCol equals number of selected colors - 1!!!*/
                    for (int i=0;i<=selCol;i++) interval[i]=(float)tf[i].getValue();
                    if (!check.isSelected()){
                        float[] temp = new float[5];   
                        java.lang.System.arraycopy(interval,0,temp,0,selCol+1);
                        Arrays.sort(temp,0,selCol);
                        String str;
                        boolean under256 = true;
                        boolean ascendent = true;
                        for (int i=0;i<=selCol;i++)
                            if (interval[i]>255)
                                under256 = false;
                         if (!under256) str= "Index values must be under 256 (8 bit LUT)!\n"; else str="";
                         if (!Arrays.equals(interval,temp)) {
                                ascendent = false;
                                str += "No increasing index values!";
                        }  else{
                                str +="";
                        }
                        if (!under256 || !ascendent) {
                            IJ.error(str);
                            return;
                        }
                     }
                     Lut_Apply LA = new Lut_Apply();
                      if(check.isSelected()) LA.apply(color,selCol); else
                     LA.apply(color,selCol,interval);
    }

    /* kind of a push and pop LUT functions, used for the Preview of the gradient
    */
    
    public FileInfo getLUT(){
        FileInfo f =  WindowManager.getCurrentImage().getFileInfo();
        return f;
    }
    
    public void setLUT(FileInfo fi){
       Lut_Apply LAP = new Lut_Apply();
       LAP.showLut(fi,true);
    }
}

/* Lut_Apply class start
 * applies gradients to Lut
 */

public class Lut_Apply extends ImagePlus{
    
    /* function apply calculates gradients and applies it by calling showlut
     * gc[] is the color array, i the number of colours
     * Gradient is done evenly
     */
    
     public void apply(Color[] gc, int i){
                FileInfo fi = new FileInfo();
		fi.reds = new byte[256]; 
		fi.greens = new byte[256]; 
		fi.blues = new byte[256];
		fi.lutSize = 256;
                float nColorsfl = 256;
                float interval = nColorsfl / (float)i;
                for (int j=0;j<i;j++){
                    float iR = gc[j].getRed();
                    float iG = gc[j].getGreen();
                    float iB = gc[j].getBlue(); 
                    float idR = gc[j+1].getRed()-gc[j].getRed();
                    float idG = gc[j+1].getGreen()-gc[j].getGreen();
                    float idB = gc[j+1].getBlue()-gc[j].getBlue();
                    idR = (idR / interval);
                    idG = (idG / interval);
                    idB = (idB / interval);
                    int a=0;
                    for (a=(int)(interval*j); a<(int)(interval*(j)+interval); a++,iR += idR,iG += idG,iB += idB) {
                        fi.reds[a] = (byte)(iR);
                        fi.greens[a] = (byte)(iG);
                        fi.blues[a] = (byte)(iB);
                    }
                    int b=(int)(interval*j+interval)-1;
                    fi.reds[b] = (byte)(gc[j+1].getRed());
                    fi.greens[b] = (byte)(gc[j+1].getGreen());
                    fi.blues[b] = (byte)(gc[j+1].getBlue());
                    nColorsfl = 256;
                }
                if (nColorsfl>0) {
                      if (nColorsfl<256) interpolate(fi.reds, fi.greens, fi.blues, (int)nColorsfl);
                           //fi.fileName = arg;
                           showLut(fi,true);
                           return;                    
                 }
    }
    
     /* overload of the previous gradient apply function
      * gc[] is the color array, i the number of colours, idx the index values
      * gradient milestones are set at idx values
      */
     
     public void apply(Color[] gc, int i,float[] idx){
                FileInfo fi = new FileInfo();
		fi.reds = new byte[256]; 
		fi.greens = new byte[256]; 
		fi.blues = new byte[256];
		fi.lutSize = 256;
                float nColorsfl = 256;
                float iv;
                String str = new String();
                for (int j=0;j<i;j++){
                    float iR = gc[j].getRed();
                    float iG = gc[j].getGreen();
                    float iB = gc[j].getBlue(); 
                    float idR = gc[j+1].getRed()-gc[j].getRed();
                    float idG = gc[j+1].getGreen()-gc[j].getGreen();
                    float idB = gc[j+1].getBlue()-gc[j].getBlue();
                    iv =idx[j+1]-idx[j];
                    idR = (idR / iv);
                    idG = (idG / iv);
                    idB = (idB / iv);
                    int a=0;
                    for (a=(int)(idx[j]); a<=(int)(idx[j+1]); a++,iR += idR,iG += idG,iB += idB) {
                        
                        fi.reds[a] = (byte)(iR);
                        fi.greens[a] = (byte)(iG);
                        fi.blues[a] = (byte)(iB);
                    }
                    int b=(int)(idx[j+1]);
                    fi.reds[b] = (byte)(gc[j+1].getRed());
                    fi.greens[b] = (byte)(gc[j+1].getGreen());
                    fi.blues[b] = (byte)(gc[j+1].getBlue());
                    nColorsfl = 256;
                }
                if (nColorsfl>0) {
                      if (nColorsfl<256) interpolate(fi.reds, fi.greens, fi.blues, (int)nColorsfl);
                           //fi.fileName = arg;
                           showLut(fi,true);
                           return;                    
                }
    }
     
    /* applies the new Lut on the actual image*/
    void showLut(FileInfo fi, boolean showImage) {
            ImagePlus imp = WindowManager.getCurrentImage();
            if (imp!=null) {
                if (imp.getType()==ImagePlus.COLOR_RGB)
                    IJ.error("Color tables cannot be assiged to RGB Images.");
                else {
                    ImageProcessor ip = imp.getProcessor();
                    ColorModel cm = new IndexColorModel(8, 256, fi.reds, fi.greens, fi.blues);
                    ip.setColorModel(cm);
                    if (imp.getStackSize()>1) imp.getStack().setColorModel(cm);
                    imp.updateAndDraw();
                }
            } 
            /*else
            imp.createImage(fi, showImage);*/
        }
 
     /* function interpolate taken out from the orignal ImageJ project from Wayne Rasband
      * Couldn't find a way to have straight access to this method so I had
      * to add it manually.
      */
    
    void interpolate(byte[] reds, byte[] greens, byte[] blues, int nColors) {
  		byte[] r = new byte[nColors]; 
		byte[] g = new byte[nColors]; 
		byte[] b = new byte[nColors];
		System.arraycopy(reds, 0, r, 0, nColors);
		System.arraycopy(greens, 0, g, 0, nColors);
		System.arraycopy(blues, 0, b, 0, nColors);
		double scale = nColors/256.0;
		int i1, i2;
		double fraction;
		for (int i=0; i<256; i++) {
			i1 = (int)(i*scale);
			i2 = i1+1;
			if (i2==nColors) i2 = nColors-1;
			fraction = i*scale - i1;
			reds[i] = (byte)((1.0-fraction)*(r[i1]&255) + fraction*(r[i2]&255));
			greens[i] = (byte)((1.0-fraction)*(g[i1]&255) + fraction*(g[i2]&255));
			blues[i] = (byte)((1.0-fraction)*(b[i1]&255) + fraction*(b[i2]&255));
		}
	}
/* Lut_Apply class end*/
}
/* Color_Chooser end*/

/* Button class start
 * new Button class, sets color and tooltip text
 */

class smallButton extends JButton {
       
    public smallButton(String buttonText, String tooltipText, String button_color) {
        Font dafont = new Font(null);
        float fontsize = 11;
        dafont = dafont.deriveFont(fontsize);
        dafont = dafont.deriveFont(Font.BOLD);
        this.setFont(dafont);
        this.setText(buttonText);
        if (button_color=="red") this.setForeground(java.awt.Color.red);
        if (button_color=="green") this.setForeground(java.awt.Color.green);
        if (button_color=="blue") this.setForeground(java.awt.Color.blue);
        this.setToolTipText(tooltipText);
    }
}

/* Button class end*/

/* DrawRect class start
     * draws a rectangle at a set position with a preset color, color can be modified
     * later on
     */

class DrawRect extends JPanel{
        private Rectangle2D rect;
        private Graphics2D g2;
        private int x,y; 
        private Color fromc;
        
        //constructor
        public DrawRect(int posx,int posy){
            x = posx;
            y = posy;
            this.setSize(20,20);
            fromc = Color.white;
        }
        
        //draws a rectangle
        public void paintComponent(Graphics g){
            super.paintComponent(g);
            g2 = (Graphics2D)g;
            double width = 20;
            double height = 20;
            rect = new Rectangle2D.Double(x,y,width,height);
            g2.setPaint(fromc);
            g2.fill(rect);
            g2.setPaint(Color.black);
            g2.draw(rect);
         }
        
        //changes rectangle color*/
        public void fillFace(Color fromgrad){
            fromc = fromgrad;           
            repaint();
        }
        
        //returns color
        public Color getColor(){
            return fromc;
        }
}

/* DrawRect class end*/

/* ActiveDrawRect class start extends DrawRect
 * implements mouse event listening for color swatches
 */

public class ActiveDrawRect extends DrawRect implements MouseListener{

    public ActiveDrawRect(int posx, int posy, Color c){
        super(posx,posy);
        addMouseListener(this);
    }
    
    public void mouseClicked(MouseEvent e) {
       JColorChooser cc = new JColorChooser();
       Color c = cc.showDialog(lut_edit.editFrame,"Color Chooser", Color.red);
       for (int i=0;i<256;i++){
            if (e.getSource()==lut_edit.rect[i]){
                if (c!=null ) {
                    lut_edit.rect[i].fillFace(c);
                }
                break;
            }
       }
    }

    public void mousePressed(MouseEvent e) {
    }

    public void mouseReleased(MouseEvent e) {
    }

    public void mouseEntered(MouseEvent e) {
       for (int i=0;i<256;i++){
            if (e.getSource()==lut_edit.rect[i]){
               String str = "LUT position:"+i+" ,R:"+lut_edit.rect[i].getColor().getRed()+ " ,G:"+lut_edit.rect[i].getColor().getGreen()+" ,B:"+lut_edit.rect[i].getColor().getBlue();
               lut_edit.rect[i].setToolTipText(str);
               ToolTipManager.sharedInstance().setInitialDelay(0);
               return;
            }
       }
    }

    public void mouseExited(MouseEvent e) {
        for (int i=0;i<256;i++){
            if (e.getSource()==lut_edit.rect[i]){
                lut_edit.rect[i].setToolTipText("");
                ToolTipManager.sharedInstance().setInitialDelay(initial_tooltip_delay);
            }
       }
    }
}

/* ActiveDrawRect class end*/

/* WholeNumberField class start
 * from Sun; creates a Textfield that does only allow integers
 */

public class WholeNumberField extends JTextField {
    private Toolkit toolkit;
    private NumberFormat integerFormatter;

    public WholeNumberField(int value, int columns) {
        super(columns);
        toolkit = Toolkit.getDefaultToolkit();
        integerFormatter = NumberFormat.getNumberInstance(Locale.US);
        integerFormatter.setParseIntegerOnly(true);
        setValue(value);
    }

    public int getValue() {
        int retVal = 0;
        try {
            retVal = integerFormatter.parse(getText()).intValue();
        } catch (ParseException e) {
            // This should never happen because insertString allows
            // only properly formatted data to get in the field.
            toolkit.beep();
        }
        return retVal;
    }

    public void setValue(int value) {
        setText(integerFormatter.format(value));
    }

    protected Document createDefaultModel() {
        return new WholeNumberDocument();
    }

    protected class WholeNumberDocument extends PlainDocument {
        public void insertString(int offs, 
                                 String str,
                                 AttributeSet a) 
                throws BadLocationException {
            char[] source = str.toCharArray();
            char[] result = new char[source.length];
            int j = 0;

            for (int i = 0; i < result.length; i++) {
                if (Character.isDigit(source[i]))
                    result[j++] = source[i];
                else {
                    toolkit.beep();
                    System.err.println("insertString: " + source[i]);
                }
            }
            super.insertString(offs, new String(result, 0, j), a);
        }
    }
}

/* Wholenumberfield class end*/

/* Lut_Edit class start*/

class Lut_Edit extends JDialog implements WindowListener{
        public JDialog editFrame;
        private smallButton Apply_button = new smallButton("Apply","Apply LUT","");
        private smallButton Preview_button = new smallButton("Preview","Preview LUT","");
        private smallButton Cancel_button = new smallButton("Cancel","Cancel LUT edition","");
        private Dimension ScreenDimension = Toolkit.getDefaultToolkit().getScreenSize();
        private int ScreenX = (int) ScreenDimension.getWidth();
        private int ScreenY = (int) ScreenDimension.getHeight();
        private int colorFrameXlocation = (int)((ScreenX/12));
        private int colorFrameYlocation = (int)(8*(ScreenY/12));                        
        private ActiveDrawRect[] rect = new ActiveDrawRect[256];
        private int selCol;
        private JCheckBox check = new JCheckBox();
        private float[] interval;
        private ButtonGroup cbg = new ButtonGroup();
        private JButton[] Define_button = new JButton[5];
        private JRadioButton[] cb = new JRadioButton[5];
        private WholeNumberField[] tf = new WholeNumberField[5];
        private FileInfo fi;
        
        public Lut_Edit() {
            editFrame = new JDialog();
            editFrame.setTitle("Edit LUT");
            editFrame.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
            editFrame.setResizable(false);
            editFrame.setLocation(colorFrameXlocation,colorFrameYlocation);
            editFrame.getContentPane().setLayout(new BorderLayout());

            JPanel panelEdit = new JPanel();
            panelEdit.setLayout(new BorderLayout());
            JPanel panelButton = new JPanel();                        
            JPanel panel = new JPanel(new GridLayout(8,32));
            
            panelButton.add(Apply_button);
            panelButton.add(Preview_button);
            panelButton.add(Cancel_button);
            panelEdit.add(panel,BorderLayout.NORTH);
            panelEdit.add(panelButton,BorderLayout.SOUTH);
            
            for (int i = 0;i < 256; i++) {
                        rect[i] = new ActiveDrawRect(0,0,Color.white);
                        panel.add(rect[i]);
                    }
            
            addApplyListener(Apply_button,editFrame);
            addPreviewListener(Preview_button,editFrame);
            addCancelListener(Cancel_button,editFrame);
            editFrame.getContentPane().add(panelEdit);
            editFrame.addWindowListener(this);
            editFrame.pack();
        }   

        public void update_lut_edit(){
            ImagePlus imp = WindowManager.getCurrentImage();
            if (imp!=null) {
                IndexColorModel icm = (IndexColorModel)imp.getProcessor().getColorModel();
                byte[] r = new byte[256];
                byte[] g = new byte[256];
                byte[] b = new byte[256];
                icm.getReds(r); 
                icm.getGreens(g); 
                icm.getBlues(b);
                Color c;
                for (int i = 0;i < 256; i++) {
                        c = new Color(r[i]&255,g[i]&255,b[i]&255);
                        rect[i].fillFace(c);
                    }
            } else IJ.error("8 bit image must be opened!");    
        }
        // Window listeneres; essentially used for the Preview function, LUT is "saved"
        public void windowActivated(WindowEvent e) {
            fi = getLUT();
        }
        public void windowClosing(WindowEvent e) {
        }

        public void windowClosed(WindowEvent e) {
        }

        public void windowOpened(WindowEvent e) {
        }

        public void windowIconified(WindowEvent e) {
        }

        public void windowDeiconified(WindowEvent e) {
        }

        public void windowDeactivated(WindowEvent e) {
        }

        private void addApplyListener(final JButton button, final JDialog parent) {
            button.addActionListener(new ActionListener () {
            public void actionPerformed(ActionEvent e) {
                apply_swatch_lut();
                editFrame.setVisible(false);
           }
        });
        }
        
        private void addPreviewListener(final JButton button, final JDialog parent) {
            button.addActionListener(new ActionListener () {
            public void actionPerformed(ActionEvent e) {
                apply_swatch_lut();
           }
        });
        }
        
        private void addCancelListener(final JButton button, final JDialog parent) {
            button.addActionListener(new ActionListener () {
            public void actionPerformed(ActionEvent e) {
                if (fi!=null) setLUT(fi);
                editFrame.setVisible(false);
           }
        });
        }
        
        private void apply_swatch_lut(){
            if (IJ.versionLessThan("1.26f"))
		return;
            byte[] reds = new byte[256];
            byte[] greens = new byte[256];
            byte[] blues = new byte[256];
            for (int i=0; i<256; i++) {
            	reds[i] = (byte)rect[i].getColor().getRed();
                greens[i] = (byte)rect[i].getColor().getGreen();
		blues[i] = (byte)rect[i].getColor().getBlue();
            }
            IndexColorModel cm = new IndexColorModel(8, 256, reds, greens, blues);
            ImagePlus imp = WindowManager.getCurrentImage();
            if (imp==null)
                makeImage("Untitled LUT", cm);
            else {
                    imp.getProcessor().setColorModel(cm);
                    imp.updateAndDraw();
		}
        }
        
        public void makeImage(String title, IndexColorModel cm) {
            int width = 256;
            int height = 32;
            byte[] pixels = new byte[width*height];
            ByteProcessor bp = new ByteProcessor(width, height, pixels, cm);
            int[] ramp = new int[width];
            for (int i=0; i<width; i++)
		ramp[i] = i; 
            for (int y=0; y<height; y++)
            bp.putRow(0, y, ramp, width);
            new ImagePlus(title, bp).show();
  	}
        
        public FileInfo getLUT(){
            FileInfo f =  WindowManager.getCurrentImage().getFileInfo();
            return f;
        }
    
        public void setLUT(FileInfo f){
            Lut_Apply LAP = new Lut_Apply();
            LAP.showLut(f,true);
        }
/* Lut_Edit class end*/
        
    }

/* Lut_Panel class end*/    
}