
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.media.j3d.*;
import javax.vecmath.Point3d;
import com.sun.j3d.utils.behaviors.keyboard.KeyNavigatorBehavior;
import com.sun.j3d.utils.behaviors.mouse.*;
import javax.vecmath.Vector3d;
import java.util.*;
import javax.vecmath.Matrix4d;
//import com.solibri.sae.geometry.TransformationMatrix;
//import com.solibri.sae.geometry.Rotation;
//import com.solibri.sae.geometry.RotationMatrix;
import java.math.BigDecimal;
import com.sun.j3d.utils.behaviors.picking.PickObject;
import com.solibri.sae.geometry.GEntity;
//import com.solibri.sae.ui.Ui;
import javax.vecmath.AxisAngle4d;
import com.sun.j3d.utils.universe.SimpleUniverse;
import com.sun.j3d.utils.geometry.ColorCube;

public class CanvasFrameDebug extends JFrame {
  BorderLayout borderLayout1 = new BorderLayout();
        Canvas3D canvas3D1 = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
        JScrollPane jScrollPane1 = new JScrollPane();
        JToolBar jToolBar1 = new JToolBar();
        JButton zoomPlusButton = new JButton();
        JButton zoomMinusButton = new JButton();
        BranchGroup sceneGraph = null;
        /** Bounds of the scene graph*/
        Bounds maxBounds;
        private View view = null;
  private TransformGroup viewTransformGroup = new TransformGroup();
        Transform3D viewTransform;
        public final int XPLUS = 0;
        public final int YPLUS = 1;
        public final int ZPLUS = 2;
        public final int XMINUS = 3;
        public final int YMINUS = 4;
        public final int ZMINUS = 5;
  private int direction = ZPLUS;
        JComboBox directionComboBox = new JComboBox();
        JTextField statusField = new JTextField();
        PickObject pickObject = null;
//  Desktop desktop = null;
        /** Vector containing all behaviors */
  private Vector navigationBehaviors = new Vector();

/*  public CanvasFrameDebug(Desktop desktop) {
                this();
                this.desktop = desktop;
  }
*/
  public CanvasFrameDebug() {
    try {
      jbInit();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }

  public void jbInit() throws Exception {
//    this.setClosable(true);
//    this.setIconifiable(true);
//    this.setMaximizable(true);
    this.setResizable(true);
    this.getContentPane().setLayout(borderLayout1);
                zoomPlusButton.setPreferredSize(new Dimension(41, 20));
                zoomPlusButton.setToolTipText("Increase Zoom");
                zoomPlusButton.setText("Z");
                zoomPlusButton.addActionListener(new java.awt.event.ActionListener()
                {

                        public void actionPerformed(ActionEvent e)
                        {
                                zoomPlusButton_actionPerformed(e);
                        }
                });
                zoomMinusButton.setPreferredSize(new Dimension(39, 20));
                zoomMinusButton.setToolTipText("Decrease Zoom");
                zoomMinusButton.setText("z");
                zoomMinusButton.addActionListener(new java.awt.event.ActionListener()
                {

                        public void actionPerformed(ActionEvent e)
                        {
                                zoomMinusButton_actionPerformed(e);
                        }
                });
                directionComboBox.setMinimumSize(new Dimension(124, 20));
                directionComboBox.setPreferredSize(new Dimension(128, 20));
                directionComboBox.setToolTipText("Select the direction");
/*              directionComboBox.addItemListener(new java.awt.event.ItemListener()
                {

                        public void itemStateChanged(ItemEvent e)
                        {
                                directionComboBox_itemStateChanged(e);
                        }
                });
*/
                statusField.setBackground(Color.lightGray);
                statusField.setBorder(null);
                statusField.setEditable(false);
                canvas3D1.addMouseMotionListener(new java.awt.event.MouseMotionAdapter()
                {

                        public void mouseMoved(MouseEvent e)
                        {
                                canvas3D1_mouseMoved(e);
                        }
                });
/*              canvas3D1.addMouseListener(new java.awt.event.MouseAdapter()
                {

                        public void mousePressed(MouseEvent e)
                        {
                                canvas3D1_mousePressed(e);
                        }
                });
*/
                zoomAllButton.setText("ZA");
                zoomAllButton.addActionListener(new java.awt.event.ActionListener()
                {

                        public void actionPerformed(ActionEvent e)
                        {
                                zoomAllButton_actionPerformed(e);
                        }
                });
                this.getContentPane().add(jScrollPane1, BorderLayout.CENTER);
                this.getContentPane().add(jToolBar1, BorderLayout.SOUTH);
                jToolBar1.add(zoomAllButton, null);
                jToolBar1.add(zoomPlusButton, null);
                jToolBar1.add(zoomMinusButton, null);
                jToolBar1.add(directionComboBox, null);
                jToolBar1.add(statusField, null);
                jScrollPane1.getViewport().add(canvas3D1, null);
    initDirectionBox();
  }

  private void initDirectionBox()
  {
    directionComboBox.addItem("Right (X Positive)");
    directionComboBox.addItem("Front (Y Positive)");
    directionComboBox.addItem("Top (Z Positive)");
    directionComboBox.addItem("Left (X Negative)");
    directionComboBox.addItem("Back (Y Negative)");
    directionComboBox.addItem("Bottom (Z Negative)");
  }

  /** Creates a view transform depending on bounds and direction */
/*      protected TransformationMatrix getTransform(Bounds bounds, int direction)
  {
    this.direction = direction;
                TransformationMatrix transform = new TransformationMatrix();
    BoundingBox box = new BoundingBox(bounds);
    Point3d upper = new Point3d();
    box.getUpper(upper);
    Point3d lower = new Point3d();
    box.getLower(lower);
    Vector3d vector =
        new Vector3d(
        lower.x + (upper.x-lower.x)/2,
        lower.y + (upper.y - lower.y)/2,
        lower.z + (upper.z - lower.z)/2);
    Rotation[] rotations = new Rotation[2];
    rotations[0] = new Rotation(Rotation.X, 0);
    rotations[1] = rotations[0];
    switch (direction)
    {
        case XPLUS:
      {
        vector.x = lower.x + (upper.x - lower.x)*2;
        rotations[0] = new Rotation(Rotation.Y, 90, true);
        rotations[1] = new Rotation(Rotation.Z, 90, true);
        break;
      }
        case YPLUS:
      {
        vector.y = lower.y + (upper.y - lower.y)*2;
        rotations[0] = new Rotation(Rotation.X, -90, true);
        rotations[1] = new Rotation(Rotation.Z, 180, true);
        break;
      }
        case ZPLUS:
      {
        vector.z = lower.z + (upper.z - lower.z)*2;
                                // Rotation is default
        break;
      }
        case XMINUS:
      {
        vector.x = upper.x - (upper.x - lower.x)*2;
        rotations[0] = new Rotation(Rotation.Y, -90, true);
        rotations[1] = new Rotation(Rotation.Z, -90, true);
        break;
      }
        case YMINUS:
      {
        vector.y = upper.y - (upper.y - lower.y)*2;
        rotations[0] = new Rotation(Rotation.X, 90, true);
//        rotations[1] = new Rotation(Rotation.Z, 180, true);
        break;
      }
        case ZMINUS:
      {
        vector.z = upper.z - (upper.z - lower.z)*2;
        rotations[0] = new Rotation(Rotation.Y, 180, true);
        rotations[1] = new Rotation(Rotation.Z, 180, true);
        break;
      }
    }
                RotationMatrix rMatrix = new RotationMatrix(rotations);
    transform.setRotation(rotations);
    transform.setLocation(vector.x, vector.y, vector.z);
    setTitle((String)directionComboBox.getItemAt(direction));
    return transform;
  }
*/

        /** This method updates the maxBounds and the scheduling leaves of the behaviors. */
  private void resetView()
  {
//    if (!sceneGraph.isCompiled()) sceneGraph.compile();
//              Desktop.printGraphElements(sceneGraph, 0);
    Enumeration childEnum = sceneGraph.getAllChildren();
    while (childEnum.hasMoreElements())
    {
        Node node = (Node)childEnum.nextElement();
      if (node instanceof TransformGroup)
      {
              Bounds bounds = node.getBounds();
            maxBounds.combine(bounds);
      }
    }
//    maxBounds = sceneGraph.getBounds();
    BoundingBox box = new BoundingBox(maxBounds);
    Point3d upper = new Point3d();
    box.getUpper(upper);
    Point3d lower = new Point3d();
    box.getLower(lower);

    BoundingSphere viewBounds = new BoundingSphere(box);
    viewTransformGroup.setBounds(viewBounds);

    // Get the view and set the corresponding selection in directions
//    viewTransform.set(getTransform(maxBounds, direction));
//    viewTransformGroup.setTransform(viewTransform);
    directionComboBox.setSelectedIndex(direction);

    Transform3D boxScale = new Transform3D();
    boxScale.setScale(50);
//    viewTransform.ortho(lower.x, upper.x, lower.z, upper.z, lower.y, upper.y);

                double scale = upper.distance(lower);
                view.setBackClipDistance(0.7*scale);
    view.setFrontClipDistance(view.getBackClipDistance()/100);

                Point3d center = new Point3d();
    viewBounds.getCenter(center);
                BoundingSphere schedulingBounds = new BoundingSphere(center, scale*10);

        Enumeration enum = navigationBehaviors.elements();
    while (enum.hasMoreElements())
    {
      Behavior behavior = (Behavior)enum.nextElement();
      BoundingLeaf boundingLeaf =
        new BoundingLeaf(schedulingBounds);
      behavior.setSchedulingBoundingLeaf(null);
      behavior.setSchedulingBoundingLeaf(boundingLeaf);
//      behavior.setBounds(schedulingBounds);
      behavior.setEnable(true);
    }
  }

  public BranchGroup createViewGraph(BranchGroup sceneGraph, Bounds maxBounds, int direction)
  {
                this.sceneGraph = sceneGraph;
                this.maxBounds = maxBounds;
    view = new View();
    ViewPlatform viewPlatform = new ViewPlatform();
    viewPlatform.setBounds(maxBounds);
    viewPlatform.setCapability(Node.ALLOW_BOUNDS_WRITE);
    viewPlatform.setCapability(viewPlatform.ALLOW_AUTO_COMPUTE_BOUNDS_READ);
    PhysicalBody physicalBody = new PhysicalBody();
    PhysicalEnvironment physicalEnvironment = new PhysicalEnvironment();
    view.attachViewPlatform(viewPlatform);
    view.setPhysicalBody(physicalBody);
    view.setPhysicalEnvironment(physicalEnvironment);
    view.addCanvas3D(canvas3D1);

          // Create the root of the branch graph
        BranchGroup vpRoot = new BranchGroup();

    viewTransform = new Transform3D();

    viewTransformGroup = new TransformGroup(viewTransform);
    viewTransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    viewTransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
    viewTransformGroup.setCapability(TransformGroup.ALLOW_BOUNDS_WRITE);
    viewTransformGroup.addChild(viewPlatform);
    vpRoot.addChild(viewTransformGroup);
//    BoundingSphere viewBounds = new BoundingSphere(box);
//    viewTransformGroup.setBounds(viewBounds);
//              Point3d center = new Point3d();
//    viewBounds.getCenter(center);

//    keyNavigator = new KeyNavigator(viewTransformGroup);

//              BoundingSphere schedulingBounds = new BoundingSphere(center, scale*10);

    KeyNavigatorBehavior keyNavBeh = new KeyBehavior(viewTransformGroup);
//    keyNavBeh.setSchedulingBounds(new BoundingSphere(schedulingBounds));
    keyNavBeh.setCapability(keyNavBeh.ALLOW_BOUNDS_WRITE);
    vpRoot.addChild(keyNavBeh);
    navigationBehaviors.add(keyNavBeh);

    MouseRotate myMouseRotate = new MRotate();
    myMouseRotate.setTransformGroup(viewTransformGroup);
//    myMouseRotate.setSchedulingBounds(new BoundingSphere(schedulingBounds));
    myMouseRotate.setCapability(myMouseRotate.ALLOW_BOUNDS_WRITE);
//    myMouseRotate.setFactor(scale*0.01);
    vpRoot.addChild(myMouseRotate);
    navigationBehaviors.add(myMouseRotate);

    MouseTranslate myMouseTranslate = new MTranslate();
    myMouseTranslate.setTransformGroup(viewTransformGroup);
//    myMouseTranslate.setSchedulingBounds(new BoundingSphere(schedulingBounds));
    myMouseTranslate.setCapability(myMouseTranslate.ALLOW_BOUNDS_WRITE);
//    myMouseTranslate.setFactor(scale*0.01);
    vpRoot.addChild(myMouseTranslate);
    navigationBehaviors.add(myMouseTranslate);

    MouseZoom myMouseZoom = new MZoom();
    myMouseZoom.setTransformGroup(viewTransformGroup);
    myMouseZoom.setCapability(myMouseZoom.ALLOW_BOUNDS_WRITE);
//    myMouseZoom.setSchedulingBounds(new BoundingSphere(schedulingBounds));
//    myMouseZoom.setFactor(scale*0.01);
//    myMouseZoom.setFactor(10);
    vpRoot.addChild(myMouseZoom);
    navigationBehaviors.add(myMouseZoom);

    // Picking behavior:
    pickObject = new PickObject(canvas3D1, sceneGraph);

          // Let Java 3D perform optimizations on this scene graph.
    vpRoot.compile();
    resetView();
        return vpRoot;
  }


  private class MZoom extends MouseZoom
  {
                /** Limit the events to only this canvas*/
    public void processMouseEvent(MouseEvent e)
    {
                        if (e.getSource().equals(canvas3D1))
      {
                super.processMouseEvent(e);
      }
    }
  }

  private class MTranslate extends MouseTranslate
  {
                /** Limit the events to only this canvas*/
    public void processMouseEvent(MouseEvent e)
    {
                        if (e.getSource().equals(canvas3D1))
      {
                super.processMouseEvent(e);
      }
    }
  }

  private class MRotate extends MouseRotate
  {
                private MRotate()
    {
        super(MouseRotate.INVERT_INPUT);
    }
    private int old_x;
    private int old_y;
                /** Limit the events to only this canvas*/
    public void processMouseEvent(MouseEvent e)
    {
                        if (
        e.getSource().equals(canvas3D1) &&
        ((e.getModifiers() & e.BUTTON1_MASK) != 0)
      )
      {
        if (e.getID() == e.MOUSE_PRESSED)
        {
          old_x = e.getX();
          old_y = e.getY();
          return;
        }
        else if (e.getID() == e.MOUSE_DRAGGED)
        {
          int x = e.getX() - old_x;
          int y = old_y - e.getY();
          Vector3d rotationAxis = new Vector3d(-y,x,0);
          double angle = rotationAxis.length()/1000 ;
          viewTransform.transform(rotationAxis);
          AxisAngle4d ax =
            new AxisAngle4d(rotationAxis.x, rotationAxis.y, rotationAxis.z, angle);
          Transform3D rotation = new Transform3D();
          rotation.set(ax);
          viewTransform.mul(rotation, viewTransform);
          viewTransformGroup.setTransform(viewTransform);
          old_x = e.getX();
          old_y = e.getY();
                                }
                        }
    }
  }

  private class KeyBehavior extends KeyNavigatorBehavior
  {
                KeyBehavior(TransformGroup viewTransformGroup)
    {
        super(viewTransformGroup);
    }
    public void initialize(){
        // set initial wakeup condition
        this.wakeupOn(new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED));
    }
    public void processStimulus(Enumeration criteria)
    {
                        // KeyNavigatorBehavior only works with WakeupOnElapsedFrames
      // event!
                        Vector events = new Vector(2);
                        while (criteria.hasMoreElements())
      {
              events.add(criteria.nextElement());
      }
      WakeupOnElapsedFrames frameEvent = new WakeupOnElapsedFrames(10);
      events.add(frameEvent);
      Enumeration newCriteria = events.elements();
        super.processStimulus(newCriteria);
      this.wakeupOn(new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED));
    }
  }

  private void setStatus(String status)
  {
    statusField.setText(status);
  }

/*      void directionComboBox_itemStateChanged(ItemEvent e)
        {
                if (e.getStateChange() == e.SELECTED && viewTransform != null)
    {
                TransformationMatrix transform = getTransform(maxBounds, directionComboBox.getSelectedIndex());
      viewTransformGroup.getTransform(viewTransform);
        viewTransform.set(transform);
      viewTransformGroup.setTransform(viewTransform);
//      canvas3D1.repaint();
    }
        }
*/
        private void zoom(double ratio)
  {
        viewTransformGroup.getTransform(viewTransform);
                Vector3d vector = new Vector3d();
    viewTransform.get(vector);
    vector.scale(ratio);
    viewTransform.setTranslation(vector);
    viewTransformGroup.setTransform(viewTransform);
  }

        private double zoomFactor = 0.9;
        JButton zoomAllButton = new JButton();
        void zoomPlusButton_actionPerformed(ActionEvent e)
        {
                zoom(zoomFactor);
        }

        void zoomMinusButton_actionPerformed(ActionEvent e)
        {
    zoom(1/zoomFactor);
        }


        void canvas3D1_mouseMoved(MouseEvent e)
        {
        int x = (int)e.getPoint().getX();
    int y = (int)e.getPoint().getY();
    Point3d point = new Point3d();
    canvas3D1.getPixelLocationInImagePlate(x,y,point);
/*    BigDecimal xb = new BigDecimal(point.x);
    xb.setScale(0, BigDecimal.ROUND_HALF_UP);
    BigDecimal yb = new BigDecimal(point.y);
    yb.setScale(0, BigDecimal.ROUND_HALF_UP);
    BigDecimal zb = new BigDecimal(point.z);
    zb.setScale(0, BigDecimal.ROUND_HALF_UP);
    setStatus(xb.toString() + "," + yb.toString() + "," + zb.toString());
*/
    setStatus(new String((int)point.x + "," + (int)point.y + "," + (int)point.z));
        }

        void zoomAllButton_actionPerformed(ActionEvent e)
        {
    resetView();
        }


  public static void main(String[] args)
  {
                // Create universe -> locale -> root -> transform
        VirtualUniverse universe = new VirtualUniverse();
        javax.media.j3d.Locale locale = new javax.media.j3d.Locale(universe);
                BranchGroup root = new BranchGroup();
    root.setCapability(root.ALLOW_CHILDREN_READ);
    root.setCapability(root.ALLOW_CHILDREN_EXTEND);
    root.setCapability(root.ALLOW_BOUNDS_READ);
    TransformGroup transform = new TransformGroup();
    transform.setCapability(transform.ALLOW_CHILDREN_READ);
    transform.setCapability(transform.ALLOW_BOUNDS_READ);
    transform.setCapability(transform.ALLOW_CHILDREN_EXTEND);
    root.addChild(transform);
    root.compile();

    // Create new CanvasFrameDebug
    CanvasFrameDebug canvas = new CanvasFrameDebug();
    canvas.setVisible(true);

    // Create view graph in canvas
    BoundingSphere maxBounds = new BoundingSphere(new Point3d(0,0,0), 0.5);
    BranchGroup view = canvas.createViewGraph(root, maxBounds, canvas.ZPLUS);
    locale.addBranchGraph(view);

    // Add geometry
    BranchGroup cubeGroup = new BranchGroup();
    cubeGroup.setCapability(cubeGroup.ALLOW_CHILDREN_READ);
    cubeGroup.setCapability(cubeGroup.ALLOW_BOUNDS_READ);
    cubeGroup.addChild(new ColorCube());
    transform.addChild(cubeGroup);

    // This creates the error
    canvas.resetView();
  }

}
