

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.media.j3d.*;
import javax.vecmath.*;

/**
 * A mouse behavior that allows user to pick and drag scene graph objects.
 * Common usage:
 * <p>
 * 1. Create your scene graph.
 * <p>
 * 2. Create this behavior with root and canvas.
 * <p>
 * <blockquote><pre>
 *      PickRotateBehavior behavior = new PickRotateBehavior(canvas, root, bounds);
 *      root.addChild(behavior);
 * </pre></blockquote>
 * <p>
 * The above behavior will monitor for any picking events on
 * the scene graph (below root node) and handle mouse drags on pick hits.
 * Note the root node can also be a subgraph node of the scene graph (rather
 * than the topmost).
 */

public class PickRotateBehavior extends PickMouseBehavior implements MouseBehaviorCallback {
    RotateBehavior drag;
    int pickMode = PickTool.BOUNDS;
    private PickingCallback callback=null;
    private TransformGroup currentTG;

    /**
     * Creates a pick/rotate behavior that waits for user mouse events for
     * the scene graph. This method has its pickMode set to BOUNDS picking.
     * @param root   Root of your scene graph.
     * @param canvas Java 3D drawing canvas.
     * @param bounds Bounds of your scene.
     **/

    public PickRotateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds){
        super(canvas, root, bounds);
        drag = new RotateBehavior(RotateBehavior.MANUAL_WAKEUP);
        drag.setTransformGroup(currGrp);
        currGrp.addChild(drag);
        drag.setSchedulingBounds(bounds);
        this.setSchedulingBounds(bounds);
    }

    public void setFactor(double factor){
        this.drag.setFactor(factor);
    }

    /**
     * Creates a pick/rotate behavior that waits for user mouse events for
     * the scene graph.
     * @param root   Root of your scene graph.
     * @param canvas Java 3D drawing canvas.
     * @param bounds Bounds of your scene.
     * @param pickMode specifys PickObject.USE_BOUNDS or PickObject.USE_GEOMETRY.
     * Note: If pickMode is set to PickObject.USE_GEOMETRY, all geometry object in
     * the scene graph that allows pickable must have its ALLOW_INTERSECT bit set.
     **/

    public PickRotateBehavior(BranchGroup root, Canvas3D canvas, Bounds bounds,
    int pickMode){
        super(canvas, root, bounds);
        drag = new RotateBehavior(RotateBehavior.MANUAL_WAKEUP);
        drag.setTransformGroup(currGrp);
        currGrp.addChild(drag);
        drag.setSchedulingBounds(bounds);
        this.setSchedulingBounds(bounds);
        this.pickMode = pickMode;
    }

    public void setType(int type){
        this.drag.setType(type);

    }



    /**
     * Update the scene to manipulate any nodes. This is not meant to be
     * called by users. Behavior automatically calls this. You can call
     * this only if you know what you are doing.
     *
     * @param xpos Current mouse X pos.
     * @param ypos Current mouse Y pos.
     **/
    public void updateScene(int xpos, int ypos){
        TransformGroup tg = null;

        if (!mevent.isMetaDown() && !mevent.isAltDown()){

            pickCanvas.setShapeLocation(xpos, ypos);
            PickResult pr = pickCanvas.pickClosest();
            if ((pr != null) &&
            ((tg = (TransformGroup)pr.getNode(PickResult.TRANSFORM_GROUP))
            != null) &&
            (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_READ)) &&
            (tg.getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE))){
                if(lastPick != null){
                    if(!(lastPick.equals(((BGroup)pr.getNode(PickResult.BGROUP))))){
                        lastPick.setDeselected();
                    }
                }
                lastPick = ((BGroup)pr.getNode(PickResult.BGROUP));
                lastPick.setSelected();
                drag.setAxiss(lastPick.getAxiss());
                drag.setTransformGroup(tg);
                drag.wakeup();
                currentTG = tg;
            } else if (callback!=null)
            callback.transformChanged( PickingCallback.NO_PICK, null );
        }
    }

    /**
     * Callback method from RotateBehavior
     * This is used when the Picking callback is enabled
     */
    public void transformChanged( int type, Transform3D transform ) {
        callback.transformChanged( PickingCallback.ROTATE, currentTG );
    }

    /**
     * Register the class @param callback to be called each
     * time the picked object moves
     */
    public void setupCallback( PickingCallback callback ) {
        this.callback = callback;
        if (callback==null)
        drag.setupCallback( null );
        else
        drag.setupCallback( this );
    }
}

