//=====================================================================//
// Display for the compression program
//=====================================================================//

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;  //structure for wireframe
    Color3f[] _colors;
    Compression c;
    static final int DRAWMESH=0;
    static final int DRAWDELTA=1;
    static final int NOTHING=2;
    final Color3f grey = new Color3f( 0.75f, 0.75f, 0.75f );

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

    public Display( Compression comp )
    {
	c = comp;
    }

    //======================================================================
    //                            Draw mesh 
    //======================================================================
    public void drawmesh()
    {
	//Java3D 1.2 needed!!!
	GraphicsConfiguration config = 
	    SimpleUniverse.getPreferredConfiguration();

	Frame f = new Frame("Edgebreaker CLERS");

        Canvas3D canvas3d = new Canvas3D(config);
	canvas3d.setSize(400, 400);
	initFrame(canvas3d, DRAWMESH);
	f.add(canvas3d);
	//c.drawMesh();
	f.pack();
	f.show();
	f.toFront();     

    }//draw mesh
	
    //===============================================================    

    /**
    *	visualize
    */    
    public void initFrame(Canvas3D canvas, int task) 
    {
	// 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 );

	switch (task) {
	  case DRAWMESH: {
	      drawMesh(objRotate);
	      break;
	  }
  	  case DRAWDELTA: {
	      drawDelta(objRotate);
	  }
	}// switch

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

    public void drawMesh(Group g) 
    {
	// draw all triangles in gray
	TriangleArray ta =  new TriangleArray( c._vindex.length, 
		            TriangleArray.COORDINATES | TriangleArray.COLOR_3);

	Point3d[] coord = new Point3d[c._vindex.length];
	_colors = new Color3f[c._vindex.length];

	for (int i=0; i<c._vindex.length; i++) {
	    if (c.v(i) == -1) {
		System.err.println("invalid index at v[" + i + "] !");
		coord[i]=c.g(0);
	    }
	    else {
		coord[i]=c.g( c.v(i) );
		//System.out.println("coord["+i+"] "+coord[i]);
	    }

	    _colors[i] = grey;
	    //_colors[i]= new Color3f(0.75f, 0.75f, 0.75f);
	    //System.out.println("Coord: "+coord[i]);
	}// for

	ta.setCoordinates(0, coord);
	ta.setColors(0,_colors);
	ta.setCapability(GeometryArray.ALLOW_COLOR_READ);
	ta.setCapability(GeometryArray.ALLOW_COLOR_WRITE);
	ta.setCapability(GeometryArray.ALLOW_COORDINATE_WRITE);

	c._mesh = new Shape3D(ta);
	c._mesh.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
    	
	LineArray la = new LineArray( 2 * c._vindex.length,
		       	      LineArray.COORDINATES | LineArray.COLOR_3 );
	Point3d[] lacoord = new Point3d[ 2 * c._vindex.length ];
	Color3f[] lac = new Color3f[ 2 * c._vindex.length ];

	int j=0; 
	Point3d coord1, coord2, coord3;
        for (int i=0; i < c._vindex.length; i+=3) {
	    coord1 = c.g( c.v(i));
	    coord2 = c.g( c.v(i+1));
	    coord3 = c.g( c.v(i+2));
	    lacoord[j++]=new Point3d( coord1 );
	    lacoord[j++]=new Point3d( coord2 );
	    lacoord[j++]=new Point3d( coord2 );
	    lacoord[j++]=new Point3d( coord3 );
	    lacoord[j++]=new Point3d( coord3 );
	    lacoord[j++]=new Point3d( coord1 );
	}// for

	for (int i=0; i<lac.length; i++) {        //color the lines
	    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( c._mesh);
	g.addChild( _lines );
    }// drawMesh

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

    /**
     * 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 = c.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<c._m.length; i++ ){
	    if( c._m[i] == 1 ){                     //point is fixed
		t = new Transform3D();
		Point3d pos = c.g( i );
		t.set( new Vector3f( pos ) );
		sphereGroup[j] = new TransformGroup( t );
		sphereGroup[j].addChild(new Sphere(0.005f, sphereAppearance));
		g.addChild(sphereGroup[j++]);
	    }// if fixed point
	}//for

    }//drawStationaryPoints

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

    public void drawDelta(Group g) 
    {
	PointArray pa = new PointArray( c._delta.size(), 
				  PointArray.COORDINATES | PointArray.COLOR_3);
	Point3d[] coord=new Point3d[ c._delta.size()];
	Color3f[] color=new Color3f[ c._delta.size()];

	// distribution of coordinates
	for (int i=0; i<coord.length; i++) {
	    coord[i]=new Point3d((Point3d)c._delta.elementAt(i));
	}

	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

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

    protected void updateMesh()
    {
	Point3d[] lacoord = new Point3d[ 2 * c._vindex.length ];

	int j=0; 
	Point3d coord1, coord2, coord3;
        for (int i=0; i < c._vindex.length; i+=3) {
	    coord1 = c.g( c.v(i) );
	    coord2 = c.g( c.v(i+1) );
	    coord3 = c.g( c.v(i+2) );
	    lacoord[j++]=new Point3d( coord1 );
	    lacoord[j++]=new Point3d( coord2 );
	    lacoord[j++]=new Point3d( coord2 );
	    lacoord[j++]=new Point3d( coord3 );
	    lacoord[j++]=new Point3d( coord3 );
	    lacoord[j++]=new Point3d( coord1 );
	}// for


        Point3d[] coord = new Point3d[ c._vindex.length ];
	
        for (int i=0; i<c._vindex.length; i++) {
	    if (c.v(i) == -1) {
		System.err.println("invalid index at v["+i+"] !");
		coord[i]=c.g(0);
	    }
	    else {
		coord[i]=c.g( c.v(i));
	    }

	}// for

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

}//end of class display
