import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.media.j3d.*;
import javax.vecmath.*;

/**
 * 
 */

public class RotationBehavior extends com.sun.j3d.utils.behaviors.mouse.MouseBehavior
{
	TransformGroup center = new TransformGroup();
	Transform3D centerXform = new Transform3D();
	double x_angle = .02;
	double y_angle = .02; 
	double x_factor = .02;
	double y_factor = .02;
	/**
	 * Creates a default mouse rotate behavior.
	 **/
	public RotationBehavior () 
	{
		super(0);
	}
	/**
	 *
	*/
  	public RotationBehavior (int flags) 
	{
	  	super(flags);
   	}   
	/**
	 * Creates a rotate behavior given the transform group.
	 * @param transformGroup The transformGroup to operate on.
	 */
	public RotationBehavior (TransformGroup transformGroup, TransformGroup center) 
	{
		super(transformGroup);
		this.center = center;
	}
 	 /**
 	  * Return the x-axis movement multipler.
  	 **/
	public double getXFactor() 
	{
			return x_factor;
  	}  
  	/**
   	 * Return the y-axis movement multipler.
   	 **/
	public double getYFactor() 
	{
			return y_factor;
  	}  
  	public void initialize() 
	{
		super.initialize();
		x_angle = 0;
		y_angle = 0;
		if ((flags & INVERT_INPUT) == INVERT_INPUT) 
		{
			invert = true;
	   		x_factor *= -1;
			y_factor *= -1;
		}
  	}  
	public void processStimulus (Enumeration criteria) 
	{
		WakeupCriterion wakeup;
		AWTEvent[] event;
	  	int id;
	  	int dx, dy;

	  	while (criteria.hasMoreElements()) 
		{
			wakeup = (WakeupCriterion) criteria.nextElement();
			if (wakeup instanceof WakeupOnAWTEvent) 
			{
					event = ((WakeupOnAWTEvent)wakeup).getAWTEvent();
					for (int i=0; i<event.length; i++) 
				{
 				      processMouseEvent((MouseEvent) event[i]);
				      if (((buttonPress)&&((flags & MANUAL_WAKEUP) == 0)) || ((wakeUp)&&((flags & MANUAL_WAKEUP) != 0)))
					{								
						id = event[i].getID();
						if (id == MouseEvent.MOUSE_DRAGGED)
						{
				              	x = ((MouseEvent)event[i]).getX();
				                  y = ((MouseEvent)event[i]).getY();

				                  dx = x_last - x;
				                  dy = y_last - y;
							if (!reset)
							{	    
								x_angle = dy * y_factor;
								y_angle = dx * x_factor;
		    
								transformX.rotX(x_angle);
								transformY.rotY(y_angle);
		    
								Matrix4d currentMat = new Matrix4d();
								Matrix4d centerMat = new Matrix4d();
		    
		    						// Remember old matrix
								center.getTransform(centerXform);
		    						centerXform.get(centerMat);

								transformGroup.getTransform(currXform);
		    						currXform.get(currentMat);

								// Translate to origin
								currXform.setTranslation(new Vector3d(currentMat.m03-centerMat.m03,
														  currentMat.m13-centerMat.m13,
														  currentMat.m23-centerMat.m23));

								currXform.mul(transformX, currXform);
								currXform.mul(transformY, currXform);
		    
		    						// Set old translation back
		    						currXform.get(currentMat);
								currXform.setTranslation(new Vector3d(currentMat.m03+centerMat.m03,
														  currentMat.m13+centerMat.m13,
														  currentMat.m23+centerMat.m23));

		   						// Update xform
		    						transformGroup.setTransform(currXform);

		    						transformChanged( currXform );
		  					}
		  					else 
							{
		    						reset = false;
		  					}

				  				x_last = x;
				 					y_last = y;
			   				}
			   				else if (id == MouseEvent.MOUSE_PRESSED) 
						{
				  				x_last = ((MouseEvent)event[i]).getX();
				  				y_last = ((MouseEvent)event[i]).getY();
			   				}
	      			}
	    			}
		 		}
	  	}
	      wakeupOn (mouseCriterion);
	}
	/** 
	 * Set the center of rotation
	 */
	public void setCenter( TransformGroup center )
	{
		this.center = center;
	}
  	/**
   	 * Set the x-axis amd y-axis movement multipler with factor.
   	 **/
  	public void setFactor( double factor) 
	{
			x_factor = y_factor = factor;
	}
	/**
	 * Set the x-axis amd y-axis movement multipler with xFactor and yFactor
	 * respectively.
	 **/
	public void setFactor( double xFactor, double yFactor) 
	{
		x_factor = xFactor;
		y_factor = yFactor;    
	}
  	/**
		 * Users can overload this method  which is called every time
		 * the Behavior updates the transform
		 *
		 * Default implementation does nothing
		 */
  	public void transformChanged( Transform3D transform ) 
	{
  	}  
}
