/*
!=======================================================================
!
!  PROGRAM  PHASE-Viewer  (PHASE-Viewer 2014.01 ver.3.3.0)
!
!  Created on 2006/09/21, 19:12
!  AUTHOR(S): KOGA, Junichiro
!  File : MyMouseZoom.java
!  
!  Contact address :  Phase System Consortium
!                     E-mail: phase_system@nims.go.jp URL https://azuma.nims.go.jp
!
!
!   Since 2002, this program set had been intensively developed as a part of the following 
!  national projects supported by the Ministry of Education, Culture, Sports, Science and
!  Technology (MEXT) of Japan; "Frontier Simulation Software for Industrial Science
!  (FSIS)" from 2002 to 2005, "Revolutionary Simulation Software (RSS21)" from 2006 to
!  2008. "Research and Development of Innovative Simulation Software (RISS)" from 2008
!  to 2013. These projects is lead by the Center for Research on Innovative Simulation 
!  Software (CISS), the Institute of Industrial Science (IIS), the University of Tokyo.
!   Since 2013, this program set has been further developed centering on PHASE System
!  Consortium. 
!   The activity of development of this program set has been supervised by Takahisa Ohno.
!
!=======================================================================
 */

package ciss.phase_viewer.acviewer.mouselistener;

import java.awt.AWTEvent;
import java.awt.event.MouseEvent;
import java.util.Enumeration;

import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.WakeupCriterion;
import javax.media.j3d.WakeupOnAWTEvent;
import javax.vecmath.Vector3d;

import com.sun.j3d.utils.behaviors.mouse.MouseBehavior;
import com.sun.j3d.utils.behaviors.mouse.MouseBehaviorCallback;

/**
 * MouseZoom is a Java3D behavior object that lets users control the Z axis
 * translation of an object via a mouse drag motion with the second mouse
 * button. See MouseRotate for similar usage info.
 */

public class MyMouseZoom extends MouseBehavior {
    double z_factor;
    Vector3d translation;

    private MouseBehaviorCallback callback = null;

    /**
     * Creates a zoom behavior given the transform group.
     * 
     * @param transformGroup
     *            The transformGroup to operate on.
     */
    public MyMouseZoom(TransformGroup transformGroup) {
        super(transformGroup);
        translation = new Vector3d();
    }

    /**
     * Creates a default mouse zoom behavior.
     **/
    public MyMouseZoom() {
        super(0);
        translation = new Vector3d();
    }

    /**
     * Creates a zoom 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
     */
    public MyMouseZoom(int flags) {
        super(flags);
        translation = new Vector3d();
    }

    public void initialize() {
        super.initialize();
        z_factor = .04;
        if ((flags & INVERT_INPUT) == INVERT_INPUT) {
            z_factor *= -1;
            invert = true;
        }
    }

    /**
     * Return the y-axis movement multipler.
     **/

    public double getFactor() {
        return z_factor;
    }

    /**
     * Set the y-axis movement multipler with factor.
     **/

    public void setFactor(double factor) {
        z_factor = factor;
    }

    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)
                                && ((MouseEvent) event[i]).isAltDown()
                                && !((MouseEvent) event[i]).isMetaDown()) {

                            x = ((MouseEvent) event[i]).getX();
                            y = ((MouseEvent) event[i]).getY();

                            dx = x - x_last;
                            dy = y - y_last;

                            if (!reset) {
                                transformGroup.getTransform(currXform);

                                translation.z = dy * z_factor;
                                double scale = 1.1d;
                                if (dy < 0)
                                    scale = 1.d / scale;
                                Transform3D scale3d = new Transform3D();
                                scale3d.set(scale);
                                currXform.mul(scale3d);
                                // transformX.set(translation);
                                //
                                // if (invert) {
                                // currXform.mul(currXform, transformX);
                                // } else {
                                // currXform.mul(transformX, currXform);
                                // }

                                transformGroup.setTransform(currXform);

                                transformChanged(currXform);

                                if (callback != null)
                                    callback.transformChanged(
                                            MouseBehaviorCallback.TRANSLATE,
                                            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);
    }

    /**
     * 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;
    }
}
