
package uk.co.wingpath.util;

import java.util.*;
import java.text.*;
import java.math.*;
import uk.co.wingpath.event.*;

/**
* Instances of this class may be used to store values and monitor changes
* to them.
* <p>A value of type <code>T</code> may stored in the variable using the
* {@link #setValue} method, and the value may be retrieved using the
* {@link #getValue} method.
* <p>A {@link ValueListener} may be added to a variable to monitor
* changes to the value of the variable. The
* {@link ValueListener#valueChanged valueChanged} method
* of the listener will be called if the {@link #setValue} method is used
* to change the value. The listener will NOT be called if the old and new
* values are the same, as determined by the <code>equals</code> method of
* type <code>T</code>.
* <p>It is permissible to store <code>null</code> as a value.
* <p>Instances of this class are thread-safe.
*/
public class SimpleVariable<T>
    implements Variable<T>
{
    private final ValueEventSource listeners;
    private T value;

    /**
    * Constructs a variable with <code>null</code> as its initial value.
    */
    public SimpleVariable ()
    {
        value = null;
        listeners = new ValueEventSource ();
    }

    /**
    * Constructs a variable with the specified initial value.
    * @param value the initial value.
    */
    public SimpleVariable (T value)
    {
        this.value = value;
        listeners = new ValueEventSource ();
    }

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

    /**
    * Sets the value of the variable.
    * <p>If the new value is not equal to the old value, the
    * <code>valueChanged</code> method of each listener will be called.
    * @param value the new value.
    */
    public synchronized void setValue (T value)
    {
        if (value == this.value)
            return;
        if (value == null || this.value == null ||
            !value.equals (this.value))
        {
            this.value = value;
            listeners.fireValueChanged (this);
        }
    }

    /**
    * Adds the specified listener.
    * @param l the listener to be added.
    */
    public void addValueListener (ValueListener l)
    {
        listeners.addListener (l);
    }

    /**
    * Removes the specified listener.
    * @param l the listener to be removed.
    */
    public void removeValueListener (ValueListener l)
    {
        listeners.removeListener (l);
    }
}

