//=====================================================================//
// Program by Anna Shleyfman
// CS 8803e -- Geomorph
// Project 1
//=====================================================================//

import java.io.*;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.behaviors.mouse.*;
import com.sun.j3d.utils.geometry.Sphere;
import javax.vecmath.*;
import javax.media.j3d.*;
import java.awt.*;

//======================================================================
//                            Class Display
//======================================================================

public class Display
{

    //======================================================================
    //                        Variable delcarations
    //======================================================================

    Shape3D _lines=null;

    private Geomorph geo;
    int num_vert;

    //======================================================================
    //                         Constructors
    //======================================================================

    public Display( Geomorph g )
    {
	geo = g;
	num_vert = geo.num_vert;
    }

    //======================================================================
    //                            Accessors
    //======================================================================

    /** 
    *    returns the vertex number of the passed corner
    **/
    private int g_ind( int corner )  //get vertex index
    {
        return geo.g_ind( corner );
    }    

    //======================================================================
    
    /**
    *   returns coordinates of vertex, given the vertex index
    *   negative vertices are used to create delaunay triangulation
    **/ 
    private Point3d g_vert( int vindex )  //get vertex
    {
	return geo.g_vert( vindex );
    }

    //======================================================================
    //                            Draw mesh 
    //======================================================================

    public void drawmesh()
    {
	GraphicsConfiguration config = 
	    SimpleUniverse.getPreferredConfiguration();

	//draws the mesh
	Frame f3 = new Frame("Created Delaunay model");

	//Java3D 1.2 needed!!!
	Canvas3D canvas3d = new Canvas3D( config );
	canvas3d.setSize( 400, 400 );
	initFrame( canvas3d );
	f3.add( canvas3d );
	f3.pack();
	f3.show();
	f3.toFront();

    }// drawmesh
	
    //======================================================================
    /**
    *	visualize
    */    
    public void initFrame(Canvas3D canvas ) 
    {
	// SimpleUniverse is a Convenience Utility class
        SimpleUniverse simpleU = new SimpleUniverse( canvas );
        simpleU.getViewer().getView().setFrontClipDistance( 0.0001 );
        simpleU.getViewer().getView().setBackClipDistance( 1000.0 );
        BranchGroup scene=new BranchGroup();
	
	// background
	Background b = new Background(1f, 1f, 1f);
	b.setApplicationBounds(new BoundingSphere(new Point3d(0,0,0), 1000 ));
    	
	Transform3D t=new Transform3D();
	t.setTranslation (new Vector3f(0f,0f,-5f));
	TransformGroup tg = new TransformGroup(t);
	TransformGroup objRotate = new TransformGroup();
	objRotate.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
	objRotate.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
	
	MouseRotate myMouseRotate = new MouseRotate();
	myMouseRotate.setTransformGroup(objRotate);
	myMouseRotate.setSchedulingBounds( new BoundingSphere( 
                                                new Point3d(0,0,0), 1000) );
	MouseZoom myMouseZoom = new MouseZoom();
	myMouseZoom.setTransformGroup(objRotate);
	myMouseZoom.setSchedulingBounds(new BoundingSphere( new Point3d(0,0,0),
							    1000));
	tg.addChild(objRotate);
	scene.addChild(tg);
	scene.addChild(myMouseRotate);
	scene.addChild(myMouseZoom);
	scene.addChild(b);

	//drawDelta(objRotate);
	drawMesh(objRotate);

	drawStationaryPoints( objRotate );
	simpleU.addBranchGraph(scene);
    }// initFrame

    //======================================================================

    /**
     *  Draws points on the screen
     */
    public void drawDelta(Group g) 
    {
	PointArray pa = new PointArray( num_vert+3, 
			     PointArray.COORDINATES | PointArray.COLOR_3);
	Color3f[] color=new Color3f[ num_vert+3 ];
	Point3d[] coord=new Point3d[ num_vert+3 ];

	// distribution of coordinates
	coord[0]=new Point3d( g_vert( -1 ) );
	coord[1]=new Point3d( g_vert( -2 ) );
	coord[2]=new Point3d( g_vert( -3 ) );

	for (int i=3; i<coord.length; i++) {
	    coord[i]=new Point3d( g_vert( i-3 ) );
	}

	for (int i=0; i<color.length; i++) {
	    color[i]=new Color3f(0f, 0f, 0f); // black
	}
	    
	pa.setCoordinates(0, coord );
	pa.setColors(0, color);
	    
	Shape3D s = new Shape3D(pa);
	g.addChild(s);    	

    }// drawDelta

    //======================================================================

    public void drawMesh( Group g )
    {
	int good_tri = 0;      // number of nondegenerate triangles in _vindex
	int lineArraySize = 0; // 2 * number of corners - 
	                       // each line requires 2 vertices

	//test for degenerate triangles
	for( int i=0; i<geo._vindex.length; i+=3){
	    if( geo._o[ i ] != -2 ){
		good_tri++;
	    }
	}//for

	System.out.println( "Number of nondegenerate triangles = " + 
			    good_tri );
	lineArraySize = 2 * 3 * good_tri;

	LineArray la = new LineArray( lineArraySize,
			    LineArray.COORDINATES | LineArray.COLOR_3);
	Color3f[] lac = new Color3f[ lineArraySize ];
	Point3d[] lacoord = new Point3d[ lineArraySize ];


	int j=0;
        for (int i=0; i < geo._vindex.length; i+=3) {
	    if( geo._o[ i ] != -2 ){
		lacoord[j++]=new Point3d( g_vert( g_ind(i) ));
		lacoord[j++]=new Point3d( g_vert( g_ind(i+1) ));
		lacoord[j++]=new Point3d( g_vert( g_ind(i+1) ));
		lacoord[j++]=new Point3d( g_vert( g_ind(i+2) ));
		lacoord[j++]=new Point3d( g_vert( g_ind(i+2) ));
		lacoord[j++]=new Point3d( g_vert( g_ind(i) ));
	    }//if
	}// for

	for (int i=0; i<lac.length; i++) {
	    lac[i] = new Color3f(0f, 0f, 0f); // black
	}// for
    	
	la.setCoordinates(0, lacoord);
	la.setColors(0, lac);
	la.setCapability(GeometryArray.ALLOW_COLOR_READ);
	la.setCapability(GeometryArray.ALLOW_COLOR_WRITE);
	la.setCapability(GeometryArray.ALLOW_COORDINATE_READ);
	la.setCapability(GeometryArray.ALLOW_COORDINATE_WRITE);

	_lines = new Shape3D(la);
	_lines.setCapability(Shape3D.ALLOW_GEOMETRY_READ);

	g.addChild(_lines);

    }// drawCollapsed

    //======================================================================
    
    protected void updateMesh()
    {
	//System.out.println( "_vindex.length = " + geo._vindex.length );
        Point3d[] lacoord = new Point3d[ 2 * geo._vindex.length ];

	int j=0;
        for (int i=0; i<geo._vindex.length; i+=3) {
	    lacoord[j++]=new Point3d( g_vert( g_ind(i) ));
	    lacoord[j++]=new Point3d( g_vert( g_ind(i+1) ));
	    lacoord[j++]=new Point3d( g_vert( g_ind(i+1) ));
	    lacoord[j++]=new Point3d( g_vert( g_ind(i+2) ));
	    lacoord[j++]=new Point3d( g_vert( g_ind(i+2) ));
	    lacoord[j++]=new Point3d( g_vert( g_ind(i) ));
	}// for

        //((GeometryArray)_mesh.getGeometry()).setCoordinates(0, coord);
        ((GeometryArray)_lines.getGeometry()).setCoordinates(0, lacoord );
        
    }// updateMesh

    //===============================================================    

    /**
     * Highlights fixed points, so we could easily identify them
     * My code
     */
    public void drawStationaryPoints( Group g )
    {
	// Create transform groups to position objects 
	// (default position is origin)
	Transform3D t;

	// Create spheres
	int numSpheres = geo.numFixed;
	TransformGroup sphereGroup[] = new TransformGroup[ numSpheres ];
	Color3f sphereColor = new Color3f( 0.1f, 0.9f, 0.0f );

	// Create define sphere appearence
	ColoringAttributes sphereColorAttr = new ColoringAttributes();
	sphereColorAttr.setColor( sphereColor );
	Appearance sphereAppearance = new Appearance();
	sphereAppearance.setColoringAttributes( sphereColorAttr );

	for( int i=0, j=0; i<geo._m.length; i++ ){
	    if( geo._m[i] == 1 ){                     //point is fixed
		t = new Transform3D();
		Point3d pos = geo.g_vert( i );
		t.set( new Vector3f( pos ) );
		sphereGroup[j] = new TransformGroup( t );
		sphereGroup[j].addChild(new Sphere(0.02f, sphereAppearance));
		g.addChild(sphereGroup[j++]);
	    }// if fixed point
	}//for

    }//drawStationaryPoints

    //===============================================================    

}// end of class Display

//===============================================================    
//              End of class Display
//===============================================================    
