//
// $Id: DEvent.java,v 1.14 2003/07/22 22:54:14 mdb Exp $

package com.threerings.presents.dobj;

import com.threerings.io.Streamable;

/**
 * A distributed object event is dispatched whenever any modification is
 * made to a distributed object. It can also be dispatched purely for
 * notification purposes, without making any modifications to the object
 * that defines the delivery group (the object's subscribers).
 */
public abstract class DEvent implements Streamable
{
    /**
     * A zero argument constructor for unserialization from yon network.
     */
    public DEvent ()
    {
    }

    /**
     * Constructs a new distributed object event that pertains to the
     * specified distributed object.
     */
    public DEvent (int targetOid)
    {
        _toid = targetOid;
    }

    /**
     * Returns the oid of the object that is the target of this event.
     */
    public int getTargetOid ()
    {
        return _toid;
    }

    /**
     * Some events are used only internally on the server and need not be
     * broadcast to subscribers, proxy or otherwise. Such events can
     * return true here and short-circuit the normal proxy event dispatch
     * mechanism.
     */
    public boolean isPrivate ()
    {
        return false;
    }

    /**
     * Applies the attribute modifications represented by this event to
     * the specified target object. This is called by the distributed
     * object manager in the course of dispatching events and should not
     * be called directly.
     *
     * @exception ObjectAccessException thrown if there is any problem
     * applying the event to the object (invalid attribute, etc.).
     *
     * @return true if the object manager should go on to notify the
     * object's subscribers of this event, false if the event should be
     * treated silently and the subscribers should not be notified.
     */
    public abstract boolean applyToObject (DObject target)
        throws ObjectAccessException;

    /**
     * Returns the object id of the client that generated this event. If
     * the event was generated by the server, the value returned will be
     * -1. This is not valid on the client, it will return -1 for all
     * events there (it is primarily provided to allow for event-level
     * access control).
     */
    public int getSourceOid ()
    {
        return _soid;
    }

    /**
     * Do not call this method. Sets the source oid of the client that
     * generated this event. It is automatically called by the client
     * management code when a client forwards an event to the server.
     */
    public void setSourceOid (int sourceOid)
    {
        _soid = sourceOid;
    }

    /**
     * Events with associated listener interfaces should implement this
     * function and notify the supplied listener if it implements their
     * event listening interface. For example, the {@link
     * AttributeChangedEvent} will notify listeners that implement {@link
     * AttributeChangeListener}.
     */
    protected void notifyListener (Object listener)
    {
        // the default is to do nothing
    }

    /**
     * Constructs and returns a string representation of this event.
     */
    public String toString ()
    {
        StringBuffer buf = new StringBuffer();
        buf.append("[");
        toString(buf);
        buf.append("]");
        return buf.toString();
    }

    /**
     * This should be overridden by derived classes (which should be sure
     * to call <code>super.toString()</code>) to append the derived class
     * specific event information to the string buffer.
     */
    protected void toString (StringBuffer buf)
    {
        buf.append("targetOid=").append(_toid);
        buf.append(", sourceOid=").append(_soid);
    }

    /** The oid of the object that is the target of this event. */
    protected int _toid;

    /** The oid of the client that generated this event. */
    protected transient int _soid = -1;

    /** Used to differentiate between null meaning we haven't initialized
     * our old value and null being the actual old value. */
    protected static final Object UNSET_OLD_VALUE = new Object();

    /** Used to differentiate between null meaning we haven't initialized
     * our old entry and null being the actual old entry. */
    protected static final DSet.Entry UNSET_OLD_ENTRY = new DSet.Entry() {
        public Comparable getKey () {
            return null;
        }
    };
}
