/*
 * org.openmicroscopy.shoola.util.ui.colourpicker.ColourSliderUI
 *
 *------------------------------------------------------------------------------
 *  Copyright (C) 2006 University of Dundee. All rights reserved.
 *
 *
 * 	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.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *------------------------------------------------------------------------------
 */

package org.openmicroscopy.shoola.util.ui.colourpicker;

//Java imports
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;


//Third-party libraries

//Application-internal dependencies

/** 
 * ColourSliderUI is the RGB Slider component, which allows the user to change
 * the RGB values of the colour using the JSlider component. It also allows the
 * user to change the text box associated with each slider to do the same.  
 *
 * @author  Jean-Marie Burel &nbsp;&nbsp;&nbsp;&nbsp;
 * 				<a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a>
 * @author	Donald MacDonald &nbsp;&nbsp;&nbsp;&nbsp;
 * 				<a href="mailto:donald@lifesci.dundee.ac.uk">donald@lifesci.dundee.ac.uk</a>
 * @version 3.0
 * <small>
 * (<b>Internal version:</b> $$Revision: $$Date: $$)
 * </small>
 * @since OME2.2
 */
class RGBSliderUI
	extends JPanel
{
	
	/** The slider representing the red channel. */
	private ColourSlider 				redSlider;
	
    /** The slider representing the green channel. */
	private ColourSlider 				greenSlider;
	
    /** The slider representing the blue channel. */
	private ColourSlider 				blueSlider;
    
    /** The slider representing the alpha channel. */
	private ColourSlider 				alphaSlider;
	
	/** Change listener for red slider. */
	private ChangeListener				redChangeListener;

	/** Change listener for green slider. */
	private ChangeListener				greenChangeListener;
	
	/** Change listener for blue slider. */
	private ChangeListener				blueChangeListener;
	
	/** Change listener for alpha slider.  */
	private ChangeListener				alphaChangeListener;
	
	/** Action listener for red text box. */
	private ActionListener				redTextboxActionListener;
	
	/** Action listener for green text box. */
	private ActionListener				greenTextboxActionListener;
	
	/** Action listener for Blue textbox.  */
	private ActionListener				blueTextboxActionListener;
	
	/** Action listener for alpha TextBox.  */
	private ActionListener				alphaTextboxActionListener;
	
	/**
	 * Boolean variable, true if the current component is active, this is 
	 * controlled from the parent component. It tells the UI whether or not
	 * to ignore refresh events.
	 */
	private boolean						active;
	
	/**
	 * The textfield representing the colour red channel.
	 */
	private JTextField					redTextbox;
	
    /**
     * The textfield representing the colour green channel.
     */
	private JTextField					greenTextbox;
	
    /**
     * The textfield representing the blue red channel.
     */
	private JTextField					blueTextbox;
	
    /**
     * The textfield representing the alpha red channel.
     */
	private JTextField					alphaTextbox;
	
	/** The JLabel representing the colour red channel. */
	private JLabel						redLabel;
	
    /** The JLabel representing the colour green channel. */
	private JLabel						greenLabel;
	
    /** The JLabel representing the colour blue channel. */
	private JLabel						blueLabel;
	
    /** The JLabel representing the colour alpha channel. */
	private JLabel						alphaLabel;
	
	/** Current layout model, which is a gridbag controller.  */
	private GridBagLayout				layout;
	
	/** Model of the contoller. */
	private RGBControl					control;
	
	/**
	 * Creates a new instance and keeps a reference to the control c.
	 *  
	 * @param c Reference to the control. Mustn't be <code>null</code>.
	 */
	RGBSliderUI(RGBControl c)
	{
        if (c == null)
            throw new NullPointerException("No control.");
		control = c;
		createUI();
		active = false;
	}
	
	/**
	 * Sets the current component Active, called from parent control letting 
	 * this component know it should listen to refresh events. 
	 * 
	 * @param act active or not.
	 */
	void setActive(boolean act) { active = act; }
	
	/**
	 * Creates the Red slider, and changes listener, attaching the change
	 * listener to the slider. 
	 */
	void createRedSlider()
	{
		Color s1,s;
		Color e;
		
		s1 = control.getColour();
		s = new Color(0,s1.getGreen(), s1.getBlue(), 255);
		e = new Color(255,s1.getGreen(), s1.getBlue(), 255);
		
		redSlider = new ColourSlider(0, 255, s, e);
		redSlider.setValue((int) (control.getRed()*255.0));
		redChangeListener = new ChangeListener() {
			public void stateChanged(ChangeEvent changeEvent)
			{
				ColourSlider src = (ColourSlider) changeEvent.getSource();
				control.setRed(src.getValue()/255.0f);
			}
		};
		
		redSlider.addChangeListener(redChangeListener);
	}

	/**
	 * Creates the Green slider, and change listener, attaching the change
	 * listener to the slider. 
	 */ 
	void createGreenSlider()
	{
		Color s1, s;
		Color e1, e;
	
		s1 = control.getColour();
		s = new Color(s1.getRed(), 0, s1.getBlue(), 255);
		e1 = control.getColour();
		e = new Color(e1.getRed(), 255, s1.getBlue(), 255);
		
		greenSlider = new ColourSlider(0, 255, s, e);
		greenSlider.setValue((int) (control.getGreen()*255.0));
		
		greenChangeListener = new ChangeListener() {
			public void stateChanged(ChangeEvent changeEvent)
		{
			ColourSlider src = (ColourSlider) changeEvent.getSource(); 
			control.setGreen(src.getValue()/255.0f);
		}
		};
		greenSlider.addChangeListener(greenChangeListener);
	}

	/**
	 * Creates the Blue slider, and changes listener, attaching the change
	 * listener to the slider. 
	 */
	void createBlueSlider()
	{
		Color s1, s;
		Color e1, e;
			
		s1 = control.getColour();
		s = new Color(s1.getRed(), s1.getGreen(), 0, 255);
		e1 = control.getColour();
		e = new Color(e1.getRed(), s1.getGreen(), 255, 255);
		
		blueSlider = new ColourSlider(0, 255, s, e);
		blueSlider.setValue((int) (control.getBlue()*255.0));
		blueChangeListener = new ChangeListener() {
				public void stateChanged(ChangeEvent changeEvent)
			{
				ColourSlider src = (ColourSlider) changeEvent.getSource(); 
				control.setBlue(src.getValue()/255.0f);
			}
		};
		
		blueSlider.addChangeListener(blueChangeListener);
	}
	
	/**
	 * Creates the Alpha slider, and changes listener, attaching the change
	 * listener to the slider. 
	 */
	void createAlphaSlider()
	{
		Color s1, s;
		Color e1, e;
	
		s1 = control.getColour();
		s = new Color(s1.getRed(), s1.getGreen(), s1.getBlue(), 0);
		e1 = control.getColour();
		e = new Color(e1.getRed(), s1.getGreen(), s1.getBlue(), 255);
		
		alphaSlider = new ColourSlider(0, 255, s, e);
		alphaSlider.setValue((int) (control.getAlpha()*255.0));
		alphaChangeListener = new ChangeListener() {
			public void stateChanged(ChangeEvent changeEvent)
		{
			ColourSlider src = (ColourSlider) changeEvent.getSource(); 
			control.setAlpha(src.getValue()/255.0f);
		}
		};
	
		alphaSlider.addChangeListener(alphaChangeListener);
	}
	
	/**
	 * Creates the Red textbox, and action listener, attaching the action
	 * listener to the textbox. 
	 */
	void createRedTextbox()
	{
		redTextbox = new JTextField(""+(int) (control.getRed()*255));
		redTextbox.setColumns(TabbedPaneUI.TEXTBOX_COLUMN);
		redTextboxActionListener = new ActionListener(){
			public void actionPerformed(ActionEvent actionEvent) {
				JTextField src = (JTextField) actionEvent.getSource();
				try {
					int value = Integer.parseInt(src.getText());
					if (value >=0 && value <= 255)
						control.setRed(value/255.0f);
					else {
						ColourPicker.invalidColorValue();
						redTextbox.setText(""+(int) (control.getRed()*255));
					}
				} catch(NumberFormatException e) {
					ColourPicker.invalidColorValue();
					redTextbox.setText(""+(int) (control.getRed()*255));
				} //notify user and reset value
			}
		};
		redTextbox.addActionListener(redTextboxActionListener);	
	}
	
	/**
	 * Creates the Green textbox, and action listener, attaching the action
	 * listener to the textbox. 
	 */
	void createGreenTextbox()
	{
		greenTextbox = new JTextField(""+(int) (control.getGreen()*255));
		greenTextbox.setColumns(TabbedPaneUI.TEXTBOX_COLUMN);
		greenTextboxActionListener = new ActionListener(){
			public void actionPerformed(ActionEvent actionEvent) {
				JTextField src = (JTextField) actionEvent.getSource();
				try
				{
					int value = Integer.parseInt(src.getText());
					if (value >= 0 && value <= 255)
						control.setGreen(value/255.0f);
					else {
						ColourPicker.invalidColorValue();
						greenTextbox.setText(""+(int) (control.getGreen()*255));
					}
				} catch(NumberFormatException e) {
					ColourPicker.invalidColorValue();
					greenTextbox.setText(""+(int) (control.getGreen()*255));
				}
			}
		};
		greenTextbox.addActionListener(greenTextboxActionListener);
	}
	
	/**
	 * Creates the Blue textbox, and action listener, attaching the action
	 * listener to the textbox. 
	 */
	void createBlueTextbox()
	{
		blueTextbox = new JTextField(""+(int) (control.getBlue()*255));
		blueTextbox.setColumns(TabbedPaneUI.TEXTBOX_COLUMN);
		blueTextboxActionListener = new ActionListener(){
			public void actionPerformed(ActionEvent actionEvent) {
				JTextField src = (JTextField) actionEvent.getSource();
				try {
					int value = Integer.parseInt(src.getText());
					if (value >=0 && value <=255)
						control.setBlue(value/255.0f);
					else {
						ColourPicker.invalidColorValue();
						blueTextbox.setText(""+(int) (control.getBlue()*255));
					}
				} catch(NumberFormatException e) {
					ColourPicker.invalidColorValue();
					blueTextbox.setText(""+(int) (control.getBlue()*255));
				}
			}
		};
		blueTextbox.addActionListener(blueTextboxActionListener);
	}
	
	/**
	 * Creates the Alpha textbox, and action listener, attaching the action
	 * listener to the textbox. 
	 */
	void createAlphaTextbox()
	{
		alphaTextbox = new JTextField(""+(int) (control.getAlpha()*255));
		alphaTextbox.setColumns(TabbedPaneUI.TEXTBOX_COLUMN);
		alphaTextboxActionListener = new ActionListener(){
			public void actionPerformed(ActionEvent actionEvent) {
				JTextField src = (JTextField) actionEvent.getSource();
				try {
					int value = Integer.parseInt(src.getText());
					if (value>=0 && value<=255)
						control.setAlpha(value/255.0f);
					else {
						ColourPicker.invalidColorValue();
						alphaTextbox.setText(""+(int) (control.getAlpha()*255));
					}
				} catch(NumberFormatException e) {
					ColourPicker.invalidColorValue();
					alphaTextbox.setText(""+(int) (control.getAlpha()*255));
				}
			}
		};
		alphaTextbox.addActionListener(alphaTextboxActionListener);
	}
	
	/** Creates labels, red, green, blue and alpha. */
	void createLabels()
	{
		redLabel = new JLabel("Red");
		greenLabel = new JLabel("Green");
		blueLabel = new JLabel("Blue");
		alphaLabel = new JLabel("Alpha");
	}
	
	/** Lays out the components previously created in createUI. */
	void layoutComponents()
	{
		layout = new GridBagLayout();
		this.setLayout(layout);
		GridBagConstraints gbc = new GridBagConstraints();
		gbc.gridx = 0;
		gbc.gridy = 0;
		gbc.weightx = 80;
		gbc.weighty = 5;
		gbc.anchor = GridBagConstraints.WEST;
		gbc.fill = GridBagConstraints.HORIZONTAL;
		gbc.insets = new Insets(0, 5, 0, 5);
		
		this.add(redLabel, gbc);
		
		gbc.gridx = 0;
		gbc.gridy = 1;
		this.add(redSlider, gbc);
		
		gbc.gridx = 1;
		gbc.gridy = 1;
		gbc.weightx = 20;
		this.add(redTextbox,gbc);
		
		gbc.gridx = 0;
		gbc.gridy = 2;
		gbc.weightx = 80;
		this.add(greenLabel, gbc);
		
		gbc.gridx = 0;
		gbc.gridy = 3;
		this.add(greenSlider, gbc);
		
		gbc.gridx = 1;
		gbc.gridy = 3;
		gbc.weightx = 20;
		this.add(greenTextbox,gbc);
		
		gbc.gridx = 0;
		gbc.gridy = 4;
		gbc.weightx = 80;
		this.add(blueLabel, gbc);
		
		gbc.gridx = 0;
		gbc.gridy = 5;
		this.add(blueSlider, gbc);
		
		gbc.gridx = 1;
		gbc.gridy = 5;
		gbc.weightx = 20;
		this.add(blueTextbox,gbc);
		
		gbc.gridx = 0;
		gbc.gridy = 6;
		gbc.weightx = 80;
		this.add(alphaLabel, gbc);
		
		gbc.gridx = 0;
		gbc.gridy = 7;
		this.add(alphaSlider, gbc);
		
		gbc.gridx = 1;
		gbc.gridy = 7;
		gbc.weightx = 20;
		this.add(alphaTextbox,gbc);
	
	}
	
	/**
     * Creates slider UI, which consists of 4 JSliders, textfields and JLabels.
	 */
	void createUI()
	{
		createRedSlider();
		createGreenSlider();
		createBlueSlider();
		createAlphaSlider();
		
		createRedTextbox();
		createGreenTextbox();
		createBlueTextbox();
		createAlphaTextbox();
		
		createLabels();
		
		layoutComponents();
	}
	
	/**
	 * Updates the red slider of the UI, including changing the colour gradient
	 * of the slider tracks.
	 */
	void updateRedSlider()
	{
		Color s, s1, e;
		redSlider.setValue((int) (control.getRed()*255));
		s1 = control.getColour();
		s = new Color(0, s1.getGreen(), s1.getBlue(), 255);
		
		e = new Color(255, s1.getGreen(), s1.getBlue(), 255);
		redSlider.setRGBStart(s);
		redSlider.setRGBEnd(e);
	}
	
	/**
	 * Updates the green slider of the UI, including changing the colour
     * gradient of the slider tracks.
	 */
	void updateGreenSlider()
	{
		Color s, s1, e;
		greenSlider.setValue((int) (control.getGreen()*255));
		s1 = control.getColour();
		s = new Color(s1.getRed(), 0, s1.getBlue(), 255);
		
		e = new Color(s1.getRed(), 255, s1.getBlue(), 255);
		greenSlider.setRGBStart(s);
		greenSlider.setRGBEnd(e);
	}
	
	/**
	 * Updates the blue slider of the UI, including changing the colour gradient
	 * of the slider tracks.
	 */
	void updateBlueSlider()
	{
		Color s, s1, e;
		blueSlider.setValue((int) (control.getBlue()*255));
		s1 = control.getColour();
		s = new Color(s1.getRed(), s1.getGreen(), 0, 255);
		
		e = new Color(s1.getRed(), s1.getGreen(), 255, 255);
		blueSlider.setRGBStart(s);
		blueSlider.setRGBEnd(e);	
	}
	
	/**
	 * Updates the alpha slider of the UI, including changing the colour 
     * gradient of the slider tracks.
	 */
	void updateAlphaSlider()
	{
		Color s, s1, e;
		alphaSlider.setValue((int) (control.getAlpha()*255));
		s1 = control.getColour();
		s = new Color(s1.getRed(), s1.getGreen(), s1.getBlue(), 0);
		
		e = new Color(s1.getRed(), s1.getGreen(), s1.getBlue(), 255);
		alphaSlider.setRGBStart(s);
		alphaSlider.setRGBEnd(e);
	}
	
	/**
	 * Updates the sliders of the UI, including changing the colour gradient
	 * of the different slider tracks.
	 */
	void updateSliders()
	{
		updateRedSlider();
		updateBlueSlider();
		updateGreenSlider();
		updateAlphaSlider();
	}

	/** Updates the textboxes of the UI.  */
	void updateTextboxes()
	{		
		redTextbox.setText(""+(int) (control.getRed()*255));
		greenTextbox.setText(""+(int) (control.getGreen()*255));
		blueTextbox.setText(""+(int) (control.getBlue()*255));
		alphaTextbox.setText(""+(int) (control.getAlpha()*255));
	}
	
	/** 
	 * Refresh method will be called by tabbedpanelUI when the model has 
	 * changed.
	 */
	void refresh() 
	{
		if (!(active)) return;
		removeListeners();
		updateSliders();
		updateTextboxes();
		addListeners();
		repaint();
	}

	/**
	 * Adds change listeners to the components. Used in conjuntion with 
	 * {@link #removeListeners()} to get round spurious event 
	 * triggers when updating components.
	 */
	void addListeners()
	{
		redSlider.addChangeListener(redChangeListener);
		greenSlider.addChangeListener(greenChangeListener);
		blueSlider.addChangeListener(blueChangeListener);
		alphaSlider.addChangeListener(alphaChangeListener);

		redTextbox.addActionListener(redTextboxActionListener);
		greenTextbox.addActionListener(greenTextboxActionListener);
		blueTextbox.addActionListener(blueTextboxActionListener);
		alphaTextbox.addActionListener(alphaTextboxActionListener);		
	}
	
	/**
	 * Removes change listeners to the components. Used in conjuntion with 
	 * {@link #addListeners()} to get round spurious event 
	 * triggers when updating components.
	 */
	void removeListeners()
	{
		redSlider.removeChangeListener(redChangeListener);
		greenSlider.removeChangeListener(greenChangeListener);
		blueSlider.removeChangeListener(blueChangeListener);
		alphaSlider.removeChangeListener(alphaChangeListener);

		redTextbox.removeActionListener(redTextboxActionListener);
		greenTextbox.removeActionListener(greenTextboxActionListener);
		blueTextbox.removeActionListener(blueTextboxActionListener);
		alphaTextbox.removeActionListener(alphaTextboxActionListener);
	}
	
}
