/*
 * $RCSfile: NodeReferenceTable.java,v $
 *
 * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
 *
 * Use is subject to license terms.
 *
 * $Revision: 1.4 $
 * $Date: 2007/02/09 17:18:12 $
 * $State: Exp $
 */

package javax.media.j3d;

import java.util.Hashtable;

/**
 * The NodeReferenceTable object is used by a leaf node's
 * <code>updateNodeReferences</code> method called by the
 * <code>cloneTree</code> method.
 * The NodeReferenceTable maps nodes from the original subgraph
 * to the new nodes in the cloned subgraph. This information
 * can then be used to update any cloned leaf node references
 * to reference nodes in the cloned subgraph.
 * <P>
 * During a <code>cloneTree</code> call, after all nodes have been duplicated,
 * each SceneGraphObject's <code>updateNodeReferences</code> method is called.
 * This method takes a NodeReferenceTable object as a parameter.  The
 * SceneGraphObject's <code>updateNodeReferences</code> method can then use the
 * <code>getNewObjectReference</code> method from this object to get updated
 * references to objects that have been duplicated in the new cloneTree
 * sub-graph.  If a match is found, a
 * reference to the corresponding SceneGraphObject in the newly cloned sub-graph 
 * is returned.  If no corresponding reference is found, either a
 * DanglingReferenceException is thrown by the <code>cloneTree</code>
 * method or a reference to the original
 * SceneGraphObject is returned depending on the value of the 
 * <code>allowDanglingReferences</code> parameter passed in the
 * <code>cloneTree</code> call.
 * @see SceneGraphObject#updateNodeReferences
 * @see Node#cloneTree
 * @see DanglingReferenceException
 */
public class NodeReferenceTable extends Object {

    Hashtable objectHashtable;
    boolean   allowDanglingReferences;

    /**
     * Constructs an empty NodeReferenceTable.
     * @since Java 3D 1.2
     */
    public NodeReferenceTable() {
    }

    // Constructor - this is NOT public!
    NodeReferenceTable(boolean allowDanglingReferences,
		       Hashtable objectHashtable) {
        set(allowDanglingReferences, objectHashtable);
    }

    void set(boolean allowDanglingReferences,
	     Hashtable objectHashtable) {
        this.objectHashtable = objectHashtable;
        this.allowDanglingReferences = allowDanglingReferences;
    }


    /**
     * This method is used in conjunction with the <code>cloneTree</code>
     * method. It can be used by the <code>updateNodeReferences</code>
     * method to see if a SceneGraphObject that is being referenced has been duplicated
     * in the new cloneTree sub-graph.
     * <P>
     * A SceneGraphObject's <code>updateNodeReferences</code> method would use this
     * method by calling it with the reference to the old (existed before
     * the cloneTree operation) object.  If the object has been duplicated
     * in the cloneTree sub-graph, the corresponding object in the cloned
     * sub-graph is returned.  If no corresponding reference is found, either
     * a DanglingReferenceException is thrown or a reference to the original
     * SceneGraphObject is returned depending on the value of the
     * <code>allowDanglingReferences</code> parameter passed in the
     * <code>cloneTree</code> call.
     *
     * @param oldReference the reference to the object in
     *  the original sub-graph.
     *
     * @return A reference to the corresponding object in the cloned
     *  sub-graph.  If no corresponding object exists, either a
     *  DanglingReferenceException will be generated by the
     *  <code>cloneTree</code> method or a reference to the original object
     *  is returned depending on the value of the
     * <code>allowDanglingReferences</code> parameter passed in the
     * <code>cloneTree</code> call.
     *
     * @see SceneGraphObject#updateNodeReferences
     * @see Node#cloneTree
     * @see DanglingReferenceException
     */
    public final SceneGraphObject
        getNewObjectReference(SceneGraphObject oldReference) {

        // look up original SceneGraphObject in hash table
        SceneGraphObject newObject =
           (SceneGraphObject)objectHashtable.get(oldReference);

        if (newObject != null) {
            // found new reference
            return newObject;
        }

        // dangling reference found!
        if (allowDanglingReferences == true) {
            return oldReference;
        }

        // dangling references not allowed
        throw new DanglingReferenceException();
    }

}
