import com.sun.j3d.loaders.objectfile.ObjectFile;
import com.sun.j3d.loaders.ParsingErrorException;
import com.sun.j3d.loaders.IncorrectFormatException;
import com.sun.j3d.loaders.Scene;
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import java.io.*;
import com.sun.j3d.utils.behaviors.mouse.*;
import com.sun.j3d.utils.behaviors.vp.*;
import java.util.*;
import com.sun.j3d.utils.geometry.ColorCube;
import javax.media.j3d.RotPosPathInterpolator;

public class MyAni extends Applet {

        static char k;
        static boolean keyflag = false;
    private boolean spin = false;
    private boolean noTriangulate = false;
    private boolean noStripify = false;
    private double creaseAngle = 60.0;
    private String filename = "man.obj";
        static Alpha alpha;
        static RotPosPathInterpolator rotPosPath;
 
//####################################### KEY EVENT PROCESS #################################### 
    
        public class SimpleBehavior extends Behavior{

        private TransformGroup targetTG;
        private Transform3D rotation = new Transform3D();
        private double angle = 0.0;
        private WakeupCondition keyCriterion ;
        private boolean keyflag = false;

        // create SimpleBehavior
        SimpleBehavior(TransformGroup targetTG){
            this.targetTG = targetTG;
        }

       public void initialize(){
            // set initial wakeup condition
                        WakeupCriterion[] keyEvents = new WakeupCriterion[3];

                        keyEvents[0] = new WakeupOnAWTEvent( KeyEvent.KEY_PRESSED );
                        keyEvents[1] = new WakeupOnAWTEvent( KeyEvent.KEY_RELEASED );
                        keyEvents[2] = new WakeupOnAWTEvent( KeyEvent.KEY_TYPED );
                        keyCriterion = new WakeupOr( keyEvents );
                        wakeupOn( keyCriterion );
            
            
        }

        // behave
        // called by Java 3D when appropriate stimulus occures
        public void processStimulus(Enumeration criteria){
            // decode event
            
                        WakeupCriterion wakeup;
                        AWTEvent[] event;

                        while( criteria.hasMoreElements() )
                        {
                        wakeup = (WakeupCriterion) criteria.nextElement();
                        if( !(wakeup instanceof WakeupOnAWTEvent) )
                        continue;

                        event = ((WakeupOnAWTEvent)wakeup).getAWTEvent();
                        for( int i = 0; i < event.length; i++ )
                        {
                        if( event[i].getID() == KeyEvent.KEY_PRESSED )
                        {
                        processKeyEvent((KeyEvent)event[i]);
                        }
                }
        }
                    
       wakeupOn( keyCriterion );
    }
  
    public void processKeyEvent(KeyEvent event)
        {
                int keycode = event.getKeyCode();
        	

                if (keycode == KeyEvent.VK_A) {
                        System.out.println("A key press");
                        // for doing display SceneGraph     <-------- here
                }
        	
                if (keycode == KeyEvent.VK_B) {
                        System.out.println("B key press");
                        // for doing display SceneGraph     <-------- here
                }


                if(event.isShiftDown()) {
                System.out.println("shift press");
                angle += 0.1;
                }
	
                else if( event.isAltDown() ) {
                System.out.println("alt press");
                angle -= 0.1;
                }
        	
                else if( event.isControlDown()) System.out.println("ctrl press");
        	
                
        }
}

    public BranchGroup createSceneGraph(String args[]) {

//  Create the root of the branch graph
        BranchGroup objRoot = new BranchGroup();
	
        TransformGroup targetTG = new TransformGroup();
        Alpha alpha = new Alpha(-1, 10000);
        Transform3D rotation = new Transform3D();
        float[] knots = {0.0f, 0.5f ,1.0f};
        Quat4f[] quats = new Quat4f[3];
        Point3f[] positions = new Point3f[3];
        
        Quat4f[] quats1 = new Quat4f[3];
        Point3f[] positions1 = new Point3f[3];
        
        Quat4f[] quats2 = new Quat4f[3];
        Point3f[] positions2 = new Point3f[3];
        
        Quat4f[] quats3 = new Quat4f[3];
        Point3f[] positions3 = new Point3f[3];
	


    TransformGroup objScale = new TransformGroup();
    Transform3D t3d = new Transform3D();
    t3d.setScale(0.7);
    objScale.setTransform(t3d);
    objRoot.addChild(objScale);


        TransformGroup objTrans = new TransformGroup();
        objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
        objScale.addChild(objTrans);

        int flags = ObjectFile.RESIZE;
        if (!noTriangulate) flags |= ObjectFile.TRIANGULATE;
        if (!noStripify) flags |= ObjectFile.STRIPIFY;
        ObjectFile f = new ObjectFile(flags, 
          (float)(creaseAngle * Math.PI / 180.0));
        Scene s = null;
        try {
          s = f.load(filename);
        }
        catch (FileNotFoundException e) {
          System.err.println(e);
          System.exit(1);
        }
        catch (ParsingErrorException e) {
          System.err.println(e);
          System.exit(1);
        }
        catch (IncorrectFormatException e) {
          System.err.println(e);
          System.exit(1);
        }
          
//      objTrans.addChild(s.getSceneGroup());
        BranchGroup sGroup = s.getSceneGroup();
        objTrans.addChild(sGroup);
	

        TransformGroup humanTG = new TransformGroup();
        TransformGroup bodyTG = new TransformGroup();
        TransformGroup headTG = new TransformGroup();
        TransformGroup rarmTG = new TransformGroup();
        TransformGroup larmTG = new TransformGroup();

        TransformGroup lthighTG = new TransformGroup();
        TransformGroup rthighTG = new TransformGroup();
	
        TransformGroup lcalfTG = new TransformGroup();
        TransformGroup rcalfTG = new TransformGroup();
	
        Shape3D head = new Shape3D();
        Shape3D body = new Shape3D();
        Shape3D rarm = new Shape3D();
        Shape3D larm = new Shape3D();
        Shape3D rhand = new Shape3D();
        Shape3D lhand = new Shape3D();
        Shape3D rthigh = new Shape3D();
        Shape3D lthigh = new Shape3D();
        Shape3D rcalf = new Shape3D();
        Shape3D lcalf = new Shape3D();
        Shape3D rfoot = new Shape3D();
        Shape3D lfoot = new Shape3D();
	
	

	
        if (s.getNamedObjects() != null)
        {
                Hashtable objs = new Hashtable();
                objs = s.getNamedObjects();
        	
                for (Enumeration e = objs.elements() ; e.hasMoreElements() ;) {
    
        }
        	
                        head = (Shape3D) objs.get("head");
                        body = (Shape3D) objs.get("body");
                        rarm = (Shape3D) objs.get("rarm");
                        larm = (Shape3D) objs.get("larm");
                        rhand = (Shape3D) objs.get("rhand");
                        lhand = (Shape3D) objs.get("lhand");
                        rthigh = (Shape3D) objs.get("rthigh");
                        lthigh = (Shape3D) objs.get("lthigh");
                        rcalf = (Shape3D) objs.get("rcalf");
                        lcalf = (Shape3D) objs.get("lcalf");
                        rfoot = (Shape3D) objs.get("rfoot");
                        lfoot = (Shape3D) objs.get("lfoot");
                	

}

        // remove from previous parent
        int i = 0;

    for (Enumeration e = sGroup.getAllChildren() ; e.hasMoreElements() ;) {
                        i++ ;
     }

        for ( int j=0; j<i; j++)
        {
        sGroup.removeChild(0);
        }




// attach each part
	
                objTrans.addChild(humanTG);
        	
                humanTG.addChild(bodyTG);
                humanTG.addChild(headTG);
                humanTG.addChild(rarmTG);
                humanTG.addChild(larmTG);
                humanTG.addChild(rthighTG);
                humanTG.addChild(lthighTG);
                humanTG.addChild(rcalfTG);
                humanTG.addChild(lcalfTG);
        	
                bodyTG.addChild(body);
	
                headTG.addChild(head);
        	
                rarmTG.addChild(rarm);
                rarmTG.addChild(rhand);
                	
                larmTG.addChild(lhand);
                larmTG.addChild(larm);
                	
                rthighTG.addChild(rthigh);
                rcalfTG.addChild(rcalf);
                rcalfTG.addChild(rfoot);
        	
                lthighTG.addChild(lthigh);
                lcalfTG.addChild(lcalf);
                lcalfTG.addChild(lfoot);
        	

                AxisAngle4f axis = new AxisAngle4f(0.0f, 0.0f,0.0f, 0.0f);
                rotation.set(axis);
        	
//
                quats[0] = new Quat4f(0.0f, 0.0f, 0.0f, 1.0f);
                quats[1] = new Quat4f(-0.25881904f, 0.0f, 0.0f, 0.9659258f);
                quats[2] = new Quat4f(-0.4226182f, 0.0f, 0.0f, 0.90630776f);
//              quats[3] = quats[0]; 
                positions[0] = new Point3f(0.0f, 0.0f, 0.0f);
                positions[1] = new Point3f(0.0f, 0.08f, 0.17f);
                positions[2] = new Point3f(0.0f, 0.16f, 0.33f);
                //              positions[3] = positions[0];
//
                quats1[0] = new Quat4f(0.0f, 0.0f, 0.0f, 1.0f);
                quats1[1] = new Quat4f(0.25881904f, 0.0f, 0.0f, 0.9659258f);
                quats1[2] = new Quat4f(0.4226182f, 0.0f, 0.0f, 0.90630776f);
        	
                positions1[0] = new Point3f(0.0f, 0.0f, 0.0f);
                positions1[1] = new Point3f(0.0f, 0.08f, -0.17f);
                positions1[2] = new Point3f(0.0f, 0.16f, -0.33f);
//rthigh
                quats2[0] = new Quat4f(0.0f, 0.0f, 0.0f, 1.0f);
                quats2[1] = new Quat4f(0.08715574f, 0.0f, 0.0f, 0.9961947f);
                quats2[2] = new Quat4f(0.17364818f, 0.0f, 0.0f, 0.99848077f);
        	
                positions2[0] = new Point3f(0.0f, 0.0f, 0.0f);
                positions2[1] = new Point3f(0.0f, 0.04f, 0.0f);
                positions2[2] = new Point3f(0.0f, 0.08f, 0.0f);
//rcalf
                quats3[0] = new Quat4f(0.0f, 0.0f, 0.0f, 1.0f);
                quats3[1] = new Quat4f(0.25881904f, 0.0f, 0.0f, 0.9659258f);
                quats3[2] = new Quat4f(0.4226182f, 0.0f, 0.0f, 0.90630776f);
        	
                positions3[0] = new Point3f(0.0f, 0.0f, 0.0f);
                positions3[1] = new Point3f(0.0f, 0.0f, 0.1f);
                positions3[2] = new Point3f(0.0f, 0.0f, 0.18f);


        	

	
                rarmTG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                larmTG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                rthighTG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                rcalfTG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        	
                RotPosPathInterpolator rotPosPath = new RotPosPathInterpolator ( alpha, rarmTG, rotation, knots, quats, positions);
                RotPosPathInterpolator rotPosPath1 = new RotPosPathInterpolator ( alpha, larmTG, rotation, knots, quats1, positions1);
                RotPosPathInterpolator rotPosPath2 = new RotPosPathInterpolator ( alpha, rthighTG, rotation, knots, quats2, positions2);
                RotPosPathInterpolator rotPosPath3 = new RotPosPathInterpolator ( alpha, rcalfTG, rotation, knots, quats3, positions3);
        	
        	
                rotPosPath.setSchedulingBounds(new BoundingSphere());
                rotPosPath1.setSchedulingBounds(new BoundingSphere());
                rotPosPath2.setSchedulingBounds(new BoundingSphere());
                rotPosPath3.setSchedulingBounds(new BoundingSphere());
        	
                SimpleBehavior myRotationBehaviorarm = new SimpleBehavior(rarmTG);
                myRotationBehaviorarm.setSchedulingBounds(new BoundingSphere());
                objRoot.addChild(myRotationBehaviorarm);

                objRoot.addChild(rotPosPath);
                objRoot.addChild(rotPosPath1);
        	
                objRoot.addChild(rotPosPath2);
                objRoot.addChild(rotPosPath3);


                	


	
//              targetTG.addChild(new ColorCube(0.4));

        	
        BoundingSphere bounds =
          new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);
          
        if (spin) {
          Transform3D yAxis = new Transform3D();
          Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE,
                                          0, 0,
                                          4000, 0, 0,
                                          0, 0, 0);

          RotationInterpolator rotator =
              new RotationInterpolator(rotationAlpha, objTrans, yAxis,
                                       0.0f, (float) Math.PI*2.0f);
          rotator.setSchedulingBounds(bounds);
          objTrans.addChild(rotator);
        } else {
          // Create the rotate behavior node
          MouseRotate behavior = new MouseRotate();
          behavior.setTransformGroup(objTrans);
          objTrans.addChild(behavior);
          behavior.setSchedulingBounds(bounds);

          // Create the zoom behavior node
          MouseZoom behavior2 = new MouseZoom();
          behavior2.setTransformGroup(objTrans);
          objTrans.addChild(behavior2);
          behavior2.setSchedulingBounds(bounds);

          // Create the translate behavior node
          MouseTranslate behavior3 = new MouseTranslate();
          behavior3.setTransformGroup(objTrans);
          objTrans.addChild(behavior3);
          behavior3.setSchedulingBounds(bounds);
        }

        // Set up the background
        Color3f bgColor = new Color3f(0.05f, 0.05f, 0.5f);
        Background bgNode = new Background(bgColor);
        bgNode.setApplicationBounds(bounds);
        objRoot.addChild(bgNode);

        // Set up the ambient light
        Color3f ambientColor = new Color3f(0.1f, 0.1f, 0.1f);
        AmbientLight ambientLightNode = new AmbientLight(ambientColor);
        ambientLightNode.setInfluencingBounds(bounds);
        objRoot.addChild(ambientLightNode);

        // Set up the directional lights
        Color3f light1Color = new Color3f(1.0f, 1.0f, 0.9f);
        Vector3f light1Direction  = new Vector3f(4.0f, -7.0f, -12.0f);
        Color3f light2Color = new Color3f(0.3f, 0.3f, 0.4f);
        Vector3f light2Direction  = new Vector3f(-6.0f, -2.0f, -1.0f);

        DirectionalLight light1
            = new DirectionalLight(light1Color, light1Direction);
        light1.setInfluencingBounds(bounds);
        objRoot.addChild(light1);

        DirectionalLight light2
            = new DirectionalLight(light2Color, light2Direction);
        light2.setInfluencingBounds(bounds);
        objRoot.addChild(light2);

        return objRoot;
    }

  
    public MyAni(String args[]) {

      


        setLayout(new BorderLayout());
        GraphicsConfiguration config =
           SimpleUniverse.getPreferredConfiguration();

        Canvas3D c = new Canvas3D(config);
        
        add("Center", c);

        // Create a simple scene and attach it to the virtual universe
        BranchGroup scene = createSceneGraph(args);
        SimpleUniverse u = new SimpleUniverse(c);
        // This will move the ViewPlatform back a bit so the
        // objects in the scene can be viewed.
        u.getViewingPlatform().setNominalViewingTransform();
        u.addBranchGraph(scene);
    }



    //
    // The following allows ObjLoad to be run as an application
    // as well as an applet
    //
    public static void main(String[] args) {
    	

        new MainFrame(new MyAni(args), 600, 600);
	
	

    }
}