/*
 * Copyright 1997-2008 Sun Microsystems, Inc.  All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
 * CA 95054 USA or visit www.sun.com if you need additional information or
 * have any questions.
 *
 */

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();
    }

}