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

public class RotateBehavior extends MouseBehavior {
    double x_angle, y_angle,z_angle;
    double x_factor = .03;
    double y_factor = .03;
    double z_factor = .03;
    Axiss axiss = new Axiss();
    Point3d center = new Point3d(0.0,0.0,0.0);
    boolean object = false;
    private MouseBehaviorCallback callback = null;



    public RotateBehavior(TransformGroup transformGroup) {
        super(transformGroup);
    }
 
    /**
     * Creates a rotate behavior.
     * Note that this behavior still needs a transform
     * group to work on (use setTransformGroup(tg)) and
     * the transform group must add this behavior.
     * @param flags interesting flags (wakeup conditions).
     */
    public RotateBehavior(int flags) {
        super(flags);
        this.setType(X_AND_Y);
    }
    
    /**
     * Creates a default mouse rotate behavior.
     **/
    public RotateBehavior() {
        super(0);
        super.setType(X_AND_Y);
    }
    
    public RotateBehavior(TransformGroup transformGroup,int type) {
        super(transformGroup);
        super.setType(type);
        this.object = false;
    }

 
    public RotateBehavior(TransformGroup transformGroup,int type, Point3d center) {
        super(transformGroup);
        super.setType(type);
        this.center = center;
        this.object = true;
    }



    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 setAxiss(Axiss axiss){
    this.axiss = axiss;
    }
    /**
     * Return the x-axis movement multipler.
     **/
    public double getXFactor() {
        return x_factor;
    }

    /**
     * Return the y-axis movement multipler.
     **/
    public double getYFactor() {
        return y_factor;
    }


    /**
     * Set the x-axis amd y-axis movement multipler with factor.
     **/
    public void setFactor( double factor) {
        x_factor = y_factor = z_factor =  factor;
    }

    /**
     * Set the x-axis amd y-axis movement multipler with xFactor and yFactor
     * respectively.
     **/
    public void setFactor( double xFactor, double yFactor, double zFactor) {
        x_factor = xFactor;
        y_factor = yFactor;
        z_factor = zFactor;
    }

    public void processStimulus (Enumeration criteria) {
        WakeupCriterion wakeup;
        AWTEvent[] events;
        MouseEvent evt;
        int id;
        int dx, dy;
        
                                
         while (criteria.hasMoreElements()) {
            wakeup = (WakeupCriterion) criteria.nextElement();
            if (wakeup instanceof WakeupOnAWTEvent) {
                events = ((WakeupOnAWTEvent)wakeup).getAWTEvent();
                if (events.length > 0) {
                    evt = (MouseEvent) events[events.length-1];
                    processMouseEvent(evt);
                    if (((buttonPress)&&((flags & MANUAL_WAKEUP) == 0)) ||
                        ((wakeUp)&&((flags & MANUAL_WAKEUP) != 0))) {
                        id = evt.getID();
                        if ((id == MouseEvent.MOUSE_DRAGGED) && 
                            !evt.isMetaDown() && ! evt.isAltDown()){
                            x = evt.getX();
                            y = evt.getY();

                            dx = x - x_last;
                            dy = y - y_last;
                            
                            if (!reset){
                            
                                x_angle = dy * y_factor;
                                y_angle = dx * x_factor;
                                z_angle = dx * z_factor;

                        	
                                if(z_on && !x_on && !y_on){
                                transformY.setIdentity();
                                transformX.setRotation(new AxisAngle4d(this.axiss.getZAxis(),z_angle));}
                                
                                if(!z_on && x_on && !y_on){
                                transformY.setIdentity();
                                transformX.setRotation(new AxisAngle4d(this.axiss.getXAxis(),x_angle));}                                
                                                              
                                if(!z_on && !x_on && y_on){
                                transformX.setIdentity();
                                transformY.setRotation(new AxisAngle4d(this.axiss.getYAxis(),y_angle));}
                                
                                if(!z_on && x_on && y_on){
                               transformX.setRotation(new AxisAngle4d(this.axiss.getXAxis(),x_angle));
                               transformY.setRotation(new AxisAngle4d(this.axiss.getYAxis(),y_angle));}
                                
                                if(z_on && x_on && !y_on){
                                transformX.setRotation(new AxisAngle4d(this.axiss.getXAxis(),x_angle));
                                transformX.setRotation(new AxisAngle4d(this.axiss.getZAxis(),z_angle));}
                                
                                if(z_on && !x_on && y_on){
                                transformX.setRotation(new AxisAngle4d(this.axiss.getZAxis(),z_angle));
                                transformY.setRotation(new AxisAngle4d(this.axiss.getYAxis(),y_angle));}                      
                                
                        /*        Transform3D t3d = new Transform3D();
                                t3d.set(new Vector3d(-center.x,-center.y,-center.z));
                                transformGroup.setTransform(t3d);
                                transformGroup.getTransform(currXform);
                                                  
                                if (invert) {
                                    currXform.mul(currXform, transformX);
                                    currXform.mul(currXform, transformY);
                               
                                } else {
                                    currXform.mul(transformX, currXform);
                                    currXform.mul(transformY, currXform);
                               
                                }
                        
                                transformGroup.setTransform(currXform);*/
                                   
                    transformGroup.getTransform(currXform);
                    ((BoundingSphere)transformGroup.getBounds()).getCenter(center);
                    
                    Matrix4d mat = new Matrix4d();
                    // Remember old matrix
                    currXform.get(mat);
                    
                    // Translate to origin
                    currXform.setTranslation(new Vector3d(-center.x,-center.y,-center.z));
                    if (invert) {
                        currXform.mul(currXform, transformX);
                        currXform.mul(currXform, transformY);
                    } else {
                        currXform.mul(transformX, currXform);
                        currXform.mul(transformY, currXform);
                    }
                    
                    // Set old translation back
                    Vector3d translation = new 
                        Vector3d(mat.m03, mat.m13, mat.m23);
                    currXform.setTranslation(translation);
                    
                    // Update xform
                    transformGroup.setTransform(currXform);

                                
                                transformChanged( currXform );

                                if (callback!=null)
                                    callback.transformChanged( MouseBehaviorCallback.ROTATE, currXform );
                            }
                            else {
                                reset = false;
                            }

                            x_last = x;
                            y_last = y;
                        }
                        else if (id == MouseEvent.MOUSE_PRESSED) {
                            x_last = evt.getX();
                            y_last = evt.getY();
                        }
                    }
                }
            }
        }

        wakeupOn (mouseCriterion);
    }

    /**
     * Users can overload this method  which is called every time
     * the Behavior updates the transform
     *
     * Default implementation does nothing
     */
    public void transformChanged( Transform3D transform ) {
    }


    /**
     * The transformChanged method in the callback class will
     * be called every time the transform is updated
     */
    public void setupCallback( MouseBehaviorCallback callback ) {
        this.callback = callback;
    }
}
