
package uk.co.wingpath.gui;

import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.event.*;
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 <code>JTextArea</code>.
*/
public class WTextArea
    extends WAbstractComponent<String>
    implements Verifiable
{
    private final JTextArea textArea;
    private final JScrollPane scrollPane;
    private final TextEditor editor;
    private boolean hasFocus;
    private String toolTip = null;

    /**
    * Constructs a <code>WTextArea</code>.
    * @param statusBar where to display error messages.
    * @param label text to be used for associated label.
    * May be <code>null</code>, in which case there will no
    * associated label.
    */
    public WTextArea (StatusBar statusBar, String label)
    {
        this (statusBar, label, true);
    }

    /**
    * Constructs a <code>WTextArea</code>.
    * @param statusBar where to display error messages.
    * @param label text to be used for associated label.
    * May be <code>null</code>, in which case there will no
    * associated label.
    * @param mayBeEmpty whether the empty string is an allowable value.
    */
    public WTextArea (StatusBar statusBar, String label, boolean mayBeEmpty)
    {
        Event.checkIsEventDispatchThread ();
        textArea = new JTextArea ();
        scrollPane = new JScrollPane (textArea,
            JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
            JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        editor = new TextEditor (textArea, "", listeners);
        editor.setVerifier (
            mayBeEmpty ? new NullVerifier (statusBar) :
                new NonEmptyVerifier (label, statusBar));
        hasFocus = false;
        initialize (scrollPane, label);

        textArea.addFocusListener (new FocusListener ()
        {
            public void focusGained (FocusEvent e)
            {
                if (!hasFocus)
                {
                    textArea.selectAll ();
                    hasFocus = true;
                }
            }

            public void focusLost (FocusEvent e)
            {
                if (!e.isTemporary ())
                {
                    hasFocus = false;
                    textArea.setCaretPosition (0);
                }
            }
        });

        addValueListener (
            new ValueListener ()
            {
                public void valueChanged (ValueEvent e)
                {
                    setToolTipText ();
                }
            });
    }

    /**
    * Checks whether the value that the user has entered is valid.
    * <p>If the user is not editing the value, <code>true</code> is returned.
    * <p>If a verifier has been set, it is called to check the validity of
    * the user-entered value.
    * If no verifier has been set, the value is assumed to be valid.
    * <p>If the user-entered value is valid, it is stored as
    * the value of the component, a value event is fired, and
    * <code>true</code> is returned.
    * If the value is not valid, <code>false</code> is returned.
    * @return <code>false</code> if the user has entered an invalid value,
    * <code>true</code> otherwise.
    * @see #setVerifier(Verifier)
    * @see Verifier
    */
    @Override
    public boolean checkValue ()
    {
        if (!editor.checkValue ())
        {
            requestFocusInWindow ();
            return false;
        }
        return true;
    }

    /**
    * Sets the verifier for this component.
    * @param verifier the new verifier
    * @see Verifier
    * @see #checkValue
    */
    public void setVerifier (Verifier verifier)
    {
        editor.setVerifier (verifier);
    }

    public String getValue ()
    {
        return editor.getValue ();
    }

    public void setValue (String val)
    {
        editor.setValue (val);
        setToolTipText ();
    }

    @Override
    public boolean hasValueChanged (String oldValue)
    {
        return editor.hasValueChanged (oldValue);
    }

    /**
    * Specifies whether or not this component should be editable.
    * @param editable whether the component should be editable.
    */
    @Override
    public void setEditable (boolean editable)
    {
        Event.checkIsEventDispatchThread ();
        textArea.setEditable (editable);
        textArea.setFocusable (editable);
    }

    public void setRows (int rows)
    {
        textArea.setRows (rows);
    }

    private void setToolTipText ()
    {
        textArea.setToolTipText (Gui.selectToolTipText (toolTip,
            textArea.getText (), textArea.getSize ().width));
    }

    @Override
    public void setToolTipText (String text)
    {
        Event.checkIsEventDispatchThread ();
        toolTip = text;
        super.setToolTipText (text); // to set tooltip for label.
        setToolTipText ();
    }

    @Override
    public void setEnabled (boolean enabled)
    {
        super.setEnabled (enabled);
        textArea.setEnabled (enabled && isEditable ());
    }
}

