import com.sun.j3d.utils.image.*; 
import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
import com.sun.j3d.utils.behaviors.mouse.MouseZoom;
import com.sun.j3d.utils.behaviors.mouse.MouseTranslate;
import java.applet.*;
import java.awt.*;
import java.lang.Float;
import java.io.*;
import java.net.*;
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.universe.*;

import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.Sphere;
import java.util.Enumeration;

import com.sun.j3d.utils.image.TextureLoader;


public class ParticleWorld001 extends Applet implements  ActionListener   //, Runnable
        {
        public static Panel guiPanel;
        public static ParticleWorld001 particleWorld001;
        public static Frame frame;
        int boxSize;
        int numberOfBoxes;
        int trailBoxes;
        int objectType = 0;
        int sceneCount =1;    
        CheckboxGroup gcb;
        BranchGroup scene;
        TextField e;
        TextField s;
        TextField tr;
        public static Scrollbar sl1;
        boolean appletFlag = true;
        boolean addReset = false;
        Thread operatorThread;
        ParticleSystem particleSystem;
        boolean updateOn = false;

           // Sets the "applet" flag which is used to determine whether or not this program is running as an applet.
   public void setAppletFlag(boolean flag)
        {
        appletFlag = flag;
        }

        // set up the lights and background as the parent node
   public BranchGroup createSceneGraph()
        {
                // Define colors
                Color3f white = new Color3f(1.0f, 1.0f, 1.0f);
                Color3f bgColor = new Color3f(0.8f, 0.8f, 0.2f);

                // Create the branch group
                BranchGroup branchGroup = new BranchGroup();

                // Create a Transformgroup to scale all objectsR so they appear in the scene.
                TransformGroup objScale = new TransformGroup();
                objScale.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                objScale.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                Transform3D t3d = new Transform3D();
                t3d.setScale(0.04);
                objScale.setTransform(t3d);
                branchGroup.addChild(objScale);

                // Create the bounding leaf node
                BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);
                BoundingLeaf boundingLeaf = new BoundingLeaf(bounds);
                objScale.addChild(boundingLeaf);

                // Get the texture
//              TextureLoader texl = new TextureLoader("out001.jpg", this);
                TextureLoader texl = new TextureLoader("out001.jpg", new Panel());
                ImageComponent2D tex = texl.getImage();

                // Set up the background
                Background bg = new Background(tex);
                bg.setApplicationBounds(bounds);
                //bg.setImage(tex);
                objScale.addChild(bg);

                // Create the ambient light
                AmbientLight ambLight = new AmbientLight(white);
                ambLight.setInfluencingBounds(bounds);
                objScale.addChild(ambLight);

                // Create the directional light
                Vector3f dir = new Vector3f(-1.0f, -1.0f, -1.0f);
                DirectionalLight dirLight = new DirectionalLight(white, dir);
                dirLight.setInfluencingBounds(bounds);
                objScale.addChild(dirLight);

                // Let Java 3D perform optimizations on this scene graph.
                branchGroup.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
                branchGroup.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
                branchGroup.compile();

                return branchGroup;
                }

        // creates the randomly placed objectsR and groups them into a child node
        // includes the mouse behavior for zooming and rotating the objectsR
        public BranchGroup objectGraph()
                {
                Color3f white = new Color3f(1.0f, 1.0f, 1.0f);
                Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
                Color3f red   = new Color3f(0.80f, 0.20f, 0.2f);
                Color3f blue   = new Color3f(0.20f, 0.20f, 0.80f);
                Color3f diffuseRed = new Color3f(0.75f, 0.0f, 0.0f);
                Color3f diffuseBlue   = new Color3f(0.0f, 0.0f, 0.75f);
                Color3f diffuseWhite = new Color3f(0.75f, 0.75f, 0.75f);
                Color3f specularRed = new Color3f(1.0f, 0.2f, 0.3f);
                Color3f specularBlue   = new Color3f(0.30f, 0.2f, 1.0f);
                Color3f specularWhite = new Color3f(1.0f,1.0f,1.0f);
                Color3f ambientRed = new Color3f(0.25f, 0.0f, 0.0f);
                Color3f ambientBlue   = new Color3f(0.0f, 0.0f, 0.25f);
                Color3f ambientWhite = new Color3f(0.15f, 0.15f, 0.15f);
                Color3f ambient = new Color3f(0.2f, 0.2f, 0.2f);
                Color3f diffuse = new Color3f(0.7f, 0.7f, 0.7f);
                Color3f specular = new Color3f(0.7f, 0.7f, 0.7f);

                // Create the branch group
                BranchGroup branchGroup = new BranchGroup();

                // Create a Transformgroup to scale all objectsR so they appear in the scene.
                TransformGroup objScale = new TransformGroup();
                objScale.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                objScale.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
                Transform3D t3d = new Transform3D();
                t3d.setScale(0.018);
                objScale.setTransform(t3d);
                branchGroup.addChild(objScale);

                // Create the bounding leaf node
                BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 250);
                BoundingLeaf boundingLeaf = new BoundingLeaf(bounds);
                objScale.addChild(boundingLeaf);

                // Create the red appearance node
                Material redMaterial = new Material(ambientRed, black, diffuseRed, specularRed, 100.0f);
                redMaterial.setLightingEnable(true);
                Appearance redAppearance = new Appearance();
                redAppearance.setMaterial(redMaterial);

                // Create the blue appearance node
                Material blueMaterial = new Material(ambientBlue, black, diffuseBlue, specularBlue, 100.0f);
                blueMaterial.setLightingEnable(true);
                Appearance blueAppearance = new Appearance();
                blueAppearance.setMaterial(blueMaterial);

                // Create the white appearance node
                Material whiteMaterial = new Material(ambientWhite, black, diffuseWhite, specularWhite, 100.0f);
                whiteMaterial.setLightingEnable(true);
                Appearance whiteAppearance = new Appearance();
                whiteAppearance.setMaterial(whiteMaterial);


                // Set up the coloring properties
                Color3f objColor = new Color3f(0.2f, 0.2f, 1.0f);
                ColoringAttributes ca = new ColoringAttributes();
                ca.setColor(objColor);
                whiteAppearance.setColoringAttributes(ca);

                // Create the transform node
                TransformGroup transformGroup = new TransformGroup();
                transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
                transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);



                //   public ParticleSystem(int n, int s, int width, int depth, int height) 
                particleSystem = new ParticleSystem(numberOfBoxes, boxSize, 10,10,10, objectType, trailBoxes, this);
                transformGroup.addChild(particleSystem.getChild());


                objScale.addChild(transformGroup);

                // Create the drag behavior node
                MouseRotate behavior = new MouseRotate();
                behavior.setTransformGroup(transformGroup);
                transformGroup.addChild(behavior);
                behavior.setSchedulingBounds(bounds);
        
                // Create the zoom behavior node
                MouseZoom behavior2 = new MouseZoom();
                behavior2.setTransformGroup(transformGroup);
                transformGroup.addChild(behavior2);
                behavior2.setSchedulingBounds(bounds);
        
                // Create the zoom behavior node
                MouseTranslate behavior3 = new MouseTranslate();
                behavior3.setTransformGroup(transformGroup);
                transformGroup.addChild(behavior3);
                behavior3.setSchedulingBounds(bounds);

                // Let Java 3D perform optimizations on this scene graph.
                branchGroup.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
                branchGroup.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
                branchGroup.setCapability(BranchGroup.ALLOW_DETACH);
//              branchGroup.compile();

                return branchGroup;
                }

        // The main starting point
        public void init()
                {
                // Set up the world if running as an applet
                if(appletFlag){particleWorld001 = new ParticleWorld001();}

                // Create the user interface controls
                makePanel();
                // Set the layout manager
                setLayout(new BorderLayout());
                // Create the 3D canvas
                Canvas3D canvas = new Canvas3D(null);
                add("Center", canvas);

                // Create the scene branch graph
                scene = createSceneGraph();
                // Insert the inital set of objectsR
                BranchGroup scene2 = objectGraph();
                scene.insertChild(scene2, 1);
                
                // Create the Universe, the Locale, and the view branch graph
                SimpleUniverse u = new SimpleUniverse(canvas);

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

                u.addBranchGraph(scene);

                frame = new Frame("Drag the mouse in the window");
//-----------------------
                int fwidth = 280;    //    <----------------------
                int fheight = 400;   //    <----------------------
//-----------------------
                frame.setSize(fwidth,fheight);
                frame.setLocation(1024/2-fwidth/2,768/2-fheight/2);
                frame.add("South", guiPanel);
                frame.add("Center", particleWorld001);
                frame.addWindowListener(new killAdapter());
                frame.setVisible(true);
                start();
                }
        
        // Inner class used to "kill" the window when running as
        //  an application.
        static class killAdapter extends WindowAdapter
                {
                public void windowClosing(WindowEvent event)
                        {
                        System.exit(0);
                        }
                }

        // Activated by the reset button, this creates a new set of objectsR
        // And replaces the existing objectsR scene
        public void reset()
                {
                // Determines if spheres or boxes are selected and sets the control variable
                if (gcb.getSelectedCheckbox().getLabel()  == "Lines")
                        {
                        objectType = 1;
                        System.out.println("Lines Chosen");
                        }
                else
                        {
                        objectType = 0;
                        System.out.println("Boxes Chosen");
                        };
                System.out.println("Object Type = " +objectType);
                numberOfBoxes = Integer.parseInt(s.getText().trim());
                boxSize = Integer.parseInt(e.getText().trim());
                trailBoxes = Integer.parseInt(tr.getText().trim());
                System.out.println("WORLD --- trailBoxes = Integer.parseInt(tr.getText().trim());"   +trailBoxes);


                BranchGroup scene2 = objectGraph();
                if(addReset)
                        {
                        sceneCount++;
                        scene.insertChild(scene2, sceneCount);
                        //scene.setChild(scene2, sceneCount);
                        }
                else
                        {
                        if(sceneCount > 1)
                                {
                                for(int rmv=sceneCount;rmv>1;rmv--)
                                        {
                                        scene.removeChild(rmv);
                                        };
                                };
                        sceneCount = 1;
                        scene.setChild(scene2, 1);
                        };                      
                }
        
        // Do this when the Reset button has been pressed
        public void actionPerformed(ActionEvent ev)
                {
                try
                        {
                        if(ev.getActionCommand()  == "Reset"){reset();};
                        if(ev.getActionCommand()  == "Add")
                                {
                                addReset = true;
                                reset();
                                addReset = false;
                                };
                        if(ev.getActionCommand()  == "Update")
                                {
                                if(updateOn)
                                        {
                                        updateOn = false;
                                        System.out.println("WORLD -- Update Off");
                                        }
                                else
                                        {
                                        updateOn = true;
                                        System.out.println("WORLD -- Update On");
                                        };
                                }
                        }
                catch (Exception e)
                        {
                        };
                System.gc();
                }

        //  Used when running as an application.
        public static void main(String[] args)
                {
                particleWorld001 = new ParticleWorld001();
                particleWorld001.setAppletFlag(false);
                particleWorld001.init();
                }

        // Creates the Control panel
        public void makePanel()
                {
                guiPanel = new Panel();
                Panel resetscroll = new Panel();
                Panel variables = new Panel();
                Panel radioBox = new Panel();
                Panel actualControls = new Panel();
                Panel buttons = new Panel();
                
                Label size = new Label();
                Label num = new Label();
                Label trlr = new Label();

                e = new TextField("1", 4);
                s = new TextField("1",4);
                tr = new TextField("1",4);

                gcb = new CheckboxGroup();
                Button b1 = new Button("Reset");
                Button b2 = new Button("Update");
                Button b3 = new Button("Add");
                b1.addActionListener(this);
                b2.addActionListener(this);
                b3.addActionListener(this);
                sl1 = new Scrollbar(Scrollbar.VERTICAL, 200, 1, 0, 200);

                numberOfBoxes = Integer.parseInt(s.getText().trim());
                boxSize = Integer.parseInt(e.getText().trim());
                trailBoxes = Integer.parseInt(tr.getText().trim());

                size.setText("Size");
                num.setText("Number");
                trlr.setText("Trailers");

                variables.setLayout(new GridLayout(3,3));
                variables.add(size);
                variables.add(e);
                variables.add(b1);
                variables.add(num);
                variables.add(s);
                variables.add(b2);
                variables.add(trlr);
                variables.add(tr);
                variables.add(b3);

                guiPanel.setLayout(new BorderLayout());
                guiPanel.setBackground(Color.lightGray);
                guiPanel.add(variables, BorderLayout.CENTER);
                guiPanel.add(sl1, BorderLayout.EAST);

                radioBox.setLayout(new GridLayout(1,2));
                radioBox.setBackground(Color.lightGray);
                radioBox.add(new Checkbox("Boxes", gcb, true));
                radioBox.add(new Checkbox("Lines", gcb, false));
                guiPanel.add(radioBox, BorderLayout.NORTH);
                }
/*
        public void start()
                {
                if (operatorThread != Thread.currentThread() )
                        {
                        operatorThread = new Thread(this);
                        operatorThread.start();
                        };
                run();
                };
        public void stop()
                {
                operatorThread = null;
                };

        public void run()
                {
                while (operatorThread == Thread.currentThread() )
                        {
                        while (updateOn)                                
                                {
                                try {Thread.sleep(sl1.getValue());} catch (Exception e) {};
                                particleSystem.update();
                                };
                        };
                };
*/
        }