/*
 * org.openmicroscopy.shoola.util.ui.colourpicker.TabbedPaneUI
 *
 *------------------------------------------------------------------------------
 *  Copyright (C) 2006-2014 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.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.AbstractAction;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import info.clearthought.layout.TableLayout; 


//Third-party libraries

//Application-internal dependencies
import org.openmicroscopy.shoola.util.ui.IconManager;
import org.openmicroscopy.shoola.util.ui.UIUtilities;

/** 
 * The TabbedPaneUI controls the allows the switching between the different 
 * views in the colour picker.  
 *
 * @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 TabbedPaneUI
	extends JPanel
	implements ActionListener, ChangeListener, DocumentListener
{
	
	/** The number of column of the label displaying the alpha value. */
	static final int			TEXTBOX_COLUMN = 2;
	
	/** Used by card layout to select colour wheel panel. */
	private static final String COLOURWHEELPANE = "Color Wheel Pane"; 
	
	/** Used by card layout to select RGB Slider panel. */
	private static final String RGBSLIDERPANE = "RGB Slider Pane"; 
	
	/** Used by card layout to select swatch panel. */
	private static final String SWATCHPANE = "Swatch Pane";
	
	/** Action id to preview the color changes.*/
	private static final int	PREVIEW = 0;
	
	/** Action id to cancel and close the dialog.*/
	private static final int	CANCEL = 1;
	
	/** Action id to accept the color changes.*/
	private static final int	ACCEPT = 2;
	
	/** Action id to revert the color changes.*/
	private static final int	REVERT = 3;
	
	/**
	 * Toolbar contains the buttons to select the HSVWheelUI, RGB Selector
	 * or Colour Swatch.
	 */
	private JToolBar 			toolbar;
	
	/**
	 * Actionbar contains the buttons to accept, cancel or revert to the 
	 * original colour selection.
	 */
	private JPanel 				userActionPanel;
	
	/** Button to choose HSVColourWheelPanel. */
	private JToggleButton 		colourWheelButton;
	
	/** Button to choose RGB Sliders panel. */
	private JToggleButton		RGBSlidersButton;
	
	/** Button to choose colour swatch panel. */
	private JToggleButton		colourSwatchButton;
	
	/** Accept the current colour choice. */
	private JButton				acceptButton;
	
	/** Accept the current colour choice. */
	private JButton				previewButton;

	/** Revert to the original colour chosen by the user. */
	private JButton				revertButton;
	
	/** Cancel the colour panel. */
	private JButton				cancelButton;
	
	/** The deescrption of the color. */
	private JTextField			fieldDescription;
	
	/** ColourWheel panel, containing the HSVPickerUI. */
	private HSVColourWheelUI	colourWheelPane;
	
	/** RGBPanel containing the ColourSlider UI. */
	private RGBSliderUI 		RGBSliderPane;
	
	/** Containing the Swatch UI. */
	private ColourSwatchUI 		swatchPane;
	
	/** Layout manager for the colourwheel, slider and swatch panels. */
	private CardLayout 			tabPaneLayout;
	
	/** 
	 * Container for the layout manager above. Containers colourwheel, slider 
	 * and swatch panels.
	 */
	private JPanel				tabPanel;
	
	/**
	 * Paintpot pane will be displayed at the top of the window, above selected
	 * pane and below toolbar.
	 */
	private PaintPotUI  		paintPotPane;

    /** Model which will be changed when user adjusts sliders/textfield. */
    private RGBControl      	control;
    
    /** The owner of this component. */
    private ColourPicker    	parent;
    
    /** The original description of the color. */
    private String				originalDescription;
    
    /** Flag indicating that the preview button was clicked.*/
    private boolean preview;
    
    /** 
     * The toolbar controls which panel is active, the user has the choice
     * of HSV Colour wheel, RGB Sliders and colour swatches.
     * Create the toolbar and its buttons, add actions to the buttons and load
     * the button icons, attach the buttons to the tool bar. 
     */
    private void createToolbar()
    {
    	toolbar = new JToolBar();
    	IconManager icons = IconManager.getInstance();
        colourWheelButton = new JToggleButton(
        icons.getIcon(IconManager.COLOUR_WHEEL_24));
        UIUtilities.unifiedButtonLookAndFeel(colourWheelButton);
        colourWheelButton.setBorderPainted(true);
        colourWheelButton.setToolTipText("Show HSV Color Wheel");

        AbstractAction action = new AbstractAction("HSV Wheel Color Button") {
            public void actionPerformed(ActionEvent evt) 
            {
                clearToggleButtons();
                pickWheelPane();
            }
        };
        
        colourWheelButton.addActionListener(action);
        RGBSlidersButton = new JToggleButton(
        icons.getIcon(IconManager.COLOUR_SLIDER_24));
        UIUtilities.unifiedButtonLookAndFeel(RGBSlidersButton);
        RGBSlidersButton.setBorderPainted(true);
        RGBSlidersButton.setToolTipText("Show RGB Colour Sliders");
        
        action = new AbstractAction("RGB Slider Button") 
        {
            public void actionPerformed(ActionEvent evt) 
            {
            	clearToggleButtons();
                pickRGBSliderPane();
            }
        };
        RGBSlidersButton.addActionListener(action);
        colourSwatchButton = new JToggleButton(
        icons.getIcon(IconManager.COLOUR_SWATCH_24));
        colourSwatchButton.setToolTipText("Show Color List");
        UIUtilities.unifiedButtonLookAndFeel(colourSwatchButton);
        colourSwatchButton.setBorderPainted(true);
        
        action = new AbstractAction("Colour Swatch Button")
        {
            public void actionPerformed(ActionEvent evt) 
            {
                clearToggleButtons();
                pickSwatchPane();
            }
        };
        colourSwatchButton.addActionListener(action);
        toolbar.setFloatable(false);
        toolbar.setRollover(true);
        toolbar.add(colourWheelButton);
        toolbar.add(RGBSlidersButton);
        toolbar.add(colourSwatchButton);
    }
    
    /** 
     * The action bar controls if the user wishes to as accept current colour
     * choice, close the colour picker window or revert to the original colour
     * selected when the colour picker was loaded. 
     * 
     * Creates action bar, its buttons and load icons. Attach action events
     * to buttons and buttons to bar. 
     */
    private void createActionbar()
    {
        userActionPanel = new JPanel();
        userActionPanel.setLayout(new FlowLayout());
        
        //accept
        acceptButton = new JButton("Accept");
        acceptButton.setToolTipText("Accept the selected color.");
        acceptButton.setActionCommand(""+ACCEPT);
        acceptButton.addActionListener(this);
        
        //revert
        revertButton = new JButton("Revert");
        revertButton.setToolTipText("Revert to the original color.");
        revertButton.setActionCommand(""+REVERT);
        revertButton.addActionListener(this);
        
        //cancel
        cancelButton = new JButton("Cancel");
        cancelButton.setToolTipText("Close the Color Picker.");
        cancelButton.setActionCommand(""+CANCEL);
        cancelButton.addActionListener(this);
        
        //preview
        previewButton = new JButton("Preview");
        previewButton.setToolTipText("Preview the color change.");
        previewButton.setActionCommand(""+PREVIEW);
        previewButton.addActionListener(this);
        previewButton.setVisible(false);
        
        userActionPanel.add(previewButton);
        userActionPanel.add(acceptButton);
        userActionPanel.add(revertButton);
        userActionPanel.add(cancelButton);
        setButtonsEnabled(false);
        parent.getRootPane().setDefaultButton(cancelButton);
    }

    /**
     * Creates PaintPotUI, RGB slider panel and HSVWheel panel and Colour
     * Swatch panel.
     */
    private void createPanels()
    {
        colourWheelPane = new HSVColourWheelUI(control);
        paintPotPane = new PaintPotUI(control.getColour(), control);
        RGBSliderPane = new RGBSliderUI(control);
        swatchPane = new ColourSwatchUI(control);
    }
    
    /** 
     * Creates all the UI elements and displays the HSVWheel as active. 
     * 
     * @param field	  Pass <code>true</code> to add a field, 
	 * 				  <code>false</code> otherwise. 
	 */
    private void createUI(boolean field)
    {
        createToolbar();
        createActionbar();
        createPanels();
                
        JPanel container = new JPanel();
        container.setLayout(new BorderLayout());
        container.add(toolbar, BorderLayout.WEST);
          
        this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        add(container);
        paintPotPane.setPreferredSize(new Dimension(260, 24));
        add(Box.createVerticalStrut(5));
        add(paintPotPane);
        add(Box.createVerticalStrut(5));
        tabPanel = new JPanel();
        tabPaneLayout = new CardLayout();
        tabPanel.setLayout(tabPaneLayout);
        tabPanel.add(colourWheelPane, COLOURWHEELPANE);
        tabPanel.add(RGBSliderPane, RGBSLIDERPANE);
        tabPanel.add(swatchPane, SWATCHPANE);
        add(tabPanel);
        if (field) {
        	add(new JSeparator());
        	JLabel label = UIUtilities.setTextFont("Description: ");
        	JPanel p = new JPanel();
        	double[][] size = {{TableLayout.PREFERRED, TableLayout.FILL}, 
        			{TableLayout.PREFERRED}};
        	p.setLayout(new TableLayout(size));
        	p.add(label, "0, 0");
        	fieldDescription = new JTextField();
        	p.add(fieldDescription, "1, 0");
        	add(p);
        }
        add(userActionPanel);
        pickSwatchPane();
    }
    
    /** Clears all buttons. */
    private void clearToggleButtons()
    {
        colourWheelButton.setSelected(false);
        RGBSlidersButton.setSelected(false);
        colourSwatchButton.setSelected(false);
    }
    
    /** Sets Wheelbutton as picked and makes it visible. */
    private void pickWheelPane()
    {   
        colourWheelButton.setSelected(true);
        colourWheelPane.setActive(true);

        tabPaneLayout.show(tabPanel,COLOURWHEELPANE);
        RGBSliderPane.setActive(false);
        swatchPane.setActive(false);
        colourWheelPane.findPuck();
        colourWheelPane.refresh();
        colourWheelPane.repaint();
    }
    
    /** Sets swatch as picked and makes it visible. */
    private void pickSwatchPane()
    {   
        tabPaneLayout.show(tabPanel,SWATCHPANE);
        colourSwatchButton.setSelected(true);
        swatchPane.setActive(true);
        RGBSliderPane.setActive(false);
        colourWheelPane.setActive(false);
        this.doLayout();
        swatchPane.refresh();
    }
    
    /** Sets RGBSlider as picked and makes it visible. */
    private void pickRGBSliderPane()
    {
        tabPaneLayout.show(tabPanel,RGBSLIDERPANE);
        RGBSlidersButton.setSelected(true);
        RGBSliderPane.setActive(true);
        colourWheelPane.setActive(false);
        swatchPane.setActive(false);
        this.doLayout();
        RGBSliderPane.refresh();
    }
    
	/**
	 * Instantiates the tabbed pane, creates the UI and sets the control.
	 * 
     * @param parent  The parent of this component. Mustn't be <code>null</code>.
	 * @param control Reference to the control. Mustn't be <code>null</code>.
	 * @param field	  Pass <code>true</code> to add a field, 
	 * 				  <code>false</code> otherwise. 
	 */
	TabbedPaneUI(ColourPicker parent, RGBControl control, boolean field)
	{
        if (parent == null)
            throw new NullPointerException("No parent.");
        if (control == null)
            throw new NullPointerException("No control.");
        this.parent = parent;
		this.control = control;
		createUI(field);
		this.control.addListener(this);
	}
	
	/**
	 * Sets the enabled flag of the {@link #acceptButton} and 
	 * {@link #revertButton}.
	 * 
	 * @param enabled The value to set.
	 */
	void setButtonsEnabled(boolean enabled)
	{
		acceptButton.setEnabled(enabled);
		revertButton.setEnabled(enabled);
		previewButton.setEnabled(enabled);
		if (enabled) parent.getRootPane().setDefaultButton(acceptButton);
		else parent.getRootPane().setDefaultButton(cancelButton);
	}
	
	/** 
	 * Reverts current colour to the original colour choice passed to 
	 * Colourpicker.
	 */
	void revertAction()
	{ 
		control.revert(); 
		swatchPane.revert();
		//Check if preview was 
		if (preview) {
			preview = false;
			parent.reset();
		}
	}

	/** 
	 * Returns the description entered if any.
	 * 
	 * @return See above.
	 */
	String getDescription()
	{
		if (fieldDescription == null) return null;
		String text = fieldDescription.getText();
		if (text == null) return null;
		return text.trim();
	}
	
	/**
	 * Sets the description associated to the color.
	 * 
	 * @param description The value to set.
	 */
	void setColorDescription(String description)
	{
		if (fieldDescription == null || description == null) return;
		originalDescription = description;
		fieldDescription.setText(description);
		fieldDescription.getDocument().addDocumentListener(this);
	}
	
	/**
	 * Shows or hides the preview button.
	 * 
	 * @param visible Pass <code>true</code> to show the preview button,
	 * 				  <code>false</code> otherwise.
	 */
	void setPreviewVisible(boolean visible)
	{
		previewButton.setVisible(visible);
	}
	
	/** 
	 * Listens to ChangeEvent. 
	 * @see ChangeListener#stateChanged(ChangeEvent)
	 */
	public void stateChanged(ChangeEvent evt) 
	{
		if (RGBSliderPane != null && RGBSliderPane.isVisible())
			RGBSliderPane.refresh();
		if (colourWheelPane != null && colourWheelPane.isVisible())
			colourWheelPane.refresh();
		if (swatchPane != null && swatchPane.isVisible())
			swatchPane.refresh();
		if (fieldDescription == null)
			setButtonsEnabled(!control.isOriginalColour());
		else {
			String text = fieldDescription.getText();
			setButtonsEnabled(!text.equals(originalDescription) 
					|| !control.isOriginalColour());
		}
	}

	/**
	 * Implemented as specified by {@link DocumentListener} I/F.
	 * @see DocumentListener#insertUpdate(DocumentEvent)
	 */
	public void insertUpdate(DocumentEvent e)
	{
		if (fieldDescription == null) return;
		String text = fieldDescription.getText();
		setButtonsEnabled(!text.equals(originalDescription) 
				|| !control.isOriginalColour());
	}

	/**
	 * Implemented as specified by {@link DocumentListener} I/F.
	 * @see DocumentListener#removeUpdate(DocumentEvent)
	 */
	public void removeUpdate(DocumentEvent e)
	{
		if (fieldDescription == null) return;
		String text = fieldDescription.getText();
		setButtonsEnabled(!text.equals(originalDescription) ||
				!control.isOriginalColour());
	}

	/**
	 * Reacts to button clicks.
	 * @see ActionListener#actionPerformed(ActionEvent)
	 */
	public void actionPerformed(ActionEvent e)
	{
		int v = Integer.parseInt(e.getActionCommand());
		switch (v) {
			case CANCEL:
				parent.cancel();
				break;
			case REVERT:
				revertAction();
				break;
			case ACCEPT:
				parent.accept();
				break;
			case PREVIEW:
				preview = true;
				parent.preview();
		}
	}
	
	/**
	 * Required by the {@link DocumentListener} I/F but no-operation
	 * implementation in our case.
	 * @see DocumentListener#changedUpdate(DocumentEvent)
	 */
	public void changedUpdate(DocumentEvent e) {}
	
}
