package cz.fidentis.analyst.canvas;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import javax.swing.SwingUtilities;

/**
 * This object is invoked when the mouse interacts with the OpenGL canvas.
 * These interactions are transformed into 3D manipulation of the scene.
 * 
 * @author Richard Pajersky
 */
public class MouseRotationListener extends MouseAdapter {
    
    private final Canvas canvas;
    
    private float lastX = 0;
    private float lastY = 0;
    
    private static double rotationSpeed = 0.4;
    private static double moveSpeed = 0.4;

    /**
     * Constructor.
     * 
     * @param canvas Canvas
     * @throws IllegalArgumentException if the canvas is {@code null}
     */
    public MouseRotationListener(Canvas canvas) {
        if (canvas == null) {
            throw new IllegalArgumentException("canvas is nuull");
        }
        this.canvas = canvas;
    }

    /**
     * Left mouse button dragging rotates
     * Right mouse button dragging moves
     * Middle mouse button dragging resets rotation and zoom
     * @param evt Mouse position info
     */
    @Override
    public void mouseDragged(MouseEvent evt) {
        if (SwingUtilities.isLeftMouseButton(evt)) {
            double rotateX = -(lastY - evt.getY()) * rotationSpeed;
            double rotateY = +(lastX - evt.getX()) * rotationSpeed;
            if (Math.abs(rotateX) < Math.abs(rotateY)) {
                rotateX = 0;
            } else if (Math.abs(rotateY) < Math.abs(rotateX)) {
                rotateY = 0;
            }
            canvas.getCamera().rotate(rotateX, rotateY);
        }
        if (SwingUtilities.isRightMouseButton(evt)) {
            double moveX = -(lastX - evt.getX()) * moveSpeed;
            double moveY = -(lastY - evt.getY()) * moveSpeed;
            canvas.getCamera().move(moveX, moveY);
        }
        if (SwingUtilities.isMiddleMouseButton(evt)) {
            canvas.getCamera().initLocation();
        }
        lastX = evt.getX();
        lastY = evt.getY();
        canvas.renderScene();
    }

    /**
     * Actualize mouse movement
     * @param e Mouse position info
     */
    @Override
    public void mouseMoved(MouseEvent e) {
        lastX = e.getX();
        lastY = e.getY();
    }

    /**
     * Zoom in or out based on mouse wheel movement
     * @param evt Mouse wheel info
     */
    @Override
    public void mouseWheelMoved(MouseWheelEvent evt) {
        if (evt.getWheelRotation() > 0) {
            canvas.getCamera().zoomIn(-5 * evt.getWheelRotation());
        } else {
            canvas.getCamera().zoomOut(5 * evt.getWheelRotation());
        }
        canvas.renderScene();
    }
    
    /**
     * Middle mouse button click resets rotation and zoom
     * @param evt Mouse position info
     */
    @Override
    public void mouseClicked(MouseEvent evt) {
        if (SwingUtilities.isMiddleMouseButton(evt)) {
            canvas.getCamera().initLocation();
            canvas.renderScene();
        }
    }
    
    /**
     * @return Rotation speed
     */
    public static double getRotationSpeed() {
        return rotationSpeed;
    }

    /**
     * Sets rotation speed
     * @param rotationSpeed 
     */
    public static void setRotationSpeed(double rotationSpeed) {
        MouseRotationListener.rotationSpeed = rotationSpeed;
    }

    /**
     * @return Move speed
     */
    public static double getMoveSpeed() {
        return moveSpeed;
    }

    /**
     * Sets move speed
     * @param moveSpeed 
     */
    public static void setMoveSpeed(double moveSpeed) {
        MouseRotationListener.moveSpeed = moveSpeed;
    }

}
