
package uk.co.wingpath.gui;

import java.util.*;
import java.util.List;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import uk.co.wingpath.event.*;
import uk.co.wingpath.event.Event;
import uk.co.wingpath.util.*;


/**
* This class implements <code>WComponent</code> using a group of
* <code>JRadioButton</code>s.
*/
public class WRadioButtons<T>
    extends WAbstractComponent<T>
{
    private final ButtonGroup buttonGroup;
    private final JRadioButton [] buttons;
    private final JPanel panel;
    private T [] values;
    private T value;
    private boolean individualToolTips = false;

    /**
    * Constructs a <code>WRadioButtons</code> instance.
    * @param label text for the associated label, or <code>null</code> if
    * there is no associated label.
    * @param values the values corresponding to each radio button. These
    * are the possible values that may be returned by <code>getValue</code>.
    * @param texts the texts to be displayed by each radio button.
    * @param initValue the initial value. This must be equal to one of the
    * elements of the <code>values</code> array.
    * @param vertical whether the buttons should be arranged vertically or
    * horizontally.
    */
    public WRadioButtons (String label, T [] values, String [] texts,
        T initValue, boolean vertical)
    {
        Event.checkIsEventDispatchThread ();
        if (texts.length != values.length)
        {
            throw new IllegalArgumentException (
                "values & texts have different sizes");
        }
        buttonGroup = new ButtonGroup ();
        panel = new JPanel ();
        panel.setLayout (new BoxLayout (panel,
            vertical ? BoxLayout.Y_AXIS : BoxLayout.X_AXIS));
        initialize (panel, label);
        this.values = values.clone ();
        value = initValue;
        buttons = new JRadioButton [values.length];

        ActionListener listener = new ActionListener ()
            {
                public void actionPerformed (ActionEvent e)
                {
                    T v = getSelectedValue ();
                    if (!v.equals (value))
                    {
                        value = v;
                        fireValueChanged (false);
                    }
                }
            };

        for (int i = 0 ; i < values.length ; ++i)
        {
            JRadioButton button = new JRadioButton (texts [i]);
            buttons [i] = button;
            buttonGroup.add (button);
            if (initValue.equals (values [i]))
                button.setSelected (true);
            panel.add (button);
            if (!vertical)
                panel.add (Box.createHorizontalStrut (10));
            button.addActionListener (listener);
        }
    }

    private T getSelectedValue ()
    {
        Event.checkIsEventDispatchThread ();
        for (int i = 0 ; i < buttons.length ; ++i)
        {
            if (buttons [i].isSelected ())
                return values [i];
        }

        return null;
    }

    /**
    * Gets the value of the component.
    * @return the value of the component.
    */
    public T getValue ()
    {
        return value;
    }

    /**
    * Sets the value of the component.
    * <p>This method does NOT fire a value event.
    * @param value the new value for the component.
    */
    public void setValue (T value)
    {
        Event.checkIsEventDispatchThread ();
        for (int i = 0 ; i < values.length ; i++)
        {
            if (values [i].equals (value))
            {
                // The order of the next two statements is important - we don't
                // want to fire a ValueEvent.
                this.value = value;
                buttons [i].setSelected (true);
                return;
            }
        }

        throw new IllegalArgumentException ("Unrecognized value: " + value);
    }

    @Override
    public void setEnabled (boolean enabled)
    {
        Event.checkIsEventDispatchThread ();
        super.setEnabled (enabled);

        for (JRadioButton button : buttons)
            button.setEnabled (enabled);
    }

    @Override
    public void requestFocusInWindow ()
    {
        Event.checkIsEventDispatchThread ();
        buttons [0].requestFocusInWindow ();
    }

    @Override
    public void setToolTipText (String text)
    {
        Event.checkIsEventDispatchThread ();
        super.setToolTipText (text);

        if (!individualToolTips)
        {
            for (JRadioButton button : buttons)
                button.setToolTipText (text);
        }
    }

    /**
    * Registers text to be displayed as tooltips for individual buttons.
    * @param tooltips tooltip text array, in same order as the values that were
    * supplied to the <code>WRadioButtons</code> constructor.
    */
    @Override
    public void setToolTipText (String [] tooltips)
    {
        Event.checkIsEventDispatchThread ();

        for (int i = 0 ; i < tooltips.length ; i++)
            buttons [i].setToolTipText (tooltips [i]);

        individualToolTips = true;
    }

    @Override
    public void setBackground (Color bg)
    {
        if (bg == Gui.COLOUR_BACKGROUND_NORMAL)
            bg = Gui.COLOUR_BACKGROUND_PANEL;
        panel.setBackground (bg);
        for (JRadioButton button : buttons)
            button.setBackground (bg);
    }
}
