/*
 *
 * Plots a 3D pyramid based on statistics provided 
 */

package plots;

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.GraphicsConfiguration;
import com.sun.j3d.utils.applet.MainFrame; 
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;

import java.awt.event.*;
import java.awt.AWTEvent;
import java.util.Enumeration;
import com.sun.j3d.utils.behaviors.keyboard.*;

//   KeyNavigatorApp renders a simple landscape
import com.sun.j3d.utils.behaviors.mouse.MouseBehavior;
import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
import com.sun.j3d.utils.behaviors.mouse.MouseTranslate;
import com.sun.j3d.utils.behaviors.mouse.MouseZoom;
import java.awt.Color;
import java.util.ArrayList;

public class PlotPyramid extends Applet {
    
    private float[] _medianVals;
    
      private ArrayList<ArrayList<Float>> _axes = new ArrayList<ArrayList<Float>>();
      /*
       * The above is created in the Parse class, and is used as follows:
       * 
       * Index 1 - close axis X
       * Index 2 - other axis X
       * Index 3 - query axis X
       * Index 4 - close axis Y
       * Index 5 - other axis Y
       * Index 6 - query axis Y
       * Index 7 - close axis Z
       * Index 8 - other axis Z
       * Index 9 - query axis Z
       * 
       **/
       
      private float resizeVal, resizeFactor;
      private final float maxCubeSize = 100; //about half of the grid? 
       
      
      
      public void calcResizeFactor(float resizeVal)
      {
          //resizeFactor = maxCubeSize/resizeVal;
          System.out.println("Resize Factor is: "+resizeFactor);
      }
        

    Shape3D createPyramid(Color3f color){
        IndexedTriangleArray pyGeom =
                new IndexedTriangleArray(5,  GeometryArray.COORDINATES 
                                           | GeometryArray.COLOR_3
                                          , 12);  //draws array of vertices as individual triangles
                                                  //3 vertices represents a triangle, 5 a pyramid

        
        pyGeom.setCoordinate(0, new Point3f(  0.0f, 0.7f,  0.0f ));
        pyGeom.setCoordinate(1, new Point3f( -0.4f, 0.0f, -0.4f ));
        pyGeom.setCoordinate(2, new Point3f( -0.4f, 0.0f,  0.4f ));
        pyGeom.setCoordinate(3, new Point3f(  0.4f, 0.0f,  0.4f ));
        pyGeom.setCoordinate(4, new Point3f(  0.4f, 0.0f, -0.4f ));

        pyGeom.setCoordinateIndex( 0, 0);
        pyGeom.setCoordinateIndex( 1, 1);
        pyGeom.setCoordinateIndex( 2, 2);
        pyGeom.setCoordinateIndex( 3, 0);
        pyGeom.setCoordinateIndex( 4, 2);
        pyGeom.setCoordinateIndex( 5, 3);
        pyGeom.setCoordinateIndex( 6, 0);
        pyGeom.setCoordinateIndex( 7, 3);
        pyGeom.setCoordinateIndex( 8, 4);
        pyGeom.setCoordinateIndex( 9, 0);
        pyGeom.setCoordinateIndex(10, 4);
        pyGeom.setCoordinateIndex(11, 1);

        /*
        Color3f c = new Color3f(1.0f, 1.0f, 0.0f);
         */
        pyGeom.setColor(0, color);
        pyGeom.setColor(1, color);
        pyGeom.setColor(2, color);
        pyGeom.setColor(3, color);
        pyGeom.setColor(4, color);

        Shape3D pyramid = new Shape3D(pyGeom);
        return pyramid;
    }
    

    Shape3D createLand(){
        LineArray landGeom = new LineArray(1000, GeometryArray.COORDINATES
                                            | GeometryArray.COLOR_3);  //sets up grid
        float l = -1000.0f;
        for(int c = 0; c < 1000; c+=4){  //draws each grid square, one inside of the other

            landGeom.setCoordinate( c+0, new Point3f( -1000.0f, 0.0f,  l ));
            landGeom.setCoordinate( c+1, new Point3f(  1000.0f, 0.0f,  l ));
            landGeom.setCoordinate( c+2, new Point3f(   l   , 0.0f, -1000.0f ));
            landGeom.setCoordinate( c+3, new Point3f(   l   , 0.0f,  1000.0f ));
            l += 82.99f;
        }
     

        Color3f c = new Color3f(0.1f, 0.8f, 0.1f);
        for(int i = 0; i < 100; i++) landGeom.setColor( i, c);

        return new Shape3D(landGeom);
    }
 
     
    public BranchGroup plotAndGetObjRoot(SimpleUniverse su, Color3f col, int xIndex, int yIndex, int zIndex)
    {
        
        TransformGroup vpTrans = null;

        BranchGroup objRoot = new BranchGroup();

        Vector3f translate = new Vector3f();
        Transform3D T3D = new Transform3D();
        TransformGroup TG = null;

        objRoot.addChild(createLand());

        SharedGroup share = new SharedGroup();
        
        //creates pyramid which can be used later in color assignment
        Shape3D pyra = createPyramid(col);  //yellow
        share.addChild(pyra);
        
        //using ArrayLists here
        
        for(int i = 0; i < _axes.get(xIndex).size(); i++)  //use number of Xs, since it will be the same for all
        {
           System.out.println("PLOTTING: " + _axes.get(xIndex).get(i) + " , " + _axes.get(yIndex).get(i) + " , " + _axes.get(zIndex).get(i));
            translate.setX(_axes.get(xIndex).get(i)); //this is the same 3D object
            translate.setY(_axes.get(yIndex).get(i));
            translate.setZ(_axes.get(zIndex).get(i));
            
            T3D.setTranslation(translate);
            TG = new TransformGroup(T3D);
            TG.addChild(new Link(share));
            objRoot.addChild(TG);
        }

        
        vpTrans = su.getViewingPlatform().getViewPlatformTransform();
        translate.set( _medianVals[0], _medianVals[1], _medianVals[2]); //sets camera starting position
        T3D.setTranslation(translate);
        vpTrans.setTransform(T3D);
        KeyNavigatorBehavior keyNavBeh = new KeyNavigatorBehavior(vpTrans);
        keyNavBeh.setSchedulingBounds(new BoundingSphere(new Point3d(),1000.0));
        objRoot.addChild(keyNavBeh);
      
	BoundingSphere mouseBounds = new BoundingSphere(new Point3d(), 1000.0);
       
        MouseRotate myMouseRotate = new MouseRotate(MouseBehavior.INVERT_INPUT);
        myMouseRotate.setTransformGroup(vpTrans);
        myMouseRotate.setSchedulingBounds(mouseBounds);
        objRoot.addChild(myMouseRotate);

        MouseTranslate myMouseTranslate = new MouseTranslate(MouseBehavior.INVERT_INPUT);
        myMouseTranslate.setTransformGroup(vpTrans);
        myMouseTranslate.setSchedulingBounds(mouseBounds);
        objRoot.addChild(myMouseTranslate);

        MouseZoom myMouseZoom = new MouseZoom(MouseBehavior.INVERT_INPUT);
        myMouseZoom.setTransformGroup(vpTrans);
        myMouseZoom.setSchedulingBounds(mouseBounds);
        objRoot.addChild(myMouseZoom);
      
        objRoot.compile();

        return objRoot;
    
    }
    
    public PlotPyramid(ArrayList<ArrayList<Float>> axes, float absMax, float[] medianVals) {
       
        this._axes = axes;
        this.resizeVal = absMax; 
        this._medianVals = medianVals;
        calcResizeFactor(this.resizeVal); //this gets the resize factor needed for resizing the 3d cube space  

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

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

        // SimpleUniverse is a Convenience Utility class
        SimpleUniverse simpleU = new SimpleUniverse(canvas3D);

       //set the colors for each pyramid here
        
        BranchGroup close_scene = plotAndGetObjRoot(simpleU, new Color3f(Color.GREEN), 0, 3, 6);
        BranchGroup other_scene = plotAndGetObjRoot(simpleU, new Color3f(Color.GRAY), 1, 4, 7);
        BranchGroup query_scene = plotAndGetObjRoot(simpleU, new Color3f(Color.RED), 2, 5, 8);
        
        simpleU.addBranchGraph(close_scene);
        simpleU.addBranchGraph(other_scene);
        simpleU.addBranchGraph(query_scene);
        
         simpleU.getCanvas().getScreen3D().setPhysicalScreenWidth(0.01); //make screen size for small objects
         simpleU.getCanvas().getScreen3D().setPhysicalScreenHeight(0.005);

    } 
} 