// imports for Java 3D
import javax.media.j3d.*;
import javax.vecmath.*;

public class OttoHead
{
        private LocalRotInterpolator rotator;           	
        private TransformGroup headTransformGroup;              // transform group for all head objects
        private OttoEyes Eyes;                                          	
        private OttoMouth Mouth;
        private OttoEyeBrows Brows;
        private OttoEyeLids Lids;
	
        public OttoHead(Node head, Shape3D headPivot)
        {
                // Initialize a local rotation interpolator
                rotator = new LocalRotInterpolator(headPivot);

                // Setup the interpolator constraints
                rotator.setBoundsRadius(.25f);
                rotator.setMaxPosXAngleRot((float) Math.PI/6);
                rotator.setMaxNegXAngleRot((float) -Math.PI/6);
                rotator.setMaxPosYAngleRot((float) Math.PI/2);
                rotator.setMaxNegYAngleRot((float) -Math.PI/2);
                rotator.setMaxPosZAngleRot((float) Math.PI/4);
                rotator.setMaxNegZAngleRot((float) -Math.PI/4);

                // Add the head to the transform group for the local rotation interpolator
                rotator.addChild(head);
        	
                // Get the transform group for the local rotation interpolator
                this.headTransformGroup = rotator.getTransformGroup();
        	
                // Point this object's rotator variable to the rotator we setup 	
                this.rotator = rotator;
        }

        // Sets up the eyes and adds them to the transform group for the head
        public void setupEyes(Node leftEye, Node rightEye, Shape3D leftEyePivot, 
                                                  Shape3D rightEyePivot)
        {
                // Initialize the eye object
                Eyes = new OttoEyes(leftEye, rightEye, leftEyePivot, rightEyePivot);

                // Add the eyes to the local rotation interpolator
                rotator.addChild(Eyes.getEyesGroup());
        }

        // Sets up the eyelids and adds them to the transform group for the head
        public void setupEyeLids(Node leftUpperEyeLid, Node rightUpperEyeLid, 
                                                         Shape3D leftLidPivot, Shape3D rightLidPivot)
        {
                // Initialize the eyelid object
                Lids = new OttoEyeLids(leftUpperEyeLid, rightUpperEyeLid, leftLidPivot, 
                                                           rightLidPivot);
        	
                // Add the eye lids to the local rotation interpolator
                rotator.addChild(Lids.getEyeLidGroup());
        }
        	
        // Sets up the eyebrows and adds them to the transform group for the head
        public void setupEyeBrows(Node leftBrowNeutral, Node rightBrowNeutral,
                                                Node leftBrowRaised, Node rightBrowRaised,
                                                Node leftBrowArched, Node rightBrowArched)
        {
                // Initialize the eye brows
                Brows = new OttoEyeBrows(leftBrowNeutral, rightBrowNeutral, leftBrowRaised, 
                                                                 rightBrowRaised, leftBrowArched, rightBrowArched);
        	
                // Add the eye brows to the scene graph
                rotator.addChild(Brows.getLeftBrowGroup());
                rotator.addChild(Brows.getRightBrowGroup());
        }
	
        // Sets up the mouth and adds it to the transform group for the head
        public void setupMouth(Node closedMouth, Node openSlightlyMouth, Node openMouth,
                                         Node oMouth, Node smileClosedMouth, Node smileSlightlyOpenMouth,
                                         Node frownClosedMouth)
        {
                // Initialize the mouth object
                Mouth = new OttoMouth(closedMouth, openSlightlyMouth, openMouth, oMouth,
                                                          smileClosedMouth, smileSlightlyOpenMouth, frownClosedMouth);
        	
                // Add the mouth to the transform group for the head
                rotator.addChild(Mouth.getMouthGroup());
        }

        // Returns the transform group that contains the head, eyes, etc.
        public TransformGroup getHeadGroup()
        {
                return(headTransformGroup);
        }
	
        // ***********************************************************************
        // The following methods handle eye and eyelid movement
        // ***********************************************************************

        // Handles eye movement
        public void Look(int direction)
        {
                Eyes.Look(direction);
        }
        // Open the left eye lid
        public void openLeftLid()
        {
                Lids.openLeftLid();
        }

        // Open the left eye lid wide
        public void openWideLeftLid()
        {
                Lids.openWideLeftLid();	
        }
	
        // Open the left eye lid fully
        public void openFullyLeftLid()
        {
                Lids.openFullyLeftLid();
        }
	
        // Close the left eye lid
        public void closeLeftLid()
        {       	
                Lids.closeLeftLid();
        }
	
        // Mostly closes the left eye lid
        public void closeMostlyLeftLid()
        {
                Lids.closeMostlyLeftLid();
        }
	
        // Partially close the left eye lid
        public void closePartiallyLeftLid()
        {
                Lids.closePartiallyLeftLid();
        }

        // Open the right eye lid
        public void openRightLid()
        {
                Lids.openRightLid();
        }

        // Open the right eye lid wide
        public void openWideRightLid()
        {
                Lids.openWideRightLid();
        }
	
        // Open the right eye lid fully
        public void openFullyRightLid()
        {
                Lids.openFullyRightLid();
        }
	
        // Close the right eye lid
        public void closeRightLid()
        {       	
                Lids.closeRightLid();
        }
	
        // Mostly close the right lid
        public void closeMostlyRightLid()
        {
                Lids.closeMostlyRightLid();
        }
	
        // Partially close the right eye lid
        public void closePartiallyRightLid()
        {
                Lids.closePartiallyRightLid();
        }

        // ***********************************************************************
        // The following methods handle eyebrow movement
        // ***********************************************************************

        // Arches the left eye brow
        public void archLeftBrow()
        {
                Brows.archLeft();
        }
	
        // Arches the right eye brow
        public void archRightBrow()
        {
                Brows.archRight();
        }
	
        // Displays the default left eye brow
        public void neutralLeftBrow()
        {
                Brows.neutralLeft();
        }
	
        // Displays the default right eye brow
        public void neutralRightBrow()
        {
                Brows.neutralRight();
        }
	
        // Raises the left eye brow
        public void raiseLeftBrow()
        {
                Brows.raiseLeft();
        }
	
        // Raises the right eye brow
        public void raiseRightBrow()
        {
                Brows.raiseRight();
        }

        // ***********************************************************************
        // The following methods handle mouth movement
        // ***********************************************************************
        // Closes the mouth
        public void closeMouth()
        {
                Mouth.closeMouth();
        }
	
        // Opens the mouth
        public void openMouth()
        {
                Mouth.openMouth();
        }
	
        // Opens the mouth slightly
        public void openMouthSlightly()
        {
                Mouth.openMouthSlightly();
        }
	
        // Forms the mouth into an "O" shape
        public void oShapeMouth()
        {
                Mouth.oShapeMouth();
        }

        // Closed mouth smile
        public void smileClosedMouth()
        {
                Mouth.smileClosedMouth();
        }
	
        // Open mouth smile
        public void smileSlightlyOpenMouth()
        {
                Mouth.smileSlightlyOpenMouth();
        }
	
        // Closed mouth frown
        public void frownClosedMouth()
        {
                Mouth.frownClosedMouth();
        }
	
        // ***********************************************************************
        // The following methods handle head rotation
        // ***********************************************************************
	
        // Multiple simulataneous head movements at default durations (in background)
        public void rotate(float xAngle, float yAngle, float zAngle)
        {
                rotator.Rotate(xAngle, yAngle, zAngle);
        }

        // Multiple simulataneous head movements at given durations (in background)
        public void rotate(float xAngle, float yAngle, float zAngle,
                                           long xDuration, long yDuration, long zDuration)
        {
                rotator.Rotate(xAngle, yAngle, zAngle, xDuration, yDuration, zDuration);
        }
	
        // Multiple simultaneous head movements at default durations, waits until done
        public void rotateWait(float xAngle, float yAngle, float zAngle)
        {
        }
	
	
        // Multiple simultaneous head movements at given durations, waits until done
        public void rotateWait(float xAngle, float yAngle, float zAngle,
                                                   long xDuration, long yDuration, long zDuration)
        {
        }

}
