import java.applet.*;
import java.awt.*;
import java.awt.Frame;
import java.awt.event.*;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.behaviors.keyboard.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import javax.swing.*;
import com.sun.j3d.loaders.*;
import java.io.*;

import java.util.*;
import com.sun.j3d.utils.behaviors.mouse.*;

public class TestMouseNavigator extends Applet implements MouseListener, MouseMotionListener
{
        BranchGroup branchGroup;

        TransformGroup transformGroup;
        Canvas3D canvas3D;
        SimpleUniverse simpleUniverse;

        static int height = 200;
        static int width = 300;

        double[] rotationAnglesAroundX;
        double rotationStepAroundX = (Math.PI/2) / height;
        int indexAroundX;
        double rotationAroundX;

        double[] rotationAnglesAroundY;
        double rotationStepAroundY = (Math.PI/2) / width;
        int indexAroundY;
        double rotationAroundY;


        public void init()
        {
                long start = System.currentTimeMillis();
                setLayout(new BorderLayout());
                GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
                canvas3D = new Canvas3D(config);
                canvas3D.addMouseListener(this);
                canvas3D.addMouseMotionListener(this);
                add("Center", canvas3D);
                simpleUniverse = new SimpleUniverse(canvas3D);


                Transform3D transform3D = new Transform3D();
                transform3D.set( new Vector3d( 0.0, 0.0, -20.0 ) );

                transformGroup = new TransformGroup();
                transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                transformGroup.setTransform(transform3D);

                ColorCube c1 = new ColorCube();
                transformGroup.addChild(c1);

                branchGroup= new BranchGroup();
                branchGroup.addChild( transformGroup );

                //MouseRotate mouseRotate = new MouseRotate( transformGroup );
                //BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);
                //mouseRotate.setSchedulingBounds(bounds);
                //branchGroup.addChild( mouseRotate );

                simpleUniverse.addBranchGraph( branchGroup );

                long end = System.currentTimeMillis();
                System.out.println((end-start)/1000);

                initiateRotationAngles();
        }

        public void initiateRotationAngles()
        {
                rotationAnglesAroundX = new double[height*2];
                for(int i = height-1; i > -1; i--)
                {
                        if(i == height-1)
                        {
                                rotationAnglesAroundX[i] = 0;
                        }
                        else
                        {
                                rotationAnglesAroundX[i] = rotationAnglesAroundX[i+1] + rotationStepAroundX;
                        }
                }

                for(int i = height; i < height*2; i++)
                {
                        if(i == height)
                        {
                                rotationAnglesAroundX[i] = 0;
                        }
                        else
                        {
                                rotationAnglesAroundX[i] = rotationAnglesAroundX[i-1] + rotationStepAroundX;
                        }
                }

                rotationAnglesAroundY = new double[width*2];
                for(int i = width-1; i > -1; i--)
                {
                        if(i == width-1)
                        {
                                rotationAnglesAroundY[i] = 0;
                        }
                        else
                        {
                                rotationAnglesAroundY[i] = rotationAnglesAroundY[i+1] + rotationStepAroundY;
                        }
                }

                for(int i = width; i < width*2; i++)
                {
                        if(i == width)
                        {
                                rotationAnglesAroundY[i] = 0;
                        }
                        else
                        {
                                rotationAnglesAroundY[i] = rotationAnglesAroundY[i-1] + rotationStepAroundY;
                        }
                }
        }


        public void mouseDragged(MouseEvent e)
        {
        }

        public void mouseMoved(MouseEvent e)
        {
                double diffY = 0;
                double diffX = 0;

                //Look up
                if( e.getY() < height)
                {
                        //Passing from below to above
                        if(indexAroundX >= height)
                        {
                                rotX(transformGroup, rotationAnglesAroundX[indexAroundX]);
                                rotationAroundX = 0;
                                indexAroundX = e.getY();
                        }

                        //Rot up
                        diffY = rotationAnglesAroundX[e.getY()] - rotationAroundX;
                        rotationAroundX = rotationAnglesAroundX[e.getY()];
                        indexAroundX = e.getY();
                        rotX(transformGroup, diffY);
                }
                //Look down
                else if( e.getY() >= height)
                {
                        //Passing from above to below
                        if(indexAroundX < height)
                        {
                                rotX(transformGroup, -rotationAnglesAroundX[indexAroundX]);
                                rotationAroundX = 0;
                                indexAroundX = e.getY();
                        }

                        //Rot down
                        diffY = rotationAnglesAroundX[e.getY()] - rotationAroundX;
                        rotationAroundX = rotationAnglesAroundX[e.getY()];
                        indexAroundX = e.getY();
                        rotX(transformGroup, -diffY);
                }
/*
                //Look left
                if( e.getX() < width)
                {
                        //Passing from right to left
                        if(indexAroundY >= width)
                        {
                                rotY(transformGroup, rotationAnglesAroundY[indexAroundY]);
                                rotationAroundY = 0;
                                indexAroundY = e.getX();
                        }

                        //Rot left
                        diffX = rotationAnglesAroundY[e.getX()] - rotationAroundY;
                        rotationAroundY = rotationAnglesAroundY[e.getX()];
                        indexAroundY = e.getX();
                        rotY(transformGroup, diffX);
                }
                //Look right
                else if( e.getX() >= width)
                {
                        //Passing from left to right
                        if(indexAroundY < width)
                        {
                                rotY(transformGroup, -rotationAnglesAroundY[indexAroundY]);
                                rotationAroundY = 0;
                                indexAroundY = e.getX();
                        }

                        //Rot right
                        diffX = rotationAnglesAroundY[e.getX()] - rotationAroundY;
                        rotationAroundY = rotationAnglesAroundY[e.getX()];
                        indexAroundY = e.getX();
                        rotY(transformGroup, -diffX);
                }
*/
        }

        public void mouseClicked(MouseEvent e)
        {
        }

        public void mousePressed(MouseEvent e)
        {
        }

        public void mouseReleased(MouseEvent e)
        {
        }

        public void mouseEntered(MouseEvent e)
        {
        }

        public void mouseExited(MouseEvent e)
        {
        }

        public TransformGroup rotX(TransformGroup transformGroup, double angle)
        {
                Transform3D oldTransform3D = new Transform3D();
                Transform3D rotationTransform3D = new Transform3D();
                transformGroup.getTransform(oldTransform3D);
                rotationTransform3D.rotX(angle);
                oldTransform3D.mul(rotationTransform3D);
                transformGroup.setTransform( oldTransform3D );
                return transformGroup;
        }

        public TransformGroup rotY(TransformGroup transformGroup, double angle)
        {
                Transform3D oldTransform3D = new Transform3D();
                Transform3D rotationTransform3D = new Transform3D();
                transformGroup.getTransform(oldTransform3D);
                rotationTransform3D.rotY(angle);
                oldTransform3D.mul(rotationTransform3D);
                transformGroup.setTransform( oldTransform3D );
                return transformGroup;
        }

        public static void main(String[] args)
        {
                Frame frame = new MainFrame(new TestMouseNavigator(), width*2, height*2);
    }
}