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


public class Small extends Applet {

    PickBehavior picker;
    Canvas3D canvas3D;


    Point3f[][] createCoordinateData() {
        //float[] data = new float[69*3];         // ******
        Point3f[][] data = new Point3f[9][];
        
        data[0] = new Point3f[17];
        data[1] = new Point3f[17];
        data[2] = new Point3f[5];
        data[3] = new Point3f[5];
        data[4] = new Point3f[5];
        data[5] = new Point3f[5];
        data[6] = new Point3f[5];
        data[7] = new Point3f[5];
        data[8] = new Point3f[5];

        int i = 0;
        data[0][i++]= new Point3f(-1.3f,-0.3f,0.3f); //0
        data[0][i++]= new Point3f(-0.9f,-0.3f,0.3f); //1
        data[0][i++]= new Point3f(-0.8f,-0.1f,0.3f); //2
        data[0][i++]= new Point3f(-0.6f,-0.1f,0.3f); //3
        data[0][i++]= new Point3f(-0.5f,-0.3f,0.3f); //4
        data[0][i++]= new Point3f(0.2f,-0.3f,0.3f); //5
        data[0][i++]= new Point3f(0.3f,-0.1f,0.3f); //6
        data[0][i++]= new Point3f(0.5f,-0.1f,0.3f); //7
        data[0][i++]= new Point3f(0.6f,-0.3f,0.3f); //8
        data[0][i++]= new Point3f(1.3f,-0.3f,0.3f); //9
        data[0][i++]= new Point3f(1.2f,-0.1f,0.3f); //10
        data[0][i++]= new Point3f(0.5f,0.0f,0.3f); //11
        data[0][i++]= new Point3f(0.1f,0.3f,0.3f); //12
        data[0][i++]= new Point3f(-0.5f,0.3f,0.3f); //13
        data[0][i++]= new Point3f(-1.1f,0.0f,0.3f); //14
        data[0][i++]= new Point3f(-1.3f,0.0f,0.3f); //15
        data[0][i++]= new Point3f(-1.3f,-0.3f,0.3f); //16
        System.out.println("end polygon; total vertex count: "+i);

        i = 0;
        data[1][i++]= new Point3f(-1.3f,-0.3f,-0.3f); // 0 17
        data[1][i++]= new Point3f(-1.3f, 0.0f,-0.3f); // 1 18
        data[1][i++]= new Point3f(-1.1f, 0.0f,-0.3f); // 2 19
        data[1][i++]= new Point3f(-0.5f, 0.3f,-0.3f); // 3 20
        data[1][i++]= new Point3f( 0.1f, 0.3f,-0.3f); // 4 21
        data[1][i++]= new Point3f( 0.5f, 0.0f,-0.3f); // 5 22
        data[1][i++]= new Point3f( 1.2f,-0.1f,-0.3f); // 6 23
        data[1][i++]= new Point3f( 1.3f,-0.3f,-0.3f); // 7 24
        data[1][i++]= new Point3f( 0.6f,-0.3f,-0.3f); // 8 25
        data[1][i++]= new Point3f( 0.5f,-0.1f,-0.3f); // 9 26
        data[1][i++]= new Point3f( 0.3f,-0.1f,-0.3f); //10 27
        data[1][i++]= new Point3f( 0.2f,-0.3f,-0.3f); //11 28
        data[1][i++]= new Point3f(-0.5f,-0.3f,-0.3f); //12 29
        data[1][i++]= new Point3f(-0.6f,-0.1f,-0.3f); //13 30
        data[1][i++]= new Point3f(-0.8f,-0.1f,-0.3f); //14 31
        data[1][i++]= new Point3f(-0.9f,-0.3f,-0.3f); //15 32
        data[1][i++]= new Point3f(-1.3f,-0.3f,-0.3f); //16 33
        System.out.println("end polygon; total vertex count: "+i);
        
        i = 0;
        data[2][i++]= new Point3f( 1.3f,-0.3f,-0.3f); // 0 34
        data[2][i++]= new Point3f( 1.2f,-0.1f,-0.3f); // 1 35
        data[2][i++]= new Point3f( 1.2f,-0.1f,0.3f); // 2 36
        data[2][i++]= new Point3f( 1.3f,-0.3f,0.3f); // 3 37
        data[2][i++]= new Point3f( 1.3f,-0.3f,-0.3f); // 4 38
        System.out.println("end polygon; total vertex count: "+i);

        i = 0;
        data[3][i++]= new Point3f( 1.2f,-0.1f,-0.3f); // 0 39
        data[3][i++]= new Point3f( 0.5f, 0.0f,-0.3f); // 1 40
        data[3][i++]= new Point3f( 0.5f, 0.0f,0.3f); // 2 41
        data[3][i++]= new Point3f( 1.2f,-0.1f,0.3f); // 3 42
        data[3][i++]= new Point3f( 1.2f,-0.1f,-0.3f); // 4 43
        System.out.println("end polygon; total vertex count: "+i);

        i = 0;
        data[4][i++]= new Point3f( 0.5f, 0.0f,-0.3f); // 0 44
        data[4][i++]= new Point3f( 0.1f, 0.3f,-0.3f); // 1 45
        data[4][i++]= new Point3f( 0.1f, 0.3f,0.3f); // 2 46
        data[4][i++]= new Point3f( 0.5f, 0.0f,0.3f); // 3 47
        data[4][i++]= new Point3f( 0.5f, 0.0f,-0.3f); // 4 48
        System.out.println("end polygon; total vertex count: "+i);

        i = 0;
        data[5][i++]= new Point3f( 0.1f, 0.3f,-0.3f); // 0 49
        data[5][i++]= new Point3f(-0.5f, 0.3f,-0.3f); // 1 50
        data[5][i++]= new Point3f(-0.5f, 0.3f,0.3f); // 2 51
        data[5][i++]= new Point3f( 0.1f, 0.3f,0.3f); // 3 52
        data[5][i++]= new Point3f( 0.1f, 0.3f,-0.3f); // 4 53
        System.out.println("end polygon; total vertex count: "+i);

        i = 0;
        data[6][i++]= new Point3f(-0.5f, 0.3f,-0.3f); // 0 54
        data[6][i++]= new Point3f(-1.1f, 0.0f,-0.3f); // 1 55
        data[6][i++]= new Point3f(-1.1f, 0.0f,0.3f); // 2 56
        data[6][i++]= new Point3f(-0.5f, 0.3f,0.3f); // 3 57
        data[6][i++]= new Point3f(-0.5f, 0.3f,-0.3f); // 4 58
        System.out.println("end polygon; total vertex count: "+i);

        i = 0;
        data[7][i++]= new Point3f(-1.1f, 0.0f,-0.3f); // 0 59
        data[7][i++]= new Point3f(-1.3f, 0.0f,-0.3f); // 1 60
        data[7][i++]= new Point3f(-1.3f, 0.0f,0.3f); // 2 61
        data[7][i++]= new Point3f(-1.1f, 0.0f,0.3f); // 3 62
        data[7][i++]= new Point3f(-1.1f, 0.0f,-0.3f); // 4 63
        System.out.println("end polygon; total vertex count: "+i);
                                                                    
        i = 0;
        data[8][i++]= new Point3f(-1.3f, 0.0f,-0.3f); // 0 64
        data[8][i++]= new Point3f(-1.3f,-0.3f,-0.3f); // 1 65
        data[8][i++]= new Point3f(-1.3f,-0.3f,0.3f); // 2 66
        data[8][i++]= new Point3f(-1.3f, 0.0f,0.3f); // 3 67
        data[8][i++]= new Point3f(-1.3f, 0.0f,-0.3f); // 4 68
        System.out.println("end polygon; total vertex count: "+i);

        return data;
    }
            

    Appearance createMaterialAppearance(){

        Appearance materialAppear = new Appearance();
        PolygonAttributes polyAttrib = new PolygonAttributes();
        polyAttrib.setCullFace(PolygonAttributes.CULL_NONE);
        materialAppear.setPolygonAttributes(polyAttrib);

        //Material material = new Material();
        //material.setDiffuseColor(new Color3f(1.0f, 0.0f, 0.0f));
        //materialAppear.setMaterial(material);

        return materialAppear;
    }


    /////////////////////////////////////////////////
    //
    // create scene graph branch group
    //
    public BranchGroup createSceneGraph() {

        System.out.println("\n --- geometry debug information --- \n");

        int[] stripCount = {17,17,5,5,5,5,5,5,5};

        ////////////////////////////////////////////////////////////////////////////
        //       trying to set the colors of the gi vertices  
        int numberOfTiles = 9;
        Color3f[][] tileColors = new Color3f[numberOfTiles][];
        for (int i=0;i<numberOfTiles;i++) {
            tileColors[i] = new Color3f[stripCount[i]];
            for (int j=0;j<stripCount[i];j++) {
                tileColors[i][j] = new Color3f(1.0f,0.0f,0.0f);
            }
        }

        ///////////////////////////////////////////////////////////////////////////////


        Point3f[][] coordinateData = null;
        coordinateData = createCoordinateData();
        

        GeometryInfo[] gi = new GeometryInfo[9];
        Triangulator tr = new Triangulator();
        NormalGenerator ng = new NormalGenerator();
        Stripifier st = new Stripifier();

        for (int i=0;i<stripCount.length;i++) {
            System.out.println("shape number: "+i);
            gi[i] = new GeometryInfo(GeometryInfo.POLYGON_ARRAY);
            
            gi[i].setCoordinates(coordinateData[i]);
            gi[i].setStripCounts(new int[]{stripCount[i]});

            gi[i].setColors(tileColors[i]);
            
            System.out.println("begin triangulation");
            tr.triangulate(gi[i]);
            System.out.println("  END triangulation");
            gi[i].recomputeIndices();
            
            ng.generateNormals(gi[i]);
            gi[i].recomputeIndices();
            st.stripify(gi[i]);
            gi[i].recomputeIndices();

        }


        Shape3D part = new Shape3D();
        part.setAppearance(createMaterialAppearance());
        part.setPickable(true);
                
        part.setCapability(part.ALLOW_GEOMETRY_READ);
        
        
        System.out.println("Stuffing the geometry arrays into the shape...");
        part.setGeometry(gi[0].getGeometryArray());
        for (int i=1;i<gi.length;i++) {
            part.addGeometry(gi[i].getGeometryArray());
        }

        System.out.println("Setting the geometries to allow intersect testing...");
        System.out.println("number of geometries: "+part.numGeometries());
        for (int i=0;i<part.numGeometries();i++) {
            part.getGeometry(i).setCapability(Geometry.ALLOW_INTERSECT);
            part.getGeometry(i).setCapability(GeometryArray.ALLOW_FORMAT_READ);
            part.getGeometry(i).setCapability(GeometryArray.ALLOW_COORDINATE_READ);
            part.getGeometry(i).setCapability(GeometryArray.ALLOW_COUNT_READ);
            part.getGeometry(i).setCapability(GeometryArray.ALLOW_REF_DATA_READ);
            part.getGeometry(i).setCapability(GeometryArray.ALLOW_COLOR_WRITE);

        }
        System.out.println("Finished stuffing and setting properties...");

        /////////////////////////////

        BranchGroup contentRoot = new BranchGroup();

        // Create the transform group node and initialize it to the
        // identity. Add it to the root of the subgraph.
        TransformGroup objSpin = new TransformGroup();
        objSpin.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        contentRoot.addChild(objSpin);

        objSpin.addChild(part);
        //contentRoot.addChild(part);
        ////////////////////////
        LineStripArray lineArray = new LineStripArray(69, LineArray.COORDINATES, stripCount); //*****
//        LineStripArray lineArray = new LineStripArray(51, LineArray.COORDINATES, stripCount); //*****
        //lineArray.setCoordinates(0, coordinateData);
        Appearance blueColorAppearance = new Appearance();
        ColoringAttributes blueColoring = new ColoringAttributes();
        blueColoring.setColor(0.0f, 0.0f, 1.0f);
        blueColorAppearance.setColoringAttributes(blueColoring);
        LineAttributes lineAttrib = new LineAttributes();
        lineAttrib.setLineWidth(2.0f);
        blueColorAppearance.setLineAttributes(lineAttrib);
        objSpin.addChild(new Shape3D(lineArray, blueColorAppearance));

        Alpha rotationAlpha = new Alpha(-1, 32000);
  
        RotationInterpolator rotator =
                 new RotationInterpolator(rotationAlpha, objSpin);
 
        // a bounding sphere specifies a region a behavior is active
        // create a sphere centered at the origin with radius of 100
        BoundingSphere bounds = new BoundingSphere(new Point3d(), 100.0);
        rotator.setSchedulingBounds(bounds);
        objSpin.addChild(rotator);

        DirectionalLight lightD = new DirectionalLight();
        lightD.setDirection(new Vector3f(0.0f,-0.7f,-0.7f));
        lightD.setInfluencingBounds(bounds);
        contentRoot.addChild(lightD);

        AmbientLight lightA = new AmbientLight();
        lightA.setInfluencingBounds(bounds);
        contentRoot.addChild(lightA);

        Background background = new Background();
        background.setColor(1.0f, 1.0f, 1.0f);
        background.setApplicationBounds(bounds);
        contentRoot.addChild(background);


        ///////////////////////////////////////////////////////////////
        // pick behavior:
        picker = new PickBehavior(contentRoot,part,canvas3D, bounds, tileColors);
        //picker.setBounds(bounds);

        contentRoot.addChild(picker);




        // Let Java 3D perform optimizations on this scene graph.
        //contentRoot.compile();

        return contentRoot;
    } // end of CreateSceneGraph method of MobiusApp

    // Create a simple scene and attach it to the virtual universe

    public Small() {
        setLayout(new BorderLayout());
        canvas3D = new Canvas3D(null);
        add("Center", canvas3D);

        BranchGroup scene = createSceneGraph();

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

        // This will move the ViewPlatform back a bit so the
        // objects in the scene can be viewed.
        simpleU.getViewingPlatform().setNominalViewingTransform();

        simpleU.addBranchGraph(scene);
    } // end of Small constructor

    //  The following allows this to be run as an application
    //  as well as an applet

    public static void main(String[] args) {
        Frame frame = new MainFrame(new Small(), 256, 256);
    } // end of main method of MobiusApp

} // end of class Small
