/*
 *      @(#)SimpleVrml97Viewer.java 1.6 98/09/18 14:58:38
 *
 * Copyright (c) 1996-1998 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
 * modify and redistribute this software in source and binary code form,
 * provided that i) this copyright notice and license appear on all copies of
 * the software; and ii) Licensee does not utilize the software in a manner
 * which is disparaging to Sun.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
 * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
 * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
 * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
 * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
 * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
 * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
 * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 *
 * This software is not designed or intended for use in on-line control of
 * aircraft, air traffic, aircraft navigation or aircraft communications; or in
 * the design, construction, operation or maintenance of any nuclear
 * facility. Licensee represents and warrants that it will not use or
 * redistribute the Software for such purposes.
 *
 * @Author: Doug Gehringer
 * @Author: Rick Goldberg
 */



import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
import com.sun.j3d.utils.behaviors.mouse.MouseZoom;
import com.sun.j3d.utils.behaviors.mouse.MouseTranslate;
import javax.media.j3d.*;
import javax.vecmath.*;
import java.net.URL;
import java.net.MalformedURLException;

import com.sun.j3d.loaders.vrml97.VrmlLoader;
import com.sun.j3d.loaders.Scene;

//
// DCS - Daniel Selman dselman@tornadolabs.com
//
//      2000/01/11 debugged picking to report names of shapes
// loaded from VRML file and added J3dTree support
//
// DCS - added J3dTree viewer
import com.tornadolabs.j3dtree.*;


//*******************************************************
//JN all comments starting with "JN" new or additional !!
//*******************************************************

//JN additional classes
import java.util.Hashtable;
import com.sun.j3d.utils.behaviors.picking.PickObject;


public class SimpleVrml97Viewer extends Applet implements ActionListener, MouseListener {

    String              location;
    Canvas3D            canvas;
    SimpleUniverse      universe;
    TransformGroup      vpTransGroup;
    VrmlLoader          loader;
    View                view;
    Panel               panel;
    Label               label;
    BranchGroup         sceneRoot;
    TransformGroup      examineGroup;
    BranchGroup         sceneGroup;
    BoundingSphere      sceneBounds;
    DirectionalLight    headLight;
    AmbientLight        ambLight;
    TextField           textField;
    Cursor              waitCursor;
    Cursor              handCursor;
    
    // DCS - added J3dTree support
    Java3dTree m_Java3dTree = new Java3dTree();

    Scene scene = null; //JN now defined here !
    SceneGraphPath sceneGraphPath;
    SceneGraphPath[] sceneGraphPathAll;
    SceneGraphPath[] sceneGraphPathAll2;

    SimpleVrml97Viewer(String initLocation) {
        setLayout(new BorderLayout());
        canvas = new Canvas3D(null);
        add("Center",canvas);

        panel = new Panel();
        panel.setLayout(new FlowLayout(FlowLayout.LEFT));
        textField = new TextField(initLocation,60);
        textField.addActionListener(this);
        label = new Label("Location:");
        panel.add(label);
        panel.add(textField);
        add("North",panel);

        waitCursor = new Cursor(Cursor.WAIT_CURSOR);
        handCursor = new Cursor(Cursor.HAND_CURSOR);

        universe = new SimpleUniverse(canvas);
        ViewingPlatform viewingPlatform = universe.getViewingPlatform();
        vpTransGroup = viewingPlatform.getViewPlatformTransform();
        Viewer viewer = universe.getViewer();
        view = viewer.getView();

        setupBehavior();
	
        loader = new VrmlLoader();
	
        gotoLocation(initLocation);
	
        // DCS - added J3dTree support
        m_Java3dTree.updateNodes( universe );
	
  canvas.addMouseListener(this);
  
    }

    public void actionPerformed(ActionEvent ae) {
        gotoLocation(textField.getText());
    }

    void gotoLocation(String location) {

        canvas.setCursor(waitCursor);

        if (sceneGroup != null) {
            sceneGroup.detach();
        }
//JN  will be defined global
//JN    Scene scene = null;
        try {
            URL loadUrl = new URL(location);
            try {
                // load the scene
                scene = loader.load(new URL(location));
            } catch (Exception e) {
                System.out.println("Exception loading URL:" + e);
            }
        } catch (MalformedURLException badUrl) {
            // location may be a path name
            try {
                // load the scene
                scene = loader.load(location);
            } catch (Exception e) {
                System.out.println("Exception loading file from path:" + e);
            }
        }
        if (scene != null) {
            // get the scene group
            sceneGroup = scene.getSceneGroup();
           
            sceneGroup.setCapability(BranchGroup.ALLOW_DETACH);
            sceneGroup.setCapability(BranchGroup.ALLOW_BOUNDS_READ);

//JN here starts the new code in this area *************************************

                sceneGroup.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
                sceneGroup.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
          	
      sceneGroup.setCapability(BranchGroup.ALLOW_PICKABLE_READ);
      sceneGroup.setCapability(BranchGroup.ALLOW_PICKABLE_WRITE);
      
      sceneGroup.setCapability(BranchGroup.ENABLE_PICK_REPORTING);
      sceneGroup.setPickable(true);

      Hashtable namedObjects = scene.getNamedObjects();
      System.out.println(" ");
      System.out.println("*** namedObjects: *** \n" + namedObjects);
      System.out.println(" ");

      // DCS - recursively set the user data here
      // so we can find our objects no matter what the picking
      // utils return as the path.
      
      System.out.println("*** set UserData to every object ***");
                java.util.Enumeration enumValues = namedObjects.elements();
      java.util.Enumeration enumKeys = namedObjects.keys();
                if( enumValues != null )
                {
                        while( enumValues.hasMoreElements() != false )
                        {
                                Object value = enumValues.nextElement();
                                Object key = enumKeys.nextElement();
                        	
                                recursiveSetUserData( value, key );
                        }
                }

      // DCS
      m_Java3dTree.recursiveApplyCapability( sceneGroup );
        	
      // add the scene group  to the scene
            examineGroup.addChild(sceneGroup);
                  	
            // now that the scene group is "live" we can inquire the bounds
            sceneBounds = (BoundingSphere)sceneGroup.getBounds();

            // set up a viewpoint to include the bounds
            setViewpoint();
        }

        canvas.setCursor(handCursor);
    }

        public void mouseEntered(MouseEvent e) {}
        public void mouseExited(MouseEvent e) {}
	
        // DCS - new method to recursively set the user 
        // data for objects in the scenegraph tree
        void recursiveSetUserData( Object value, Object key )
        {
                if( value instanceof SceneGraphObject != false )
                {
                        // set the user data for the item
                        SceneGraphObject sg = (SceneGraphObject) value;
                        sg.setUserData( key );
                                        	
                        // recursively process group
                        if( sg instanceof Group )
                        {
                                Group g = (Group) sg;
                        	
                                // all sub groups must have the ENABLE_PICK_REPORTING 
                                // to be reported in the sceneGraphPath
                                g.setCapability( Node.ENABLE_PICK_REPORTING );
                        	
                                // recurse on child nodes
                                java.util.Enumeration enumKids = g.getAllChildren();
                        	
                                while( enumKids.hasMoreElements() != false )
                                        recursiveSetUserData( enumKids.nextElement(), key );
                        }
                }
        }


  
        // DCS - rewritten to check for user data
	
        public void mouseClicked(MouseEvent e) 
        {
    System.out.println("*** MouseClick ***");
    System.out.println(" ");

    int xTest =  e.getPoint().x;
    int yTest =  e.getPoint().y;
    PickObject pickObject = new PickObject(canvas, sceneGroup);

    sceneGraphPath = pickObject.pickClosest(xTest, yTest);
        
    if( sceneGraphPath != null )
    {
            System.out.println("*** Looking for Picked Object ***");
            
            for (int q = 0; q < sceneGraphPath.nodeCount(); q++)
            {
              Node ActualNode = sceneGraphPath.getNode( q );
              
              if( ActualNode.getUserData() != null )
              {
                System.out.println("Found Object: " + ActualNode.getUserData() );
              	
                // because some of the shapes have multiple parts
                // we can select several sub parts, so escape here
                break;
              }
            }
    }
  }

  public void mousePressed(MouseEvent e) {}
  public void mouseReleased(MouseEvent e) {}

    void setViewpoint() {
        Transform3D viewTrans = new Transform3D();
        Transform3D eyeTrans = new Transform3D();

        // point the view at the center of the object
        Point3d center = new Point3d();
        sceneBounds.getCenter(center);
        double radius = sceneBounds.getRadius();
        Vector3d temp = new Vector3d(center);
        viewTrans.set(temp);

        // pull the eye back far enough to see the whole object
        double eyeDist = 1.4*radius / Math.tan(view.getFieldOfView() / 2.0);
        temp.x = 0.0;
        temp.y = 0.0;
        temp.z = eyeDist;
        eyeTrans.set(temp);
        viewTrans.mul(eyeTrans);

        // set the view transform
        vpTransGroup.setTransform(viewTrans);
    }


    private void setupBehavior() {
        sceneRoot = new BranchGroup();

        examineGroup = new TransformGroup();
        examineGroup.setCapability(TransformGroup.ALLOW_CHILDREN_EXTEND);
        examineGroup.setCapability(TransformGroup.ALLOW_CHILDREN_READ);
        examineGroup.setCapability(TransformGroup.ALLOW_CHILDREN_WRITE);
        examineGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
        examineGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        sceneRoot.addChild(examineGroup);

        BoundingSphere behaviorBounds = new BoundingSphere(new Point3d(),
                Double.MAX_VALUE);

        MouseRotate mr = new MouseRotate();
        mr.setTransformGroup(examineGroup);
        mr.setSchedulingBounds(behaviorBounds);
        sceneRoot.addChild(mr);

        MouseTranslate mt = new MouseTranslate();
        mt.setTransformGroup(examineGroup);
        mt.setSchedulingBounds(behaviorBounds);
        sceneRoot.addChild(mt);

        MouseZoom mz = new MouseZoom();
        mz.setTransformGroup(examineGroup);
        mz.setSchedulingBounds(behaviorBounds);
        sceneRoot.addChild(mz);

        BoundingSphere lightBounds =
        new BoundingSphere(new Point3d(), Double.MAX_VALUE);
        ambLight = new AmbientLight(true, new Color3f(1.0f, 1.0f, 1.0f));
        ambLight.setInfluencingBounds(lightBounds);
        ambLight.setCapability(Light.ALLOW_STATE_WRITE);
        sceneRoot.addChild(ambLight);
        headLight = new DirectionalLight();
        headLight.setCapability(Light.ALLOW_STATE_WRITE);
        headLight.setInfluencingBounds(lightBounds);
        sceneRoot.addChild(headLight);
        
        m_Java3dTree.recursiveApplyCapability( sceneRoot );

        universe.addBranchGraph(sceneRoot);
    }



    public static void main(String[] args) {
        String locString = null;
        if (args.length == 0) {
            locString = System.getProperties().getProperty("user.dir") +
//JN            "/parts/simple.wrl";
      "/VRML/BoxConeSphere1.wrl";
        } else {
            if (args.length != 1) {
                System.out.println("Usage: SimpleVrml97Viewer [pathname|URL]");
                System.exit(0);
            } else {
                locString = args[0];
            }
        }

        new MainFrame(new SimpleVrml97Viewer(locString), 650, 500);
    }

}